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:
| Field | Type | Description |
|---|
chain | string | Source chain (CAIP-2) |
txHash | string | Source transaction hash |
token | string | Deposit token address |
amount | string | Deposit amount (raw token units) |
sender | string | Sender address |
account | string | Registered account address |
targetChain | string | Destination chain (CAIP-2) |
targetToken | string | Destination token address |
status | string | "processing", "completed", or "failed" |
sourceTxHash | string | null | Bridge source transaction hash |
destinationTxHash | string | null | Bridge destination transaction hash |
sourceAmount | string | null | Bridge source amount |
destinationAmount | string | null | Bridge destination amount |
errorCode | string | null | Error code if the deposit failed |
createdAt | string | ISO 8601 timestamp of when the deposit was detected |
completedAt | string | null | ISO 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": { ... }
}
| Field | Type | Description |
|---|
version | string | Protocol version. Currently "1.0" |
type | string | Event type identifier |
eventId | string | Stable identifier for this delivery. Use it as the canonical dedupe key |
time | string | ISO 8601 timestamp of when the event was sent |
test | boolean | undefined | Present and true only for events dispatched via the test endpoint |
data | object | Event-specific payload (see below) |
Event types
| Type | Trigger |
|---|
deposit-received | Token transfer detected on a registered account |
bridge-started | Bridging intent created and submitted to the Orchestrator |
bridge-complete | Tokens arrived on the target chain |
bridge-delayed | Bridge provider did not fill within the expected window; a refund is expected |
bridge-failed | Bridging failed |
post-bridge-swap-complete | Post-bridge token swap completed |
post-bridge-swap-failed | Post-bridge token swap failed |
deposit-refunded | Deposit funds returned to a recipient on the source chain |
deposit-received
Sent when an incoming token transfer is detected on a registered account.
| Field | Type | Description |
|---|
chain | string | Source chain (CAIP-2, e.g. "eip155:8453") |
token | string | Token address |
amount | string | Deposit amount in raw token units |
account | string | Account address |
transactionHash | string | Deposit transaction hash |
sender | string | Sender 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.
| Field | Type | Description |
|---|
source.chain | string | Source chain (CAIP-2) |
source.asset | string | Source asset address |
source.amount | string | Source amount |
destination.chain | string | Destination chain (CAIP-2) |
destination.asset | string | Destination asset address |
destination.amount | string | Destination amount |
account | string | Account address |
deposit.transactionHash | string | Original deposit transaction hash |
deposit.chain | string | Deposit chain (CAIP-2) |
deposit.asset | string | Deposit asset address |
deposit.amount | string | Deposit amount |
deposit.sender | string | Sender address |
settlementLayer | string | Settlement layer used (e.g. "layerzero") |
estimatedFillTime.seconds | number | undefined | Estimated time to fill, in seconds, when the route provides one |
bridge-complete
Sent when tokens have arrived on the target chain.
| Field | Type | Description |
|---|
deposit.transactionHash | string | Original deposit transaction hash |
deposit.chain | string | Deposit chain (CAIP-2) |
deposit.asset | string | Deposit asset address |
deposit.amount | string | Deposit amount |
deposit.sender | string | Sender address |
source.transactionHash | string | Source chain claim transaction hash |
source.chain | string | Source chain (CAIP-2) |
source.amount | string | Source amount |
source.asset | string | Source asset address |
destination.transactionHash | string | Destination chain transaction hash |
destination.chain | string | Destination chain (CAIP-2) |
destination.amount | string | Destination amount |
destination.asset | string | Destination asset address |
account | string | Account address |
settlementLayer | string | undefined | Settlement 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.
| Field | Type | Description |
|---|
reason | string | Human-readable explanation of the delay |
estimatedDelayTime.seconds | number | undefined | Additional time the refund is expected to take, when available |
account | string | Account address |
deposit.transactionHash | string | Deposit transaction hash |
deposit.chain | string | Deposit chain (CAIP-2) |
deposit.token | string | Deposit token address |
deposit.amount | string | Deposit amount |
deposit.sender | string | Sender address |
bridge-failed
Sent when a bridging operation fails. See error codes for the full list and retry behavior.
| Field | Type | Description |
|---|
errorCode | string | Error code (e.g. "BRIDGE-1") |
account | string | Account address |
message | string | undefined | Human-readable error description |
deposit.transactionHash | string | Deposit transaction hash |
deposit.chain | string | Deposit chain (CAIP-2) |
deposit.token | string | Deposit token address |
deposit.amount | string | Deposit amount |
deposit.sender | string | Sender 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.
| Field | Type | Description |
|---|
deposit.transactionHash | string | Original deposit transaction hash |
deposit.chain | string | Deposit chain (CAIP-2) |
deposit.asset | string | Deposit asset address |
deposit.amount | string | Deposit amount |
deposit.sender | string | Sender address |
swap.transactionHash | string | Swap transaction hash |
swap.chain | string | Chain where the swap executed (CAIP-2) |
swap.tokenIn | string | Input token address |
swap.tokenOut | string | Output token address |
swap.amount | string | Output amount |
swap.recipient | string | Recipient address |
bridge.transactionHash | string | undefined | Bridge transaction hash |
bridge.chain | string | undefined | Bridge chain (CAIP-2) |
bridge.asset | string | undefined | Bridge asset address |
bridge.amount | string | undefined | Bridge amount |
account | string | Account address |
post-bridge-swap-failed
Sent when a post-bridge token swap fails.
| Field | Type | Description |
|---|
errorCode | string | Error code (e.g. "SWAP-1") |
message | string | undefined | Human-readable error description |
account | string | Account address |
deposit.transactionHash | string | Original deposit transaction hash |
deposit.chain | string | Deposit chain (CAIP-2) |
deposit.asset | string | Deposit asset address |
deposit.amount | string | Deposit amount |
deposit.sender | string | Sender address |
swap.chain | string | Chain where the swap was attempted (CAIP-2) |
swap.tokenIn | string | Input token address |
swap.tokenOut | string | Output token address |
swap.amount | string | Attempted swap amount |
swap.recipient | string | Intended recipient address |
swap.bridgeTransactionHash | string | undefined | Bridge 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.
| Field | Type | Description |
|---|
account | string | Account address |
deposit.transactionHash | string | Original deposit transaction hash |
deposit.chain | string | Deposit chain (CAIP-2) |
deposit.asset | string | Deposit asset address |
deposit.amount | string | Deposit amount |
deposit.sender | string | Sender address |
refund.transactionHash | string | Refund transaction hash |
refund.chain | string | Refund chain (CAIP-2) |
refund.asset | string | Refund asset address |
refund.amount | string | Refund amount |
refund.recipient | string | Address 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:
- Read the raw request body as a string (before JSON parsing)
- Compute the HMAC-SHA256 of the raw body using your webhook secret
- Compare the result with the value in the
X-Webhook-Signature header (strip the sha256= prefix)
- 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-received → bridge-started → bridge-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).