Circle APIs Documentation

Learn how to integrate with Circle APIs to accept traditional and stablecoin payments, embed digital wallets into your product or service, or power your internet marketplace.

Accept Card Payments

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 compliance with the Payment Card Industry (PCI) Data Security Standard (DSS).

The Circle Payments API exposes a public key endpoint that can be used to retrieve your own key in order to encrypt data on the client-side. That way, sensitive card details are never transmitted in the open to your server. This approach may help reduce the scope of your PCI compliance obligations.

As an example, on page load you will load the OpenPgP.js JavaScript library used for encryption. The reason for loading this file dynamically is that the file size is quite big (~600KB) and including it as part of your main application JavaScript file might slow down the initial page load time.

// example of dynamically fetching openpgp library when using webpack
const openpgpModule = import(
  /* webpackChunkName: "openpgp,
     webpackPrefetch: true" */
  'openpgp')

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.

// Object to be encrypted
interface CardDetails {
 number?: string,    // required when storing card details
 cvv?: string        // required when cardVerification is set to cvv
}

// Encrypted result
interface EncryptedValue {
 encryptedData: string,
 keyId: string
}
 
const pciEncryptionKey = await getPCIPublicKey()
 
/**
* Encrypt card data function
*/
return async function(dataToEncrypt: CardDetails): Promise<EncryptedValue> {
 const decodedPublicKey = atob(pciEncryptionKey.publicKey)
 const openpgp = await openpgpModule
 const options = {
   message: openpgp.message.fromText(JSON.stringify(dataToEncrypt)),
   publicKeys: (await openpgp.key.readArmored(decodedPublicKey)).keys
 }
 
 return openpgp.encrypt(options).then((ciphertext) => {
   return {
     encryptedData: btoa(ciphertext.data),
     keyId: pciEncryptionKey.keyId
   }
 })
}

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).

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 business 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!

Updated 22 days ago


Accept Card Payments


Suggested Edits are limited on API Reference Pages

You can only suggest edits to Markdown body content, but not to the API spec.