StableFX

Tutorial: Test your StableFX Integration as a Taker

This tutorial walks you through the steps to test your StableFX integration as a taker.

Before you begin, ensure that you have:

  • Obtained a sandbox API key for StableFX from Circle
  • Obtained testnet USDC in a supported wallet on Arc
  • Installed cURL on your development machine

This guide provides API requests in cURL format, along with example responses.

To test your integration, you need to create at least one trade in the sandbox environment. Use the following steps to create a trade:

Request a quote for a trade from USDC to EURC using the create a quote endpoint. You should provide a value for the amount parameter in either the from or to fields, but not both. The following is an example request for a quote:

Shell
curl --request POST \
  --url https://api-sandbox.circle.com/v1/exchange/stablefx/quotes \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer ${YOUR_API_KEY}' \
  --header 'Content-Type: application/json' \
  --data '
{
  "from": {
    "currency": "USDC",
    "amount": "10"
  },
  "to": {
    "currency": "EURC"
  },
  "tenor": "instant"
}
'

Response

JSON
{
  "id": "c4d1da72-111e-4d52-bdbf-2e74a2d803d5",
  "rate": 0.915,
  "to": {
    "currency": "EURC",
    "amount": "9.15"
  },
  "from": {
    "currency": "USDC",
    "amount": "10"
  },
  "timestamp": "2023-01-01T12:04:05Z",
  "expiry": "2023-01-01T12:04:05Z",
  "fee": {
    "currency": "USDC",
    "amount": "0.01"
  }
}

Accept the quote and create a trade on StableFX using the create a trade endpoint. You need to provide the quote ID and a randomly generated idempotency key in UUIDv4 format. The following is an example request for a trade:

Shell

curl --request POST \
  --url https://api-sandbox.circle.com/v1/exchange/stablefx/trades \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer ${YOUR_API_KEY}' \
  --header 'Content-Type: application/json' \
  --data '
{
  "idempotencyKey": "${randomUUID}",
  "quoteId": "c4d1da72-111e-4d52-bdbf-2e74a2d803d5"
}
'

Response

JSON
{
  "id": "c2558cd1-98b5-4ccd-90b8-96891512af20",
  "contractTradeId": "b4cdae0f-9285-48bf-8abf-109ae0177621",
  "status": "pending",
  "rate": 0.915,
  "from": {
    "currency": "USDC",
    "amount": "10"
  },
  "to": {
    "currency": "EURC",
    "amount": "9.15"
  },
  "createDate": "2025-01-01T12:04:05Z",
  "updateDate": "2025-01-01T12:04:05Z",
  "quoteId": "c4d1da72-111e-4d52-bdbf-2e74a2d803d5"
}

Once the trade is created, you need to register your signature with the StableFX API.

Using the trade ID, get the typed data for the trade using the generate trade presign data endpoint. On the taker side, you must provide the recipientAddress parameter. The following is an example request for the typed data:

Shell
curl --request GET \
  --url https://api-sandbox.circle.com/v1/exchange/stablefx/signatures/presign/taker/c2558cd1-98b5-4ccd-90b8-96891512af20?recipientAddress=0xabc123... \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer ${YOUR_API_KEY}'

Response

JSON
{
  "consideration": {
    "quoteId": "c4d1da72-111e-4d52-bdbf-2e74a2d803d5",
    "base": "0x...",
    "quote": "0x...",
    "baseAmount": "10",
    "quoteAmount": "9.15",
    "maturity": 1752148800
  },
  "recipient": "0xabc123...",
  "deadline": 1752149700,
  "fee": "100000"
}

Using your wallet, sign the typed data returned from the previous step.

Submit the signed data to the submit a trade signature endpoint. The following is an example request for the signed data:

Shell
curl --request POST \
  --url https://api-sandbox.circle.com/v1/exchange/stablefx/signatures \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer ${YOUR_API_KEY}' \
  --header 'Content-Type: application/json' \
  --data '
{
  "tradeId": "c2558cd1-98b5-4ccd-90b8-96891512af20",
  "type": "taker",
  "address": "0xabc123...",
  "details": {
    "consideration": {
      "quoteId": "c4d1da72-111e-4d52-bdbf-2e74a2d803d5",
      "base": "0x...",
      "quote": "0x...",
      "baseAmount": "10",
      "quoteAmount": "9.15",
      "maturity": 1752148800
    },
    "recipient": "0xabc123...",
    "deadline": 1752149700,
    "fee": "100000"
  },
  "signature": "0xsignature"
}

If the signed data is accepted, the API returns a blank 200 response.

