> ## Documentation Index
> Fetch the complete documentation index at: https://developer.uphold.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Card deposit via the REST API

> Support card deposits using the Uphold REST API: link a card as an external account, create a quote, handle 3DS, and create the deposit transaction.

export const feature_0 = "deposit"

This guide walks you through supporting card deposits using the REST API.

## Prerequisites

* The user has [completed onboarding](/developer-guides/user-onboarding/overview) and has the required capabilities enabled.

## Walkthrough

```mermaid theme={null}
sequenceDiagram
  autonumber
  participant Usr as User
  participant U as Your App
  participant B as Your Backend
  participant A as Uphold

  Usr->>U: Start card deposit
  U->>B: List card accounts
  B->>A: GET /core/external-accounts
  A-->>B: { externalAccounts }
  B-->>U: { externalAccounts }
  opt No existing card account
    Usr->>U: Add card details
    U->>B: Link card account
    B->>A: Create card external account
    A-->>B: { externalAccount }
    B-->>U: { externalAccount }
  end
  Usr->>U: Choose card account
  alt First time (EMD disclaimer)
    U->>Usr: Display EMD disclaimer
    Usr->>U: Acknowledge
  end
  U->>B: List accounts
  B->>A: GET /core/accounts
  A-->>B: { accounts }
  B-->>U: { accounts }
  Usr->>U: Choose destination account and amount
  U->>B: Request quote
  B->>A: Create quote (card → account)
  A-->>B: { quote }
  B-->>U: { quote }
  Usr->>U: Confirm

  U->>B: Create transaction (with returnUrl)
  B->>A: Create transaction
  A-->>B: { transaction (with confirmationUrl if authorization required) }
  B-->>U: { transaction }
  A-->>B: webhook: transaction.created (processing)

  alt confirmationUrl present (authorization required)
    U->>Usr: Redirect to confirmationUrl
    Usr->>A: Complete authorization challenge
    A->>Usr: Redirect to returnUrl
  end

  A-->>B: webhook: transaction.status-changed (completed/failed)
  B-->>Usr: Notify the user
```

***

## Check available rails

Call [List Rails](/rest-apis/core-api/assets/list-rails) to verify card deposit is available.

```http theme={null}
GET /core/rails?type=card
```

```json theme={null}
{
  "rails": [
    {
      "type": "card",
      "network": "visa",
      "method": "debit-card",
      "asset": "GBP",
      "decimals": 2,
      "features": [
        "deposit",
        "withdraw"
      ]
    }
  ]
}
```

## Link or select a card account

Let the user link a new card or select an existing one.

### Find an existing card account

Call [List external accounts](/rest-apis/core-api/external-accounts/list-external-accounts) to fetch the user's saved cards.

```http theme={null}
GET /core/external-accounts
```

Make sure the selected card has `status: "ok"` and **{feature_0}** in `features`.

```json theme={null}
{
  "externalAccounts": [
    {
      "id": "7d5928c5-8ac4-4b0d-8b45-f332ba6a9de7",
      "ownerId": "e4ce04dc-67b7-4e9f-af91-482cb6f9fc4a",
      "type": "card",
      "status": "ok",
      "label": "My Visa Card",
      "asset": "GBP",
      "network": "visa",
      "features": [
        "deposit",
        "withdraw"
      ],
      "details": {
        "type": "debit",
        "last4Digits": "5119",
        "expiryDate": {
          "month": 12,
          "year": 2028
        },
        "octSupport": "supported"
      }
    }
  ]
}
```

### Link a new card account

If the user wants to use a card not yet on file, call [Create external account](/rest-apis/core-api/external-accounts/create-external-account) with the card details.

```http theme={null}
POST /core/external-accounts
{
  "type": "card",
  "label": "My Visa Card",
  "number": "4921817844445119",
  "securityCode": "123",
  "expiryDate": {
    "month": 12,
    "year": 2028
  }
}
```

The response initially returns `status: "processing"` while the card is validated.

```json theme={null}
{
  "externalAccount": {
    "id": "7d5928c5-8ac4-4b0d-8b45-f332ba6a9de7",
    "type": "card",
    "status": "processing",
    "label": "My Visa Card"
  }
}
```

