Skip to main content

Operations and Transaction Intents

Two resources cover everything asynchronous or wallet-signed in API v2:
  • An operation is long-running server work you poll for a terminal state.
  • A transaction intent is a Solana transaction that Blank prepared for a specific wallet, which that wallet must sign before Blank will broadcast it.
An API key never replaces a wallet signature. It authorizes preparing and submitting a transaction; the pinned wallet still signs the exact prepared message. Blank verifies the message, the required signer, the blockhash window, the intent policy, and the resource version before broadcast.

Operations

Operations are account-scoped: a key can only read operations owned by its own Blank account. Unknown or foreign IDs return 404 operation_not_found.

Fields

queued and running responses carry Retry-After: 2. Honour it instead of tight polling.

Polling

A failed operation carries the full Problem Details in error, including the code and the requestId of the failure. Log both. Rather than polling at all, subscribe to build.blank.operation.failed.v1 and the completion events you care about. See Webhooks.

Transaction intents

Intents are account-scoped in the same way. The public contract exposes retrieval and signed submission; an intent is prepared by the Blank flow that needs a wallet signature, and you receive its intentId from that flow.

Fields

Lifecycle

  1. prepared — Blank has built the transaction and is waiting for a signature.
  2. submitted — the signature verified and the transaction is durably queued for broadcast. The response carries Retry-After: 2.
  3. confirmed — the transaction landed. transactionSignature is populated.
  4. expired — the blockhash window closed before a valid submission arrived.
  5. failed — broadcast or confirmation failed. error explains why.

Signing and submitting

Sign the prepared message byte-for-byte. Do not let a wallet rewrite the fee payer, blockhash, compute-budget instructions, or lookup tables. Any change to the message returns 422 transaction_intent_tampered. And never sign a transaction your application has not independently inspected.
Submission requires both concurrency headers, which the SDK sets from the arguments you pass:
  • If-Match: "<version>" — the intent version you read
  • Idempotency-Key — a durable key you should generate and persist yourself
The 202 response includes Location pointing at the intent, ETag with the new version, and Retry-After: 2. Raw HTTP:

Reconciling an uncertain submission

A 202 means the transaction is durably queued, not that it landed. Never assume an outcome from a dropped connection.
  1. Retry the submission with the same Idempotency-Key. A completed attempt replays with Idempotent-Replayed: true; an in-flight attempt returns 409 idempotency_request_in_progress with Retry-After: 1.
  2. Poll getTransactionIntent until status reaches confirmed, failed, or expired, honouring Retry-After.
  3. On confirmed, record transactionSignature. On failed, read error.code. On expired, request a fresh intent — a signature cannot be reused across intents.
TransactionIntent.error.code is a closed contract: solana_transaction_failed, transaction_intent_invalid_state, transaction_intent_expired, transaction_intent_broadcast_exhausted, solana_blockhash_expired, or solana_signature_mismatch. See Transaction-intent result codes for the action associated with each one.

Submission errors

Shared errors also apply: 401 invalid_api_key, 403 insufficient_scope, 409 idempotency_key_reused, 409 idempotency_request_in_progress, 429 rate_limit_exceeded. See Errors and Conventions.