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.

If you are accepting a one-off payment (that is, your product does not need to support accepting multiple future payments for this card), then you should set the cardVerification property in the request to none, as a CVV check will be done during payment creation time.

If you intend on reusing this card for repeated payments in the future, then it makes sense to complete card verification at this point by the cardVerification property in the request to cvv.

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 verificationStatus object.

Create a Card Payment

If this is a recurring / repeat payment and you are providing the CVV of the card again then that value needs to be encrypted. 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 contain the cvv property.

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. You then 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 3 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.