Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.rhinestone.dev/llms.txt

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

There are two ways to track a deposit through the processing pipeline:
  • Polling — query the GET /deposits endpoint filtered by transaction hash. Simple and stateless.
  • Webhooks — receive push notifications as deposits move through each stage. Real-time and event-driven.
Use whichever fits your architecture. Many integrations combine both: webhooks for real-time updates, polling as a fallback or for on-demand status checks.

Polling

Query the GET /deposits endpoint with the txHash parameter to look up a deposit by its source transaction hash.
const DEPOSIT_SERVICE_URL =
    "https://v1.orchestrator.rhinestone.dev/deposit-processor";
const API_KEY = "YOUR_RHINESTONE_API_KEY";

const txHash = "0xabc123...";

const response = await fetch(
    `${DEPOSIT_SERVICE_URL}/deposits?txHash=${txHash}`,
    {
        headers: { "x-api-key": API_KEY },
    },
);

const { deposits } = await response.json();

Response

Each item in the deposits array has the following shape:
FieldTypeDescription
chainstringSource chain (CAIP-2)
txHashstringSource transaction hash
tokenstringDeposit token address
amountstringDeposit amount (raw token units)
senderstringSender address
accountstringRegistered account address
targetChainstringDestination chain (CAIP-2)
targetTokenstringDestination token address
statusstring"processing", "completed", or "failed"
sourceTxHashstring | nullBridge source transaction hash
destinationTxHashstring | nullBridge destination transaction hash
sourceAmountstring | nullBridge source amount
destinationAmountstring | nullBridge destination amount
errorCodestring | nullError code if the deposit failed
createdAtstringISO 8601 timestamp of when the deposit was detected
completedAtstring | nullISO 8601 timestamp of when the deposit completed

Polling loop

Poll until the deposit reaches a terminal status (completed or failed):
async function waitForDeposit(txHash: string): Promise<void> {
    const url = `${DEPOSIT_SERVICE_URL}/deposits?txHash=${txHash}`;
    const headers = { "x-api-key": API_KEY };

    while (true) {
        const response = await fetch(url, { headers });
        const { deposits } = await response.json();
        const deposit = deposits[0];

        if (!deposit) {
            // Deposit not yet indexed — wait and retry
            await new Promise((r) => setTimeout(r, 1_000));
            continue;
        }

        if (deposit.status === "completed") {
            console.log("Deposit completed:", deposit.destinationTxHash);
            return;
        }

        if (deposit.status === "failed") {
            console.error("Deposit failed:", deposit.errorCode);
            return;
        }

        // Still processing — poll again
        await new Promise((r) => setTimeout(r, 1_000));
    }
}
A 1-second interval works well for most use cases. Most deposits complete within seconds.

Webhooks

The deposit service sends webhook notifications to your configured endpoint as deposits move through the processing pipeline. All webhooks are POST requests with Content-Type: application/json. Configure your webhook URL and optional secret via the POST /setup endpoint.

Payload envelope

Every webhook request body follows the same envelope structure:
{
  "version": "1.0",
  "type": "<event-type>",
  "eventId": "12345",
  "time": "2025-01-15T12:00:00.000Z",
  "data": { ... }
}
FieldTypeDescription
versionstringProtocol version. Currently "1.0"
typestringEvent type identifier
eventIdstringStable identifier for this delivery. Use it as the canonical dedupe key
timestringISO 8601 timestamp of when the event was sent
testboolean | undefinedPresent and true only for events dispatched via the test endpoint
dataobjectEvent-specific payload (see below)

Event types

TypeTrigger
deposit-receivedToken transfer detected on a registered account
bridge-startedBridging intent created and submitted to the Orchestrator
bridge-completeTokens arrived on the target chain
bridge-delayedBridge provider did not fill within the expected window; a refund is expected
bridge-failedBridging failed
post-bridge-swap-completePost-bridge token swap completed
post-bridge-swap-failedPost-bridge token swap failed
deposit-refundedDeposit funds returned to a recipient on the source chain

deposit-received