Once validated, the status transitions to `ok` and the full details are available.

```json theme={null}
{
  "externalAccount": {
    "id": "7d5928c5-8ac4-4b0d-8b45-f332ba6a9de7",
    "ownerId": "e4ce04dc-67b7-4e9f-af91-482cb6f9fc4a",
    "type": "card",
    "status": "ok",
    "label": "My Visa Card",
    "asset": "GBP",
    "network": "visa",
    "features": [
      "deposit",
      "withdraw"
    ],
    "details": {
      "type": "debit",
      "last4Digits": "5119",
      "expiryDate": {
        "month": 12,
        "year": 2028
      },
      "octSupport": "supported"
    }
  }
}
```

<Note>Monitor the external account status via [Get external account](/rest-apis/core-api/external-accounts/get-external-account) or the `external-account.status-changed` webhook until `status` is `ok` before proceeding.</Note>

### EMD disclaimer

This disclaimer is required to comply with FCA regulations. Display it to users based in GB, the first time they link a credit/debit card or generate bank deposit details — it only needs to be shown once:

> Uphold Europe Limited is an EMD Agent of Optimus Cards UK Limited (FRN: 902034). All received funds are held in a designated safekeeping account with a regulated bank and kept separate from Uphold's own assets. These funds are not protected by the UK Financial Services Compensation Scheme.

## Select destination account

