Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.ratiofx.com/llms.txt

Use this file to discover all available pages before exploring further.

Settlement status is available two ways: synchronously in the POST /v1/execute response, and asynchronously via webhook callback. Use webhooks to drive downstream processing without polling.

Webhook setup

Provide your webhook endpoint URL during onboarding. Ratio sends HTTP POST requests to this URL when events occur.
ConfigurationDescription
Webhook URLYour HTTPS endpoint (e.g., https://yourapp.com/ratio/callback)
Webhook secretHMAC-SHA256 key for verifying callback authenticity
EventsSettlement confirmations, quote expirations, system state changes
Your webhook endpoint must:
  • Accept POST requests with Content-Type: application/json
  • Return HTTP 200 within 5 seconds to acknowledge receipt
  • Be idempotent — the same event may be delivered more than once
Return 200 immediately on receipt, then process the event asynchronously. This prevents timeouts from triggering Ratio’s retry logic.

Webhook events

settlement.confirmed

Fired when a swap settles on-chain. Includes full execution details.
{
  "event": "settlement.confirmed",
  "timestamp": "2026-02-27T10:00:32Z",
  "data": {
    "execution_id": "EX-9910-USD-IDR",
    "quote_id": "QT-8821-USD-IDR",
    "pair": "USD-IDR",
    "status": "SETTLED",
    "filled_rate": 16020.00,
    "source_amount": 50000,
    "destination_amount": 801000000,
    "tx_hash": "0xKAIA...ABC",
    "settled_at": "2026-02-27T10:00:32Z"
  }
}

settlement.failed

Fired when a swap execution fails. This is rare and typically caused by an on-chain revert.
{
  "event": "settlement.failed",
  "timestamp": "2026-02-27T10:00:35Z",
  "data": {
    "execution_id": "EX-9911-USD-IDR",
    "quote_id": "QT-8822-USD-IDR",
    "pair": "USD-IDR",
    "status": "FAILED",
    "reason": "ON_CHAIN_REVERT"
  }
}

quote.expired

Fired when a firm quote expires without being executed. Reserved inventory is released.
{
  "event": "quote.expired",
  "timestamp": "2026-02-27T10:01:15Z",
  "data": {
    "quote_id": "QT-8823-USD-IDR",
    "pair": "USD-IDR",
    "side": "BUY",
    "amount": 50000,
    "expiry_timestamp": "2026-02-27T10:01:15Z"
  }
}

system.state_change

Fired when a corridor’s operating state changes (for example, from NORMAL to PROTECT).
{
  "event": "system.state_change",
  "timestamp": "2026-02-27T10:05:00Z",
  "data": {
    "corridor": "MYR-IDR",
    "previous_state": "NORMAL",
    "new_state": "PROTECT",
    "allowed_directions": ["BUY", "SELL"]
  }
}

Event types summary

EventDescription
settlement.confirmedSwap has settled on-chain. Includes full execution details.
settlement.failedSwap execution failed (rare — typically due to on-chain revert).
quote.expiredA firm quote expired without being executed. Inventory released.
system.state_changeA corridor’s system state has changed.

Signature verification

Every webhook request includes a signature header:
X-Ratio-Signature: sha256=<hex_digest>
Verify the signature before processing any event:
  1. Compute HMAC-SHA256 of the raw request body using your webhook secret.
  2. Compare the computed digest with the value in the X-Ratio-Signature header.
  3. Reject the request if the signatures do not match.
Always verify the signature. Do not process webhook payloads that fail signature verification.
import hmac
import hashlib

def verify_webhook(body: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(),
        body,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature)

Retry policy

If your endpoint does not return HTTP 200 within 5 seconds, Ratio retries with exponential backoff:
AttemptDelay
1st retry10 seconds
2nd retry30 seconds
3rd retry2 minutes
4th retry10 minutes
5th retry1 hour
After 5 failed attempts, the webhook is marked as failed. You can query settlement status directly via GET /v1/system/state as a fallback.

Best practices

  • Verify the signature on every incoming request before processing the payload.
  • Make your handler idempotent. The same event may be delivered more than once due to retries.
  • Return 200 immediately, then process the event asynchronously to avoid triggering retries from slow processing.
  • Log the execution_id from every settlement.confirmed event for reconciliation and support escalation.