API reference · v1

Developers

Authentication

Every request carries an API key in the Authorization header. Keys are scoped to your contracts: a key can only submit to and read the contracts it was issued for.

header
Authorization: Bearer $CORSA_API_KEY

Submit

Submit a finalized PSBT (preferred) or a signed transaction against a contract. Validation happens here: anything that can be refused is refused now, never at mining time.

POST/v1/contracts/{contractId}/submissions
curl
curl -X POST https://api.corsa.example/v1/contracts/{contractId}/submissions \
  -H "Authorization: Bearer $CORSA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "psbt": "cHNidP8BAH..." }'
202 Accepted
{
  "submissionId": "sub_01J...",
  "state": "accepted",
  "weightUnits": 1532,
  "window": { "startHeight": 921410, "endHeight": 921420 }
}

Check status

States: accepted → queued → mining → delivered, or failed with a reason.

GET/v1/submissions/{submissionId}

Replace

Swap the staged transaction for a new one. Allowed until the delivery window opens.

PUT/v1/submissions/{submissionId}

Withdraw

Remove a submission. Allowed any time before delivery.

DELETE/v1/submissions/{submissionId}

Webhooks

Subscribe to state changes:

  • submission.accepted
  • submission.queued
  • submission.mining
  • submission.delivered
  • submission.failed
submission.delivered
{
  "type": "submission.delivered",
  "submissionId": "sub_01J...",
  "data": {
    "txid": "4f2a...c91e",
    "blockHeight": 921413,
    "blockHash": "00000000000000000001a7...",
    "coinbase": {
      "txid": "9b0d...7f33",
      "attribution": "corsa:delivery"
    }
  }
}

Errors

Every rejection comes with a machine-readable reason code and a human-readable message.

422 Unprocessable
{
  "error": {
    "code": "input_already_spent",
    "message": "An input of this transaction has been spent.",
    "submissionId": "sub_01J..."
  }
}