Card deposits can target any account. If the selected account is not in the card's currency, the amount will be converted at settlement using Uphold's prevailing rate. Make sure the destination asset has the necessary [features enabled](/rest-apis/core-api/assets/introduction#features-and-deposits-/-withdrawals).

### Find an existing account

Call [List accounts](/rest-apis/core-api/accounts/list-accounts) to retrieve the user's accounts and let them pick the one they want to fund.

```http theme={null}
GET /core/accounts
```

```json theme={null}
{
  "accounts": [
    {
      "id": "a00507fe-628c-4f27-ae81-e1c40b2a8fb8",
      "ownerId": "e4ce04dc-67b7-4e9f-af91-482cb6f9fc4a",
      "label": "My GBP account",
      "asset": "GBP",
      "balance": {
        "total": "500.00",
        "available": "500.00"
      }
    }
  ]
}
```

### Create a new account

If the user has no accounts, create one with [Create account](/rest-apis/core-api/accounts/create-account) before proceeding.

```http theme={null}
POST /core/accounts
{
  "label": "My GBP account",
  "asset": "GBP"
}
```

```json theme={null}
{
  "account": {
    "id": "a00507fe-628c-4f27-ae81-e1c40b2a8fb8",
    "ownerId": "e4ce04dc-67b7-4e9f-af91-482cb6f9fc4a",
    "label": "My GBP account",
    "asset": "GBP",
    "balance": {
      "total": "0",
      "available": "0"
    }
  }
}
```

## Create a quote

Call [Create quote](/rest-apis/core-api/transactions/create-quote) with the card external account as origin and the destination account.

```http theme={null}
POST /core/transactions/quote
{
  "origin": {
    "type": "external-account",
    "id": "7d5928c5-8ac4-4b0d-8b45-f332ba6a9de7"
  },
  "destination": {
    "type": "account",
    "id": "a00507fe-628c-4f27-ae81-e1c40b2a8fb8"
  },
  "denomination": {
    "asset": "GBP",
    "amount": "250.00",
    "target": "origin"
  }
}
```

```json [expandable] theme={null}
{
  "quote": {
    "id": "623000c8-9bdf-4a2b-aa3d-6a6b44a7f6a0",
    "origin": {
      "amount": "250.00",
      "asset": "GBP",
      "node": {
        "type": "external-account",
        "id": "7d5928c5-8ac4-4b0d-8b45-f332ba6a9de7",
        "ownerId": "e4ce04dc-67b7-4e9f-af91-482cb6f9fc4a"
      },
      "rate": "1"
    },
    "destination": {
      "amount": "250.00",
      "asset": "GBP",
      "node": {
        "type": "account",
        "id": "a00507fe-628c-4f27-ae81-e1c40b2a8fb8",
        "ownerId": "e4ce04dc-67b7-4e9f-af91-482cb6f9fc4a"
      },
      "rate": "1"
    },
    "denomination": {
      "asset": "GBP",
      "amount": "250.00",
      "target": "origin",
      "rate": "1"
    },
    "fees": [],
    "expiresAt": "2024-07-24T15:22:39Z"
  }
}
```

<Info>Quotes typically **expire** quickly. Prompt for user confirmation within the expiry window and requote if needed.</Info>

## Confirm and create transaction

Once the user confirms, call [Create transaction](/rest-apis/core-api/transactions/create-transaction) with the quote ID.

Always include the `authorize:3ds` requirement for card-origin transactions — whether the card requires authorization is decided per transaction by the issuer and isn't known until the transaction response. You may include stateful data in query parameters of the `returnUrl`, such as the `quoteId`, so you can preserve context and resume the transaction flow upon return.

```http theme={null}
POST /core/transactions
{
  "quoteId": "623000c8-9bdf-4a2b-aa3d-6a6b44a7f6a0",
  "params": {
    "requirements": [
      {
        "name": "authorize:3ds",
        "returnUrl": "https://example.com/redirect?quoteId=623000c8-9bdf-4a2b-aa3d-6a6b44a7f6a0"
      }
    ]
  }
}
```

If authorization is required, the response will include a `confirmationUrl` on the origin node. Redirect the user to that URL to complete the challenge. After completion, the user will be redirected back to your `returnUrl`.

```json theme={null}
{
  "transaction": {
    "id": "623000c8-9bdf-4a2b-aa3d-6a6b44a7f6a0",
    "status": "processing",
    "origin": {
      "node": {
        "type": "external-account",
        "id": "7d5928c5-8ac4-4b0d-8b45-f332ba6a9de7",
        "confirmationUrl": "https://authentication-devices.sandbox.checkout.com/sessions-interceptor/sid_...",
        "ownerId": "e4ce04dc-67b7-4e9f-af91-482cb6f9fc4a"
      }
    }
  }
}
```

In a successful card deposit, the origin is the `external-account` representing the card and the destination is the user's `account`.

```json [expandable] theme={null}
{
  "transaction": {
    "id": "f5a6b7c8-3d4e-4f7a-b00c-9d8e7f6a5b4c",
    "origin": {
      "asset": "GBP",
      "amount": "250.00",
      "node": {
        "type": "external-account",
        "id": "7d5928c5-8ac4-4b0d-8b45-f332ba6a9de7",
        "ownerId": "e4ce04dc-67b7-4e9f-af91-482cb6f9fc4a"
      }
    },
    "destination": {
      "asset": "GBP",
      "amount": "250.00",
      "node": {
        "type": "account",
        "id": "a00507fe-628c-4f27-ae81-e1c40b2a8fb8",
        "ownerId": "e4ce04dc-67b7-4e9f-af91-482cb6f9fc4a"
      }
    },
    "status": "completed",
    "quotedAt": "2025-01-10T11:02:39Z",
    "createdAt": "2025-01-10T11:12:39Z",
    "updatedAt": "2025-01-10T11:13:08Z",
    "denomination": {
      "asset": "GBP",
      "amount": "250.00",
      "target": "origin"
    }
  }
}
```

## Monitor for settlement

Card deposit transactions may remain in `processing` while the payment settles. Monitor until the transaction reaches a terminal state.

* **Webhook events** (recommended):
  * [core.transaction.created](/rest-apis/core-api/transactions/webhooks/transaction-created) — `status: processing` → transaction created, pending settlement
  * [core.transaction.status-changed](/rest-apis/core-api/transactions/webhooks/transaction-status-changed) — `status: completed` → funds settled; `status: failed` → irrecoverable error
* **Polling** (fallback): [Get transaction](/rest-apis/core-api/transactions/get-transaction)

## Notify the user

Display an in-app confirmation when the transaction is `completed`, and send an email if applicable.

<Check>You now support card deposits via the REST API.</Check>
