Prepare vs Execute

Understand SDP's two signing modes for onchain transactions.

Every SDP mutation endpoint that produces a Solana transaction supports two signing modes. The mode you choose determines who signs and submits the transaction.

Execute mode (default)

When you call a mutation endpoint without the /prepare suffix, SDP handles everything:

  1. Builds the transaction
  2. Signs it using your configured custody provider
  3. Submits it to Solana
  4. Returns the confirmed result with a transaction signature
curl -X POST https://api.solana.com/v1/issuance/tokens/tok_abc123/mint \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: mint-001" \
  -d '{
    "mint": {
      "destination": "7xKXz...9fGh",
      "amount": "1000000"
    }
  }'
const response = await fetch(
  "https://api.solana.com/v1/issuance/tokens/tok_abc123/mint",
  {
    method: "POST",
    headers: {
      "Authorization": "Bearer sk_test_...",
      "Content-Type": "application/json",
      "Idempotency-Key": "mint-001",
    },
    body: JSON.stringify({
      mint: { destination: "7xKXz...9fGh", amount: "1000000" },
    }),
  }
);
const { data } = await response.json();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.solana.com/v1/issuance/tokens/tok_abc123/mint"))
    .header("Authorization", "Bearer sk_test_...")
    .header("Content-Type", "application/json")
    .header("Idempotency-Key", "mint-001")
    .POST(HttpRequest.BodyPublishers.ofString("""
        {
          "mint": {
            "destination": "7xKXz...9fGh",
            "amount": "1000000"
          }
        }"""))
    .build();

When to use execute mode:

  • You trust SDP's custody provider with signing
  • You want the simplest integration (one API call)
  • Backend-to-backend workflows where you don't need user signatures

Prepare mode

When you add /prepare to a mutation endpoint, SDP builds the transaction but returns it unsigned:

curl -X POST https://api.solana.com/v1/issuance/tokens/tok_abc123/mint/prepare \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{
    "mint": {
      "destination": "7xKXz...9fGh",
      "amount": "1000000"
    },
    "options": { "simulate": true }
  }'
const response = await fetch(
  "https://api.solana.com/v1/issuance/tokens/tok_abc123/mint/prepare",
  {
    method: "POST",
    headers: {
      "Authorization": "Bearer sk_test_...",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      mint: { destination: "7xKXz...9fGh", amount: "1000000" },
      options: { simulate: true },
    }),
  }
);
const { data } = await response.json();
// data.preparedTransaction.serialized — base64 transaction to sign
// data.simulation — { success, unitsConsumed, logs }
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.solana.com/v1/issuance/tokens/tok_abc123/mint/prepare"))
    .header("Authorization", "Bearer sk_test_...")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("""
        {
          "mint": {
            "destination": "7xKXz...9fGh",
            "amount": "1000000"
          },
          "options": { "simulate": true }
        }"""))
    .build();

When to use prepare mode:

  • You manage your own keys (hardware wallet, multisig, etc.)
  • You need user approval before signing (wallet pop-up flow)
  • You want to simulate the transaction before committing
  • Regulatory requirements mandate specific signing infrastructure

Signing a prepared transaction

After receiving the serialized transaction:

  1. Decode the base64 string into a transaction object
  2. Sign with the required private key(s)
  3. Submit to Solana via sendRawTransaction
  4. Confirm the transaction using confirmTransaction

Submit before lastValidBlockHeight expires. If the blockhash expires, call /prepare again for a fresh transaction.

Simulation

Prepare endpoints accept options.simulate: true to dry-run the transaction before you sign. The simulation returns:

  • success — whether the transaction would succeed
  • unitsConsumed — compute units used
  • logs — program execution logs
  • error — error details if simulation fails

Endpoints that support both modes

ResourceExecutePrepare
Deploy tokenPOST .../deployPOST .../deploy/prepare
MintPOST .../mintPOST .../mint/prepare
BurnPOST .../burnPOST .../burn/prepare
Force-burnPOST .../force-burnPOST .../force-burn/prepare
SeizePOST .../seizePOST .../seize/prepare
Update authorityPOST .../authorityPOST .../authority/prepare
TransferPOST /v1/payments/transfersPOST /v1/payments/transfers/prepare

Issuance paths are prefixed with /v1/issuance/tokens/{tokenId}. Transfer flows use the concrete payments mutation paths POST /v1/payments/transfers and POST /v1/payments/transfers/prepare.

Idempotency

Both modes support the Idempotency-Key header. For execute mode, the key prevents duplicate submissions. For prepare mode, the key ensures you get the same prepared transaction if you retry the request.