# Accept card payments

> Link debit and credit cards to a Moov account with the card link Drop, API, or SDKs, save cards on file, and charge them as the source of a transfer.

> AI agents: search and read all Moov docs with the docs MCP server at https://docs.moov.io/mcp (no API key). Setup: https://docs.moov.io/guides/developer-tools/mcp-ai/docs-mcp/index.md

Link a customer's credit or debit card to their Moov account, then charge it with a transfer to the merchant's Moov wallet. Use this for ecommerce, SaaS, and subscription checkouts.

## Before you start

- A payer account and a merchant account. See [create accounts](/guides/accounts/create-accounts/index.md) or [hosted onboarding](/guides/accounts/hosted-onboarding/index.md).
- The merchant needs the `collect-funds.card-payments` and `wallet.balance` [capabilities](/guides/accounts/capabilities/index.md). The payer needs `transfers`.
- To link cards through the API instead of the card link Drop, an attestation of PCI compliance submitted to Moov.
- In test mode, use the [test cards](/guides/get-started/api-authentication/test-mode/index.md#link-cards--card-acceptance).

Endpoints used: [link a card](/api/sources/cards/create/index.md), [list payment methods](/api/sources/payment-methods/list/index.md), [create a transfer](/api/money-movement/transfers/create/index.md), and [retrieve a transfer](/api/money-movement/transfers/get/index.md).

Linking a card verifies it with the card network, including Address Verification Service (AVS) and Card Verification Value (CVV) checks.

## Link the card

You can use the pre-built [card link Drop](/moovjs/drops/card-link/index.md), or if you've submitted an attestation of PCI compliance to Moov, you can link cards directly through the API. If you opt for the API method, you'll be responsible for storing and handling card data.

### Save a card for future use

Before you link a card, consider whether the card should be saved on file to use Moov's [card account updater](/guides/sources/cards/card-account-updater/index.md) service. This can be done by setting `cardOnFile` to **true** when linking a card. If nothing is passed to `cardOnFile`, or you set it to **false**, the card will not automatically update card number and expiration date information. If a card becomes out of date, it will not work for future payments.

If you set the `cardOnFile` flag to **true**, the `merchantAccountID` (Moov account ID of a merchant on your platform) provided should signify which merchant the cardholder has consented to save their information. The account associated with the `merchantAccountID` will incur fees for successful card updates using Moov's card account updater.

If you leave the `merchantAccountID` field blank while saving a card on file, the system will default to your partner account ID, indicating the cardholder's relationship with your platform's brand. You can update the `merchantAccountID` at any time using the update card `PATCH` [endpoint](/api/sources/cards/update/index.md).

> **Note:** Accounts must be approved for card account updater. [Contact Moov](https://support.moov.io/) for more information.

### Drop

The simplest way to securely collect sensitive card details is by using the card link Drop, a prebuilt UI component for embedding card-based payments. By using the [card link Moov Drop](/moovjs/drops/card-link/index.md), you’ll send card data directly to Moov’s PCI-compliant card vault, and the information will not touch your servers.

Once the information has been submitted via the Drop, Moov verifies the card details with card networks.

```html
<moov-card-link class="card-link"></moov-card-link>

<script>
  let moovCardLink = document.querySelector("moov-card-link");
  moovCardLink.accountID = "accountID";
  moovCardLink.oauthToken = "oauthToken";
  moovCardLink.onSuccess = (card) => {
    console.log("Card linked");
    // now show a success screen
  }
  moovCardLink.onError = (error) => {
    console.log("Error linking card");
    // now show an error screen
  }

  // call submit when button is pressed
  moovCardLink.submit();
</script>
```

### API & SDKs

Link a card using our API or Go SDKs. If you set the optional `X-Wait-For` header to `payment-method`, the response will include any payment methods that were created for the newly linked card in the `paymentMethods` field.

**cURL**

```zsh
curl -X POST "https://api.moov.io/accounts/{accountID}/cards" \
  -H "Authorization: Bearer {token}" \
  -H "X-Wait-For: payment-method" \
  -H "x-moov-version: v2026.07.00" \
  --data-raw '{
    "billingAddress": {
      "addressLine1": "123 Main Street",
      "city": "Denver",
      "stateOrProvince": "CO",
      "postalCode": "80301",
      "country": "US"
    },
    "cardCvv": "123",
    "cardNumber": "4111111111111111",
    "expiration": {
      "month": "01",
      "year": "28"
    },
    "holderName": "Jules Jackson"
  }'
```

**Go SDK**

```go
mc, _ := moov.NewClient()

var accountID string

cardPayload := moov.CreateCard{
  BillingAddress: moov.Address{
    AddressLine1:    "123 Main Street",
    City:            "Denver",
    StateOrProvince: "CO",
    PostalCode:      "80301",
    Country:         "US",
  },
  CardNumber: "4111111111111111",
  CardCvv:    "123",
  Expiration: moov.Expiration{
    Month: "01",
    Year:  "28",
},
  HolderName: "Jules Jackson",
}

mc.CreateCard(ctx, accountID, cardPayload)
```

## Check the card verification

When a card is linked, Moov performs a verification with the relevant card network to confirm that the card account is open and valid. Additionally, the verification checks if the CVV and address match the information on file with the card issuer.

The `merchantAccountID` is used to pass merchant information during card verification. Although these verification transactions are rarely visible to cardholders, when they are, it's crucial that cardholders recognize the merchant associated with the verification so they know it's not fraudulent.

> **Note:** Although it's best practice to always include the `merchantAccountID` during card verification, it's not mandatory. If you omit this field, the system defaults to your partner account ID.

It is possible the verification request will be declined by the card issuer. Decline information is provided in the response body of the `422` error. Errors could be validation errors, such as an invalid card number, or actual declines from the card issuer. Below is an example of a card issuer decline.

```json
{
  "error": "card verification failure: card-not-activated"
}
```

## Verify the cardholder name (optional)

Moov supports Visa’s [Account Name Inquiry (ANI)](https://usa.visa.com/content/dam/VCOM/regional/na/us/support-legal/documents/account-name-inquiry-onesheet-merchant-version.pdf). ANI ensures that the name provided on the linked card matches the name held on file with the issuer. This tool is optional and serves to enhance cardholder verification.

The card link `POST` [endpoint](/api/sources/cards/create/index.md) and `PATCH` [endpoint](/api/sources/cards/update/index.md) offer an optional `verifyName` field. To submit a name to Visa for verification, supply the `holderName` and set `verifyName` to **true**. [Pull from card](/guides/accept-payments/cards/pull-from-card/index.md) requires name verification.

```json
{
  "cardVerification": {
    "fullName": "match",
    "firstName": "match",
    "middleName": "noMatch",
    "lastName": "match"
  }
}
```

Each name field returns `match`, `partialMatch`, `noMatch`, or `notChecked`.

## Create the card payment

The customer’s card will be the source of funds, so Moov needs the `card-payment` payment method from their account. You can obtain the `paymentMethodID` from the payment methods `GET` [endpoint](/api/sources/payment-methods/list/index.md). The `sourceID` should be the `cardID`, which you can get from the cards `GET` [endpoint](/api/sources/cards/get/index.md).

Since the merchant’s wallet will be the destination of the funds, we will need the `moov-wallet` payment method. You can obtain the `paymentMethodID` using the payment methods `GET` [endpoint](/api/sources/payment-methods/list/index.md) and finding the `moov-wallet` payment method associated with the merchant account.

To submit the card payment, create a transfer from the cardholder (source) to the merchant (destination).

**cURL**

```zsh
curl -X POST "https://api.moov.io/accounts/{accountID}/transfers" \
  -H "Authorization: Bearer {token}" \
  -H "x-idempotency-key: UUID" \
  -H "X-Wait-For: rail-response" \
  -H "x-moov-version: v2026.07.00" \
  --data-raw '{
    "amount": {
      "value": 100,
      "currency": "USD"
    },
    "destination": {
      "paymentMethodID": "string"
    },
    "source": {
      "paymentMethodID": "string"
    },
    "description": "Optional transaction description."
  }'
```

Card-based payments first settle in a Moov wallet. The funds can later be moved to an external bank account through a disbursement transfer.

> **Tip:** When you include the `X-Wait-For` header in the request, you will get a synchronous response that includes full transfer and rail-specific details from the payment network. This is useful for when a user is clicking a button to make a payment and needs a synchronous response so they can get confirmation that it worked. If you omit the `X-Wait-For` header, you will get an asynchronous response that only includes the transferID and the timestamp for when the transfer was created.

## Confirm the payment

The transfer stays `pending` until funds reach the merchant's wallet, by 1:00 PM ET the next banking day (see [settlement timing](/guides/accept-payments/cards/timing/index.md)). `source.cardDetails.status` of `confirmed` means the issuer approved the charge. Subscribe to `transfer.updated` to see it move to `completed`, or [retrieve the transfer](/api/money-movement/transfers/get/index.md).

If you got a `202` response, the transfer is neither successful nor failed yet. See [create transfer responses](/guides/money-movement/events-and-statuses/index.md#create-transfer-responses).

```json
{
  "source": {
    "cardDetails": {
      "status": "confirmed",
      "confirmedOn": "2023-09-10T18:23:56Z"
    }
  }
}
```

## Move the funds out

Once the payment has been processed and the funds are available, the funds can be moved out of the merchant `moov-wallet` using another transfer where that wallet is the source. [Bank holidays](https://www.frbservices.org/about/holiday-schedules) may delay the availability of funds.

**Card to wallet**

![Card to wallet transfer diagram](./images/card-to-wallet-light.png)

## Reverify a card

> **Note:** Moov will only perform a new verification request if a new CVV is provided.

You can use the update a card `PATCH` [endpoint](/api/sources/cards/update/index.md) to update and re-verify certain information about the card. The `cardID` is the ID of the card you want to update, and the `accountID` represents the Moov account that the card is linked to.

```json
{
  "cardCvv": "123"
}
```

Optional request data:

| Field            | Type   | Description                                  |
|------------------|--------|----------------------------------------------|
| `expiration`     | object | The card's expiration month and year         |
| `cardCvv`        | string | The card's CVV number                        |
| `billingAddress` | object | The billing address associated with the card |

Note that when performing a `PATCH` on an existing card, Moov will perform another CVV verification request to the card networks using the new information provided. If the new verification is declined by the card issuer, the previously linked card will not be affected. If the verification succeeds, the card record will be updated with the new information.

Refer to the `cardVerification{}` object in the response to see if the new CVV information is correct.

```json
{
  "cardVerification": {
    "cvv": "match",
    "addressLine1": "match",
    "postalCode": "match"
  }
}
```

## Improve approval rates

Some card issuers display alerts or notifications about card verifications to cardholders. Being transparent and recognizable prevents accidental suspicion.

Include as much complete and accurate data as possible to comply with card brand rules and mandates, optimize card authorization rates, prevent interchange downgrades, and increase defensibility against chargebacks. Consider the following best practices:

- **Street address**: Send the optional `addressLine1` in `billingAddress`. For most situations, Moov recommends sending the address so that full address verification can take place. Not including `addressLine1` may impact approval rates, cause interchange downgrades, and impact chargeback win rate.
- **Card verification**: Always include `merchantAccountID` when performing a card verification. This provides context to the cardholder if the verification transaction becomes visible.
- **Save a card on file**: If you're saving a card for future use, specify `merchantAccountID` and set the `cardOnFile` flag to **true**. This indicates the cardholder's relationship with the merchant, and their consent to save their card details for future transactions.

## Next steps

- [Refund or cancel a card payment](/guides/accept-payments/cards/reversals/index.md)
- [Respond to disputes](/guides/accept-payments/cards/disputes/index.md)
- [Charge a saved card on a schedule](/guides/accept-payments/cards/recurring-payments/index.md)
- [Handle declines](/guides/accept-payments/cards/declines/index.md)

