Skip to main content
REST broadcasts create persisted transaction records that Para tracks to terminal status on-chain. Records are queryable, auditable, and emit webhooks when they confirm or fail — no partner-side indexer required. Rows are written for POST /v1/wallets/{walletId}/transfer broadcasts and for POST /v1/wallets/{walletId}/sign-transaction when broadcast: true. Sign-only calls do not write rows.

Status Lifecycle

pending → submitted → confirmed
                    → reverted
                    ↘ failed
StatusMeaning
pendingRecord inserted; broadcast not yet attempted.
submittedRPC accepted the signed bytes. Monitor is running. Not terminal.
confirmedIncluded in a block, not reverted. blockNumber and blockHash are populated.
revertedIncluded on-chain but execution failed (EVM status=0 or Solana signature error). Terminal.
failedNever broadcast, or broadcast was rejected by the RPC. failureStage identifies where. Terminal.
Partner code must treat unknown status values as non-terminal. Para may add new statuses (finalized, replaced) in a later release without bumping the API version.

Response Shape

Calls that broadcast return a transactionId field and set an x-transaction-id response header. Use either to look up the record afterward.
{
  "signedTransaction": "0x02f8...",
  "txHash": "0x1234abcd...",
  "transactionId": "550e8400-e29b-41d4-a716-446655440000"
}
For sign-transaction, omitted broadcast is also sign-only — no record is written and no transactionId is returned.
If a broadcast request fails after Para creates the transaction row, the error response still sets x-transaction-id and includes transactionId in the JSON body. Failures after signing also include signedTransaction. Use the transaction history record’s failureStage and failureCode fields for persisted failure details.

Reading Transaction History

List transactions for a wallet

curl -H "X-API-Key: $PARA_API_KEY" \
  "https://api.beta.getpara.com/v1/wallets/$WALLET_ID/transactions?status=confirmed&limit=20"
Filter by status via ?status=. Filter by source operation via ?intentKind=transfer or ?intentKind=sign_transaction. Paginate via ?cursor= using the opaque cursor returned in each response. Results are ordered by createdAt DESC.

Look up a single transaction

curl -H "X-API-Key: $PARA_API_KEY" \
  "https://api.beta.getpara.com/v1/wallets/$WALLET_ID/transactions/$TX_ID"
Records that belong to a different partner return 404 with an identical body to missing records.

Record Fields

Each record includes intentKind, either transfer or sign_transaction. For EVM sign_transaction records, Para stores chainId, to, and value when value was present in the request. tokenAddress is absent. Para does not decode calldata. For Solana sign_transaction records, to, value, and tokenAddress are absent because Para does not decode arbitrary Solana instructions.

Polling Recipe

When webhooks aren’t practical, poll the record until it leaves the submitted state.
async function waitForConfirmation(walletId: string, transactionId: string) {
  const start = Date.now();
  let delayMs = 2000;
  const timeoutMs = 10 * 60 * 1000;

  while (Date.now() - start < timeoutMs) {
    const res = await fetch(
      `https://api.beta.getpara.com/v1/wallets/${walletId}/transactions/${transactionId}`,
      { headers: { 'X-API-Key': process.env.PARA_API_KEY! } },
    );
    const record = await res.json();

    if (record.status === 'confirmed' || record.status === 'reverted' || record.status === 'failed') {
      return record;
    }
    await new Promise((r) => setTimeout(r, delayMs));
    delayMs = Math.min(delayMs * 1.5, 15000);
  }
  throw new Error('timed out waiting for confirmation');
}

Webhooks

Subscribe to two event types from the Developer Portal to receive terminal-state notifications automatically:
EventWhen it fires
rest.transaction.confirmedTransaction included in a block without reverting.
rest.transaction.failedTransaction reverted on-chain, or monitor detected a terminal RPC failure.
Payload example for rest.transaction.confirmed:
{
  "transactionId": "550e8400-e29b-41d4-a716-446655440000",
  "walletId": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
  "partnerId": "11111111-2222-3333-4444-555555555555",
  "intentKind": "transfer",
  "type": "EVM",
  "hash": "0x1234abcd...",
  "blockNumber": "5127103",
  "blockHash": "0xdeadbeef...",
  "resolvedAt": "2026-04-23T12:00:00.000Z"
}
rest.transaction.failed mirrors the shape and adds status (reverted or failed), plus optional failureStage, failureCode, and failureMessage fields.

Failure Fields

When status = failed, failureStage describes where the pipeline broke:
StageMeaning
mpc_signThe MPC signing ceremony errored before a signature was produced.
signature_applyThe signature could not be attached to the transaction.
signer_verifyThe recovered signer address did not match the wallet’s public address (EVM only).
broadcastThe RPC node rejected the signed bytes (e.g. INSUFFICIENT_NATIVE_BALANCE, EXECUTION_FAILED).
monitor_timeoutThe signed transaction was broadcast but didn’t reach a terminal on-chain state within Para’s 30-minute monitor window. The transaction may still confirm later — query the chain directly to verify.
When status = reverted, the transaction reached the chain and executed with a revert — blockNumber and blockHash are populated, failureStage is absent, and failureMessage contains any error detail surfaced by the monitor.

Broadcast Error Messages

REST /transfer now sources broadcast-failure messages from Para’s shared broadcast helper rather than passing through raw ethers.js strings. If code parses the previous raw string format, update it to read failureCode (e.g. INSUFFICIENT_NATIVE_BALANCE, EXECUTION_FAILED) from the transaction record or failure webhook instead.

Retention

Both /transfer broadcasts and sign-transaction calls with broadcast: true write rows. Retention remains deferred until the rest_transfers table reaches an agreed large-row or disk threshold.