Sent when an incoming token transfer is detected on a registered account.
FieldTypeDescription
chainstringSource chain (CAIP-2, e.g. "eip155:8453")
tokenstringToken address
amountstringDeposit amount in raw token units
accountstringAccount address
transactionHashstringDeposit transaction hash
senderstringSender address
{
    "version": "1.0",
    "type": "deposit-received",
    "eventId": "12345",
    "time": "2025-01-15T12:00:00.000Z",
    "data": {
        "chain": "eip155:8453",
        "token": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
        "amount": "1000000",
        "account": "0x1234567890abcdef1234567890abcdef12345678",
        "transactionHash": "0xabc123...",
        "sender": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
    }
}

bridge-started

Sent when a bridging intent is created and submitted to the Orchestrator.
FieldTypeDescription
source.chainstringSource chain (CAIP-2)
source.assetstringSource asset address
source.amountstringSource amount
destination.chainstringDestination chain (CAIP-2)
destination.assetstringDestination asset address
destination.amountstringDestination amount
accountstringAccount address
deposit.transactionHashstringOriginal deposit transaction hash
deposit.chainstringDeposit chain (CAIP-2)
deposit.assetstringDeposit asset address
deposit.amountstringDeposit amount
deposit.senderstringSender address
settlementLayerstringSettlement layer used (e.g. "layerzero")
estimatedFillTime.secondsnumber | undefinedEstimated time to fill, in seconds, when the route provides one

bridge-complete

Sent when tokens have arrived on the target chain.
FieldTypeDescription
deposit.transactionHashstringOriginal deposit transaction hash
deposit.chainstringDeposit chain (CAIP-2)
deposit.assetstringDeposit asset address
deposit.amountstringDeposit amount
deposit.senderstringSender address
source.transactionHashstringSource chain claim transaction hash
source.chainstringSource chain (CAIP-2)
source.amountstringSource amount
source.assetstringSource asset address
destination.transactionHashstringDestination chain transaction hash
destination.chainstringDestination chain (CAIP-2)
destination.amountstringDestination amount
destination.assetstringDestination asset address
accountstringAccount address
settlementLayerstring | undefinedSettlement layer used
{
    "version": "1.0",
    "type": "bridge-complete",
    "eventId": "12346",
    "time": "2025-01-15T12:01:30.000Z",
    "data": {
        "deposit": {
            "transactionHash": "0xabc123...",
            "chain": "eip155:8453",
            "asset": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
            "amount": "1000000",
            "sender": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
        },
        "source": {
            "transactionHash": "0xdef456...",
            "chain": "eip155:8453",
            "amount": "1000000",
            "asset": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"
        },
        "destination": {
            "transactionHash": "0x789ghi...",
            "chain": "eip155:42161",
            "amount": "990000",
            "asset": "0xaf88d065e77c8cc2239327c5edb3a432268e5831"
        },
        "account": "0x1234567890abcdef1234567890abcdef12345678"
    }
}

bridge-delayed

Sent when the bridge provider has not filled the intent within the expected window. A refund is expected on the source chain; the subsequent deposit-refunded event confirms the funds returned.
FieldTypeDescription
reasonstringHuman-readable explanation of the delay
estimatedDelayTime.secondsnumber | undefinedAdditional time the refund is expected to take, when available
accountstringAccount address
deposit.transactionHashstringDeposit transaction hash
deposit.chainstringDeposit chain (CAIP-2)
deposit.tokenstringDeposit token address
deposit.amountstringDeposit amount
deposit.senderstringSender address

bridge-failed

Sent when a bridging operation fails. See error codes for the full list and retry behavior.
FieldTypeDescription
errorCodestringError code (e.g. "BRIDGE-1")
accountstringAccount address
messagestring | undefinedHuman-readable error description
deposit.transactionHashstringDeposit transaction hash
deposit.chainstringDeposit chain (CAIP-2)
deposit.tokenstringDeposit token address
deposit.amountstringDeposit amount
deposit.senderstringSender address

post-bridge-swap-complete

Sent when a post-bridge token swap completes successfully. This occurs when the account has token routing rules configured that require a swap after bridging.
FieldTypeDescription
deposit.transactionHashstringOriginal deposit transaction hash
deposit.chainstringDeposit chain (CAIP-2)
deposit.assetstringDeposit asset address
deposit.amountstringDeposit amount
deposit.senderstringSender address
swap.transactionHashstringSwap transaction hash
swap.chainstringChain where the swap executed (CAIP-2)
swap.tokenInstringInput token address
swap.tokenOutstringOutput token address
swap.amountstringOutput amount
swap.recipientstringRecipient address
bridge.transactionHashstring | undefinedBridge transaction hash
bridge.chainstring | undefinedBridge chain (CAIP-2)
bridge.assetstring | undefinedBridge asset address
bridge.amountstring | undefinedBridge amount
accountstringAccount address

