Skip to main content
Transactions V2 allows for a more straightforward integration with CPN compared to Transactions V1. It also provides more powerful onchain settlement primitives, such as auto-acceleration and gas fees that are fixed at quote time. If you have previously integrated with CPN using the Transactions V1 API, you can migrate to Transactions V2 without changes to your wallet infrastructure. Compared to Transactions V1, Transactions V2 has the following differences:
  • When creating the CPN quote, you must set the transactionVersion parameter to VERSION_2.
  • Gas fees are not charged in native tokens, but in USDC. They are determined at quote creation instead of transaction creation in the quote fees field. The gas fee is collected by Circle’s payment settlement smart contract during onchain transaction processing.
  • There are separate API endpoints for creating and submitting transactions.
Depending on the blockchain, there are additional differences:
  • EVM chains
  • Solana
  • Before initiating a transaction, the sender wallet must grant the Permit2 contract a USDC allowance.
  • When signing the transaction, you no longer need to compose and sign the raw EVM transaction; you only need to sign the EIP-712 typed data provided to you in the messageToBeSigned field and submit the signature.
  • CPN handles the auto-acceleration of the transaction. You no longer need to monitor transaction broadcast status or submit acceleration transactions.
This guide provides information on how to migrate your existing integration from Transactions V1 to V2 on EVM. On Solana, you would follow a similar process with some differences in the signing process.

Prerequisites

Before you begin, ensure that you have:
  • Obtained an API key for CPN from Circle
  • USDC in your sender wallet
  • cURL installed on your development machine
  • (EVM chains only) Granted a USDC allowance to the Permit2 contract. See How-to: Grant USDC Allowance to Permit2 for more information.
Note: This guide provides API requests in cURL format, along with example responses.

Steps

Use the following steps to create an onchain transaction using Transactions V2.

Step 1. Create a quote

Use the create a quote endpoint to create a quote with the transactionVersion parameter set to VERSION_2.
curl --request POST \
  --url https://api.circle.com/v1/cpn/quotes \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer ${YOUR_API_KEY}' \
  --header 'Content-Type: application/json' \
  --data '
{
    "paymentMethodType": "SPEI",
    "senderCountry": "US",
    "destinationCountry": "MX",
    "sourceAmount": {
        "currency": "USDC"
    },
    "destinationAmount": {
        "amount": "200",
        "currency": "MXN"
    },
    "blockchain": "ETH-SEPOLIA",
    "senderType": "INDIVIDUAL",
    "recipientType": "INDIVIDUAL",
    "transactionVersion": "VERSION_2"
}
'
Response
{
  "data": [
    {
      "id": "2792f4a6-f1bd-4435-b681-1da309122159",
      "paymentMethodType": "SPEI",
      "blockchain": "ETH-SEPOLIA",
      "senderCountry": "US",
      "destinationCountry": "MX",
      "createDate": "2025-09-24T00:01:13.532073875Z",
      "quoteExpireDate": "2025-09-24T00:01:42.502094Z",
      "cryptoFundsSettlementExpireDate": "2025-09-24T01:01:12.502097Z",
      "sourceAmount": {
        "amount": "15.000000",
        "currency": "USDC"
      },
      "destinationAmount": {
        "amount": "252.91",
        "currency": "MXN"
      },
      "fiatSettlementTime": {
        "min": "0",
        "max": "5",
        "unit": "MINUTES"
      },
      "exchangeRate": {
        "rate": "16.860667",
        "pair": "USDC/MXN"
      },
      "fees": {
        "totalAmount": {
          "amount": "1.568971",
          "currency": "USDC"
        },
        "breakdown": [
          {
            "type": "TAX_FEE",
            "amount": {
              "amount": "0.234663",
              "currency": "USDC"
            }
          },
          {
            "type": "BFI_TRANSACTION_FEE",
            "amount": {
              "amount": "0.138037",
              "currency": "USDC"
            }
          },
          {
            "type": "CIRCLE_SERVICE_FEE",
            "amount": {
              "amount": "0.000000",
              "currency": "USDC"
            }
          },
          {
            "type": "BLOCKCHAIN_GAS_FEE",
            "amount": {
              "amount": "1.196271",
              "currency": "USDC"
            }
          }
        ]
      },
      "senderType": "INDIVIDUAL",
      "recipientType": "INDIVIDUAL",
      "certificate": {
        // certificate object
      },
      "quoteOptions": {
        "isFirstParty": false
      },
      "transactionVersion": "VERSION_2"
    }
  ]
}
Note: The quote returned from this step must follow the Transactions V2 workflow, you can’t switch from V2 back to V1 without first recreating the quote.

Step 2. Create a V2 transaction

