Note: This guide provides API requests in cURL format, along with example responses.
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:
Permit2 contract a
USDC allowance.transactionVersion parameter
to VERSION_2.fees field. The
gas fee is collected by Circle's payment settlement smart contract during
onchain transaction processing.messageToBeSigned field and submit the signature.This guide provides information on how to migrate your existing integration from Transactions V1 to V2.
Before you begin, ensure that you have:
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.
Use the following steps to create an onchain transaction using Transactions V2.
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.
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": {}
}
}
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"
}
'
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.