Skip to Content

Rescue Funds

POST/payments/:paymentId/rescue

Description

Recover excess deposits or wrong tokens from a direct payment contract. Transfers the full token balance to the specified receiver. Requires a signed request.

💡

Rescue is typically used when a customer accidentally overpays or sends the wrong stablecoin.

Headers

HeaderDescriptionRequired
AuthorizationBearer token with your API keyyes
Content-Typeapplication/jsonyes
X-SignatureSignature from signRescue(), signed with your signing key.yes

Path Parameters

NameTypeDescriptionRequired
paymentIdstringThe unique identifier of the payment to rescue funds from.yes

Request Body

NameTypeDescriptionRequired
tokenstringToken contract address to rescue.yes
receiverstringWallet address to send the rescued tokens to.yes
deadlineintegerUnix timestamp after which the signature expires. Use the value returned by signRescue().yes

Example Request

import { CheckoutSigner } from '@exodus/checkout-signer'
 
const signer = new CheckoutSigner()
 
const paymentId = 'tz4a98xxat96iws9zmbrgj3a'
// The token to recover and where it should go — not on the payment object
const token = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' // USDC on Ethereum
const receiver = '0x742d35Cc6634C0532925a3b844Bc9e7595f8fE21'
 
// Fetch the payment (or use the payment webhook object as-is)
const payment = await fetch(
  `https://checkout-api.exodus-int.com/payments/${paymentId}`,
  { headers: { Authorization: 'Bearer sk_live_xxxxxxxxxxxxxxxx' } },
).then((r) => r.json())
 
// Pass the payment straight in; token and receiver are yours to supply
const { signature, body } = signer.signRescue(payment, { token, receiver })
 
const response = await fetch(
  `https://checkout-api.exodus-int.com/payments/${paymentId}/rescue`,
  {
    method: 'POST',
    headers: {
      Authorization: 'Bearer sk_live_xxxxxxxxxxxxxxxx',
      'Content-Type': 'application/json',
      'X-Signature': signature,
    },
    body: JSON.stringify(body),
  },
)

Response

SUCCESSFUL RESCUE
{
  "id": "tz4a98xxat96iws9zmbrgj3a",
  "on_chain_id": "0x1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b",
  "token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
  "receiver": "0x742d35Cc6634C0532925a3b844Bc9e7595f8fE21",
  "tx_hash": "0x8a9c67b2d1e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9"
}

Error Responses

NOTHING TO RESCUE
{
  "error": {
    "type": "invalid_request",
    "message": "No token balance available to rescue"
  }
}
INVALID SIGNATURE
{
  "error": {
    "type": "authentication_error",
    "message": "Invalid signature"
  }
}
🛡️

Rescue screens the receiver address before moving funds. If the screen blocks it or the screening provider is temporarily unavailable, the API returns 422 with error.type: "cannot_process".

SCREENING BLOCKED (422)
{
  "error": {
    "type": "cannot_process",
    "message": "Payment cannot be processed",
    "code": "flagged",
    "data": {
      "payment_id": "tz4a98xxat96iws9zmbrgj3a",
      "address": "0x742d35Cc6634C0532925a3b844Bc9e7595f8fE21"
    }
  }
}

error.code is flagged (receiver blocked) or screening_pending (provider temporarily unavailable, retry later).

Start building

XO

Request Demo

Schedule a call with our team

Select a product
Arrow right

Start building
Grateful

Contact Us

We're here to help