post-bridge-swap-failed

Sent when a post-bridge token swap fails.
FieldTypeDescription
errorCodestringError code (e.g. "SWAP-1")
messagestring | undefinedHuman-readable error description
accountstringAccount address
deposit.transactionHashstringOriginal deposit transaction hash
deposit.chainstringDeposit chain (CAIP-2)
deposit.assetstringDeposit asset address
deposit.amountstringDeposit amount
deposit.senderstringSender address
swap.chainstringChain where the swap was attempted (CAIP-2)
swap.tokenInstringInput token address
swap.tokenOutstringOutput token address
swap.amountstringAttempted swap amount
swap.recipientstringIntended recipient address
swap.bridgeTransactionHashstring | undefinedBridge transaction hash

deposit-refunded

Sent when funds from a deposit are returned to a recipient on the source chain. Typically follows a bridge-delayed event.
FieldTypeDescription
accountstringAccount address
deposit.transactionHashstringOriginal deposit transaction hash
deposit.chainstringDeposit chain (CAIP-2)
deposit.assetstringDeposit asset address
deposit.amountstringDeposit amount
deposit.senderstringSender address
refund.transactionHashstringRefund transaction hash
refund.chainstringRefund chain (CAIP-2)
refund.assetstringRefund asset address
refund.amountstringRefund amount
refund.recipientstringAddress that received the refund

Signature verification

If you provided a webhookSecret during setup, every webhook request includes an X-Webhook-Signature header:
X-Webhook-Signature: sha256=<hex-encoded-signature>
The signature is an HMAC-SHA256 hash computed over the raw JSON request body using your secret. To verify:
  1. Read the raw request body as a string (before JSON parsing)
  2. Compute the HMAC-SHA256 of the raw body using your webhook secret
  3. Compare the result with the value in the X-Webhook-Signature header (strip the sha256= prefix)
  4. Use a constant-time comparison to prevent timing attacks
import { createHmac, timingSafeEqual } from "node:crypto";

function verifyWebhookSignature(
    rawBody: string,
    signatureHeader: string,
    secret: string,
): boolean {
    const expected =
        "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex");
    return (
        signatureHeader.length === expected.length &&
        timingSafeEqual(Buffer.from(signatureHeader), Buffer.from(expected))
    );
}
Always verify against the raw request body string, not a re-serialized version of the parsed JSON. Re-serialization may change key order or whitespace, which will produce a different signature.

Delivery behavior

  • Retries — failed deliveries are retried multiple times before the event is marked failed. Events that exhaust their retries can still be replayed on demand via POST /webhooks/events/{id}/resend, which reuses the original eventId.
  • Ordering — events for a single deposit are sent in lifecycle order (deposit-receivedbridge-startedbridge-complete), but there is no global ordering guarantee across deposits.
  • URL validation — the webhook URL must use HTTPS and must not target internal or private network addresses.
  • Idempotency — use eventId from the envelope as the canonical dedupe key.

Backfilling missed events

If your receiver was offline or rejected events, replay them through the events API. Every dispatched webhook is persisted regardless of delivery outcome. List events delivered (or attempted) to your URL, newest first:
const response = await fetch(
    `${DEPOSIT_SERVICE_URL}/webhooks/events?since=2025-01-15T00:00:00Z`,
    { headers: { "x-api-key": API_KEY } },
);
const { events, nextCursor } = await response.json();
Re-send a stored event to your URL — the original eventId is reused so dedupe still holds:
await fetch(`${DEPOSIT_SERVICE_URL}/webhooks/events/${eventId}/resend`, {
    method: "POST",
    headers: { "x-api-key": API_KEY },
});
For more details, see the API reference for GET /webhooks/events and POST /webhooks/events/{id}/resend.

Conventions

  • EVM addresses and token addresses are lowercase. Non-EVM addresses (Solana, Tron) preserve their original case.
  • All amounts are strings (raw token units, not human-readable).
  • Chains use CAIP-2 identifiers (e.g. "eip155:8453" for Base).