See below for a sample end-to-end flow covering the steps involved in accepting a card payment using the Circle Payments API.


# Prepare Encryption of Sensitive Data

Card details are encrypted in the browser so sensitive card details are never accessible to you server.

The Circle Payments API exposes a [public key endpoint](🔗) that is used to encrypt data on the client-side.

On page load you will load the [OpenPgP.js](🔗) JavaScript library used for encryption.

The request to [get your public key](🔗) to be used for encryption can also be done on page load so that it is already available when the user wants to make a payment. Your public keys change infrequently, so we further recommend that you cache their values for a duration of 24 hours or more.

# Encrypt End-user's Card Details

Before card details are saved using the API, the sensitive data elements first need to be encrypted on the client-side. Below is a sample code that describes the data-types and functions involved in performing the encryption of card details.

The returned `encryptedData` and `keyId` values will then be included in the request made to [save card details](🔗).

# Save End-user's Card Details

The next step is to save the end-user's card details by using the [create card endpoint](🔗).

As well as passing the encrypted card details some extra fields need to be added to the request before it can be sent to the [create card endpoint](🔗). You need to collect billing details for your end user, as well as provide a unique ID for the active session (`sessionId`) and the IP address of the end-user (`ipAddress`).

Creating a card will respond with an `id` value that can be stored on your side to refer to this end-user's card in future payment requests. The card creation response also contains the result of the different verification checks performed under the `verification` property. See [Verifying Card Details](🔗) for details on what checks are performed and the meaning of the returned values. The card will also be checked by the Circle Risk Service. If the card is denied by Risk then an `errorCode` and `riskEvaluation` property will be set on the response see [Risk Evaluation](🔗) for details on the evaluation responses. Both the card verification and Risk Service checks are performed asynchronously so the results will not be set in the initial response. To get the results you can either poll the GET /cards/{id} endpoint or use a subscription notification.

# Create a Card Payment

You then need to make a [payment request](🔗). You will use the `id` of the card created in the previous step as the "source" for this payment.

When making a payment request you can choose to verify the CVV value again by setting the `verification` property in the request to `cvv`. The code to encrypt the CVV value when making a payment is the same as shown above except this time the `CardDetails` object passed to the encryption function needs only to contain the `cvv` property. If the `verification` value in the request is set to `none` then the `encryptedData` property does not need to be provided.

You also need to provide an `amount` and `currency` to be charged against this end-user's card. Amounts are expressed in units of the currency, with decimals prefixed with a `.` separator. Currency is expressed in ISO 4217 currency codes - note that for the time being, only [USD is supported](🔗). You will receive settlement for this payment in [USDC](🔗) equivalent (minus processing fees).

Make sure to include a `refId` property to allow for [idempotent requests](🔗) . The end-user's `sessionId` and `ipAddress` fields referenced above need to be included once more in the request when making a payment (those values are used for preventing fraud).

# Auth and Capture (Beta)

When creating a payment `POST /v1/payments` you have the option to either authorize a payment only (thus delaying capture), or auth and capture a payment at the same time.

By default, `POST /v1/payments` will auth and capture a payment at the same time. For scenarios where you want to auth a payment only and delay capture until a later time, send `autoCapture: false` in the request.

For a payment that is authorized only, it is your responsibility to capture the payment using `POST /v1/payments/id/capture`. Auths that are not captured will expire 6 days + 18 hours after creation. If you do not intend to capture an auth, use `POST /v1/payments/id/cancel` to release the cardholder's funds.

**Authorization** (Auth): Check the cardholder has sufficient funds to cover the cost of the transaction. **Capture**: Request the transfer of funds from the cardholder's issuing bank.

Partial Capture (Beta)

The ability to partially capture a payment is not yet supported for all accounts. Please reach out to your Account Manager to confirm if partial capture is enabled for your account.

# Check for Payment Status

The Circle Payments API processes payments asynchronously. In order to determine the status of a payment you initiated, you have to poll the API periodically until the payment status has changed from `pending` to either `confirmed` or `failed`. To poll for payment status, use the [retrieve payment endpoint](🔗) with the `id` of the payment you initiated.

# Congratulations!

🎉 You have accepted your first card payment and your USDC settlement is on its way!

# Are you ready for the next step?

If you are in advanced stages of experimenting with our APIs and want to plan moving to production, please start by [applying for a Circle Account](🔗) and subsequently [reach out to sales](🔗). We'll be happy to walk you through to the next steps.

We can't wait to see what you are going to build!