Use the following steps to fund the trade onchain.

Before you send funds onchain, you should confirm that the trade is ready for funding. To do this, call the get all trades endpoint. You should filter the response by the pending_settlement status. Your trade ID should be listed in the response.

Shell
curl --request GET \
  --url https://api-sandbox.circle.com/v1/exchange/stablefx/trades?type=taker&status=pending_settlement \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer ${YOUR_API_KEY}'

Response

JSON
{
  "id": "c2558cd1-98b5-4ccd-90b8-96891512af20",
  "contractTradeId": "24",
  "status": "pending_settlement",
  "rate": 0.915,
  "from": {
    "currency": "USDC",
    "amount": ""
  },
  "to": {
    "currency": "USDC",
    "amount": ""
  },
  "createDate": "2023-01-01T12:04:05Z",
  "updateDate": "2023-01-01T12:04:05Z",
  "quoteId": "c4d1da72-111e-4d52-bdbf-2e74a2d803d5"
}

To use the StableFX API to deliver the funds onchain, you must first sign the funding typed data with an EIP-712 signature. To get the data to sign, call the generate funding presign data endpoint. Your request must include the contract ID of the trade and the side of the trade that you are taking. The following an example request:

Shell
curl --request POST \
  --url https://api-sandbox.circle.com/v1/exchange/stablefx/signatures/funding/presign \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer ${YOUR_API_KEY}' \
  --header 'Content-Type: application/json' \
  --data '
{
  "contractTradeIds": ["${stablefx_contract_trade_id}"],
  "type": "taker"
}
'

Response

JSON
{
  "typedData": {
    "domain": {
      "name": "Permit2",
      "chainId": 11155111,
      "verifyingContract": "0xffd21ca8F0876DaFAD7de09404E0c1f868bbf1AE"
    },
    "types": {
      "EIP712Domain": [
        {
          "name": "name",
          "type": "string"
        },

        {
          "name": "chainId",
          "type": "uint256"
        },

        {
          "name": "verifyingContract",
          "type": "address"
        }
      ],
      "TokenPermissions": [
        {
          "name": "token",
          "type": "address"
        },

        {
          "name": "amount",
          "type": "uint256"
        }
      ],
      "SingleTradeWitness": [
        {
          "name": "id",
          "type": "uint256"
        }
      ],
      "PermitWitnessTransferFrom": [
        {
          "name": "permitted",
          "type": "TokenPermissions"
        },

        {
          "name": "spender",
          "type": "address"
        },

        {
          "name": "nonce",
          "type": "uint256"
        },

        {
          "name": "deadline",
          "type": "uint256"
        },

        {
          "name": "witness",
          "type": "SingleTradeWitness"
        }
      ]
    },
    "primaryType": "PermitWitnessTransferFrom",
    "message": {
      "permitted": {
        "token": "0xTOKEN",
        "amount": "1000"
      },
      "spender": "0xffd21ca8F0876DaFAD7de09404E0c1f868bbf1AE",
      "nonce": "42",
      "deadline": "1735689600",
      "witness": {
        "id": "10"
      }
    }
  }
}

Using a Permit2-compliant EIP-712 compatible wallet or application, sign the data from the typedData field returned in the previous step.

The StableFX API can handle the onchain transaction for you. You must submit a permit2-compliant data object along with the signature to the fund trades endpoint. The endpoint allows you to submit either a single object or a batch of objects along with the required signatures.

The following is an example request for a single trade:

Shell
curl --request POST \
  --url https://api-sandbox.circle.com/v1/exchange/stablefx/fund \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer ${YOUR_API_KEY}' \
  --header 'Content-Type: application/json' \
  --data '
{
  "type": "taker",
  "signature": "0xsignature",
  "permit2": {
    "permitted": {
      "token": "0xTOKEN1",
      "amount": "10"
    },
    "spender": "0xTOKEN1",
    "nonce": "123456",
    "deadline": 1752149700,
    "witness": {
      "id": "123456"
    }
  }
}
'

If the signed data is accepted, the API returns a blank 200 response.

You can repeat parts 1 and 2 to create multiple trades. This can be useful for testing a batch integration where you fund multiple trades at once. If you are testing batching, you need to get the contractTradeId for each trade that requires funding. You can do this by calling the get all trades endpoint. You can filter the response by the pending_settlement status.

Once you have the array of IDs, you can use the same fund trades endpoint to fund multiple trades by submitting the permit2 data for each trade along with the appropriate signatures.

Did this page help you?
© 2023-2025 Circle Technology Services, LLC. All rights reserved.