You would then follow the same payment API workflow as before, create a payment from the create a payment endpoint. After your payment is in the CRYPTO_FUNDS_PENDING state, initiate the transaction using the create a transaction V2 endpoint.
curl --request POST \
  --url https://api.circle.com/v2/cpn/payments/:paymentId/transactions \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer ${YOUR_API_KEY}' \
  --header 'Content-Type: application/json' \
  --data '
{
  "idempotencyKey" : "${RANDOM_UUID}"
}
'
Response
{
  "data": {
    "id": "dbc27d23-cd4f-447e-855e-349cb2853d23",
    "status": "CREATED",
    "paymentId": "49d4231e-6c4f-319e-946d-ed8c8bab5abc",
    "expireDate": "2025-09-08T20:02:06.651391Z",
    "blockchain": "ETH-SEPOLIA",
    "senderAddress": "0x1234567890123456789012345678901234567890",
    "destinationAddress": "0x0000000000000000000000000000000000000001",
    "amount": {
      "amount": "15.000000",
      "currency": "USDC"
    },
    "messageType": "PAYMENT_SETTLEMENT_CONTRACT_V1_0_PAYMENT_INTENT",
    "messageToBeSigned": {
      "domain": {
        "name": "Permit2",
        "chainId": "11155111",
        "verifyingContract": "0x000000000022D473030F116dDEE9F6B43aC78BA3"
      },
      "message": {
        "permitted": {
          "token": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
          "amount": "14174474"
        },
        "spender": "0xe2B17D0C1736dc7C462ABc4233C91BDb9F27DD1d",
        "nonce": "25668617285137697861288274946631174355105919960416755114569514179393151588120",
        "deadline": "1757362866",
        "witness": {
          "from": "0x1234567890123456789012345678901234567890",
          "to": "0x0000000000000000000000000000000000000001",
          "value": 14174474,
          "validAfter": "1757358106",
          "validBefore": "1757361726",
          "nonce": "0x38bfec2b230187932870d575132e8ae1f83b34c10e3bf6d64c377f0c13245718",
          "beneficiary": "0x4f1c3a0359A7fAd8Fa8E9E872F7C06dAd97C91Fd",
          "maxFee": "0",
          "attester": "0x768919ef04853b5fd444ccff48cea154768a0291",
          "requirePayeeSign": false
        }
      },
      "primaryType": "PermitWitnessTransferFrom",
      "types": {
        "EIP712Domain": [
          {
            "name": "name",
            "type": "string"
          },
          {
            "name": "chainId",
            "type": "uint256"
          },
          {
            "name": "verifyingContract",
            "type": "address"
          }
        ],
        "PermitWitnessTransferFrom": [
          {
            "name": "permitted",
            "type": "TokenPermissions"
          },
          {
            "name": "spender",
            "type": "address"
          },
          {
            "name": "nonce",
            "type": "uint256"
          },
          {
            "name": "deadline",
            "type": "uint256"
          },
          {
            "name": "witness",
            "type": "PaymentIntent"
          }
        ],
        "TokenPermissions": [
          {
            "name": "token",
            "type": "address"
          },
          {
            "name": "amount",
            "type": "uint256"
          }
        ],
        "PaymentIntent": [
          {
            "name": "from",
            "type": "address"
          },
          {
            "name": "to",
            "type": "address"
          },
          {
            "name": "value",
            "type": "uint256"
          },
          {
            "name": "validAfter",
            "type": "uint256"
          },
          {
            "name": "validBefore",
            "type": "uint256"
          },
          {
            "name": "nonce",
            "type": "bytes32"
          },
          {
            "name": "beneficiary",
            "type": "address"
          },
          {
            "name": "maxFee",
            "type": "uint256"
          },
          {
            "name": "requirePayeeSign",
            "type": "bool"
          },
          {
            "name": "attester",
            "type": "address"
          }
        ]
      }
    },
    "metadata": {}
  }
}

Step 3. Sign and submit the transaction

From the response in the previous step, extract the messageToBeSigned field. You must sign this data using EIP-712 typed data signing from your sender wallet. Once signed, you should submit it to the submit transaction V2 endpoint. The following is an example request:
curl --request POST \
  --url https://api.circle.com/v2/cpn/payments/:paymentId/transactions/:transactionId/submit \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer ${YOUR_API_KEY}' \
  --header 'Content-type: application/json' \
  --data '
{
  "signedTransaction": "0x12b5fb72e99f9bb0300d2eb66a6d89dd5a667f43669893cf14bfcc390754dcb61b69f92cba598ec83a184e11c97e3bb9964a2bfd7a09688eee63f586ad9ccae21c"
}
'
Note: For Solana, follow the steps in How-to: Create an Onchain Transaction to sign the transaction. You would submit the signed transaction in the same way as for EVM.
After the transaction is submitted, CPN is responsible for broadcasting the transaction to the blockchain. You will be notified by webhooks when events related to the transaction occur. Unlike Transaction V1, you don’t need to actively monitor the transaction or manually accelerate it. CPN monitors the transaction and automatically accelerates it if necessary.