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:
- Builds the transaction
- Signs it using your configured custody provider
- Submits it to Solana
- 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:
- Decode the base64 string into a transaction object
- Sign with the required private key(s)
- Submit to Solana via
sendRawTransaction - 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 succeedunitsConsumed— compute units usedlogs— program execution logserror— error details if simulation fails
Endpoints that support both modes
| Resource | Execute | Prepare |
|---|---|---|
| Deploy token | POST .../deploy | POST .../deploy/prepare |
| Mint | POST .../mint | POST .../mint/prepare |
| Burn | POST .../burn | POST .../burn/prepare |
| Force-burn | POST .../force-burn | POST .../force-burn/prepare |
| Seize | POST .../seize | POST .../seize/prepare |
| Update authority | POST .../authority | POST .../authority/prepare |
| Transfer | POST /v1/payments/transfers | POST /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.