Overview
Escape hatch for a stalled deposit bridge leg: fetches the finalized
Circle attestation and returns one ready-to-sign emergencyClaimBridge
transaction on the destination chain. Minted USDC goes directly to the
burn-time beneficiary's wallet, bypassing the destination vault deposit.
The matching intent (kind emergency_claim) is written server-side. No
auth.
Eligibility (each failure is a 400 invalid_state): the transfer must be
a deposit leg, not already confirmed or user_claimed, at least 30
minutes old, and its recorded beneficiary must be the strategy owner. If
Circle has not finalized the attestation, the response is a 409
attestation_pending; poll on that status code.
approvalsNeeded is always []. expiresAt is nominal: the claim stays
valid until the message nonce is consumed on the destination chain. A
null gasHint with estimation_failed can mean the nonce was already
consumed (the transfer completed normally); the on-chain result is
authoritative.
Endpoint
POST https://earn-api.quicknode.dev/functions/v1/api/v1/strategies/{id}/calldata/claim
Authorization
Include the published apikey header. This endpoint is public and does not require a SIWE signature.
Rate limits
This operation belongs to the calldata rate-limit bucket. It allows 10 requests per 60 seconds, keyed by strategy+ip. A coarser limit of approximately 30 requests per 60 seconds also applies per IP across deposit, withdrawal, and claim calldata requests.
Parameters
| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
| id | path | string | Yes | Strategy UUID. |
Request body
Emergency claim request body. Public (no SIWE). Unlike deposit/withdraw an empty body is NOT valid: the route cannot pick a stalled transfer for the caller.
| Field | Type | Required | Description |
|---|---|---|---|
| transferId | string | Yes | The stalled transfer's `cctp_transfers` row id (find it via `GET /v1/strategies/{id}/bridges`). |
Example request
curl --request POST \
--url 'https://earn-api.quicknode.dev/functions/v1/api/v1/strategies/b7c1e2d3-0000-4000-8000-000000000001/calldata/claim' \
--header 'Accept: application/json' \
--header 'apikey: <EARN_PUBLIC_API_KEY>' \
--header 'Content-Type: application/json' \
--data '{
"transferId": "9a8b7c6d-0000-4000-8000-000000000123"
}'
Response
| Field | Type | Required | Description |
|---|---|---|---|
| kind | string (claim) | Yes | Identifies the response as an emergency claim calldata plan. |
| transactions | array<object> | Yes | Exactly one `emergencyClaimBridge` transaction, on the transfer's DESTINATION chain (transaction kind `emergency_claim`). |
| approvalsNeeded | array<object> | Yes | Always empty (`emergencyClaimBridge` pulls no tokens from the sender). |
| expiresAt | string | Yes | Advisory only — a finalized attestation stays valid until the nonce is consumed on the destination chain. |
| transactions[].chainId | integer | Yes | Destination chain on which to submit the claim. |
| transactions[].to | string | Yes | Quicknode Earn proxy on the destination chain. |
| transactions[].data | string | Yes | Emergency-claim calldata. Submit it verbatim. |
| transactions[].value | string | Yes | Native-token value. Always `"0"`. |
| transactions[].intentId | string | Yes | Intent UUID used to track the claim. |
| transactions[].kind | string (emergency_claim) | Yes | Transaction intent kind. |
| transactions[].description | string | Yes | Human-readable claim summary. |
| transactions[].gasHint | string | null | Yes | Recommended gas limit, or `null` when estimation failed. |
| transactions[].gasHintReason | string | No | `estimation_failed` when `gasHint` is `null`. |
Example response
{
"kind": "claim",
"transactions": [
{
"chainId": 42161,
"to": "0x48b415841165304f7EfaA7D5dD5FC65cc7B4bd8e",
"data": "0x0f2b1a3c0000000000000000000000000000000000000000000000000000000000000040",
"value": "0",
"intentId": "7f3a1c2b-0000-4000-8000-000000000abc",
"kind": "emergency_claim",
"description": "Claim bridged USDC on chain 42161 directly to your wallet, bypassing the relayer and the destination vault deposit",
"gasHint": "220000"
}
],
"approvalsNeeded": [],
"expiresAt": "2026-07-07T19:00:00.000Z"
}
HTTP responses
| Status | Description |
|---|---|
| 200 | One emergency-claim transaction on the destination chain. |
| 400 | A malformed JSON body or `transferId` (`invalid_request`), or the transfer is not claimable (`invalid_state`: already terminal, not deposit-shaped, not 30 minutes old yet, or the beneficiary does not match the strategy owner). |
| 404 | Strategy not found (`not_found`), or no such CCTP transfer for this strategy (`transfer_not_found`; also returned when the transfer belongs to another strategy). |
| 409 | Attestation not finalized yet (`attestation_pending`). Retry after `Retry-After` seconds. |
| 429 | Rate limit exceeded. `Retry-After` (seconds) tells you when to retry. Reads, feedback, and push writes are keyed per IP; create/update/delete are keyed per wallet+IP; deposit/withdraw/claim calldata is keyed per strategy+IP. |
| 500 | Internal error (including a failed intent write), or `unsupported_chain_pair` when the transfer's chain pair has no CCTP route configured. |
This page is based on operation claimCalldata in the Earn OpenAPI 3.1 specification.