Skip to main content
Checkout lets you send a crypto payment from any supported chain and have it settled in a specific token on a specific chain. This guide walks through the complete checkout flow, from creating a transaction to polling for settlement completion.

Prerequisites

Before starting a checkout flow, you need a checkoutId. Create one by calling the Create a checkout API endpoint:
curl --request POST \
  --url https://app.dynamic.xyz/api/v0/environments/<YOUR_ENVIRONMENT_ID>/checkouts \
  --header 'Authorization: Bearer <YOUR_API_TOKEN>' \
  --header 'Content-Type: application/json' \
  --data '{
    "mode": "payment",
    "settlementConfig": {
      "strategy": "cheapest",
      "settlements": [
        {
          "chainName": "EVM",
          "tokenAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
          "chainId": "1",
          "symbol": "USDC",
          "tokenDecimals": 18,
          "isNative": false
        }
      ]
    },
    "destinationConfig": {
      "destinations": [
        {
          "chainName": "EVM",
          "type": "address",
          "identifier": "0xYourSettlementAddress"
        }
      ]
    },
    "enableOrchestration": true
  }'
The response includes an id field — use this as the checkoutId when calling createCheckoutTransaction.

Supported Chains

The checkout flow supports the following chains:
  • BTC
  • EVM
  • SOL
  • SUI
Except for the EVM chains listed below, only mainnet is supported:
NameID
Base Sepolia Testnet"84532"
Arbitrum Sepolia Testnet"421614"
Arc Testnet"5042002"
OP Sepolia Testnet"11155420"

Overview

The checkout flow follows these steps:
  1. Create a transaction with createCheckoutTransaction
  2. Attach the source wallet with attachCheckoutTransactionSource
  3. Quote the conversion with getCheckoutTransactionQuote
  4. Submit the transaction with submitCheckoutTransaction (prepares, signs, and broadcasts)
  5. Poll for completion with getCheckoutTransaction

Full example

import {
  createCheckoutTransaction,
  attachCheckoutTransactionSource,
  getCheckoutTransactionQuote,
  submitCheckoutTransaction,
  getCheckoutTransaction,
} from '@dynamic-labs-sdk/client';

const checkout = async (walletAccount) => {
  // Step 1: Create the transaction
  const { transaction } = await createCheckoutTransaction({
    amount: '25.00',
    currency: 'USD',
    checkoutId: 'checkout_abc123',
  });

  // Step 2: Attach the wallet source
  await attachCheckoutTransactionSource({
    transactionId: transaction.id,
    fromAddress: walletAccount.address,
    fromChainId: '1',
    fromChainName: walletAccount.chain,
  });

  // Step 3: Get a quote
  const quoted = await getCheckoutTransactionQuote({
    transactionId: transaction.id,
    fromTokenAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
  });

  console.log('Quote:', quoted.quote);

  // Step 4: Submit (prepare + sign + broadcast)
  const result = await submitCheckoutTransaction({
    transactionId: transaction.id,
    walletAccount,
  });

  // Step 5: Poll for completion
  const final = await getCheckoutTransaction({
    transactionId: transaction.id,
  });

  console.log('Final state:', final.settlementState);
};

Handling cancellation and errors

import {
  submitCheckoutTransaction,
  cancelCheckoutTransaction,
} from '@dynamic-labs-sdk/client';

try {
  await submitCheckoutTransaction({
    transactionId: transaction.id,
    walletAccount,
  });
} catch (error) {
  if (error.message.includes('rejected')) {
    // User rejected the signing request in their wallet
    await cancelCheckoutTransaction({
      transactionId: transaction.id,
    });
    console.log('Transaction cancelled');
  } else {
    console.error('Checkout failed:', error.message);
  }
}

Polling for status

After submission, poll getCheckoutTransaction to track progress through execution and settlement states:
import { getCheckoutTransaction } from '@dynamic-labs-sdk/client';

const TERMINAL_EXECUTION = ['cancelled', 'expired', 'failed'];
const TERMINAL_SETTLEMENT = ['completed', 'failed'];

const pollTransaction = async (transactionId) => {
  const poll = async () => {
    const tx = await getCheckoutTransaction({ transactionId });

    if (
      TERMINAL_EXECUTION.includes(tx.executionState) ||
      TERMINAL_SETTLEMENT.includes(tx.settlementState)
    ) {
      return tx;
    }

    await new Promise((resolve) => setTimeout(resolve, 3000));
    return poll();
  };

  return poll();
};