Skip to main content
The relayer exposes a Gin HTTP server. Every endpoint listed here is implemented and live on testnet today. The SDK pages map each documented SDK call to one of these endpoints.
Base URL: https://relayer.tachyon.pe. Testnet and mainnet share the same host; select the network via the chain IDs you pass in each request.
Authentication: no API key required. Endpoints are rate-limited at the platform level (see rate limits). Signature-protected endpoints (recipient flows, settle) validate per-request signatures as documented on each endpoint.

Conventions

  • All bodies are JSON unless noted.
  • Successful responses include "success": true. Failures include "success": false and "error": "...".
  • Signature-protected endpoints take an EIP-191 / EIP-712 signature as a JSON field. Each endpoint documents the exact message that’s signed.
  • Address fields are 0x-prefixed hex (checksummed where the contract requires).
  • Amount fields are decimal strings (in token base units).

Public read endpoints

GET /health

Liveness check. Returns relayer status, configured networks, and chain info. 200 response:
{
  "status": "healthy",
  "service": "bridge-relayer",
  "timestamp": "2026-04-17T10:23:54Z",
  "networks": ["horizen_mainnet", "base_mainnet"],
  "chainInfo": {
    "horizen_mainnet": "26514",
    "base_mainnet": "8453"
  }
}

GET /ecies-pubkey

Returns the relayer’s ECIES public key. Senders use this to encrypt recipient details (so only the relayer can decrypt them) before calling POST /store-recipients. 200 response:
{
  "success": true,
  "publicKey": "04abc...",
  "message": "Use this public key to encrypt recipient information"
}

GET /get-recipients/:intentId

Returns recipient information for an intent. Only the winning solver can fetch these, the call requires an X-Solver-Address header that matches the intent’s winner on the source chain. Headers:
  • X-Solver-Address (required), solver’s EOA
Query:
  • sourceChainId (optional), disambiguator if the same intent ID exists across chains
200 response:
{
  "success": true,
  "intentId": "...",
  "recipients": ["0x...", "0x..."],
  "amounts": ["1000000", "2000000"],
  "timestamp": 1745000000,
  "chainId": 8453,
  "totalAmount": "3000000"
}
Errors: 403 if requester isn’t the winner; 404 if intent unknown or not yet deposited.

GET /intent-details/:intentId

Returns lifecycle data for an intent: deposit / solve / settle tx hashes, status, timestamps. 200 response:
{
  "success": true,
  "intent": {
    "intentId": "...",
    "sourceChainId": "26514",
    "destChainId": "8453",
    "solverAddress": "0x...",
    "depositTxHash": "0x...",
    "solveTxHash": "0x...",
    "settleTxHash": "0x...",
    "status": "completed",
    "timestamp": "2026-04-17T10:23:54Z",
    "settledAt": "2026-04-17T10:24:03Z"
  }
}
statuspending, solving, settled, completed.

POST /verify

Checks whether an intent has been solved on its destination chain. Body:
{
  "intentId": "...",
  "network": "base_mainnet",
  "sourceChainId": "26514"
}
200 response:
{
  "success": true,
  "intentId": "...",
  "network": "base_mainnet",
  "solved": true
}

POST /get-routes and GET /get-routes

Returns supported chain pairs and registered solvers per pair. Filter by any combination of source chain, destination chain, source token, destination token. POST body / GET query:
{
  "sourceChain": "horizen_mainnet",
  "destChain":   "base_mainnet",
  "tokenA":      "0x...",
  "tokenB":      "0x..."
}
GET accepts origin/originAsset as aliases for sourceChain/tokenA. 200 response:
{
  "success": true,
  "routes": [{ "sourceChain": "horizen_mainnet", "destChain": "base_mainnet", "tokenA": "0x...", "tokenB": "0x..." }],
  "solvers": [{ "address": "0x...", "routes": [...], "balances": [...], "registeredAt": "...", "lastSeen": "..." }]
}

Sender / solver write endpoints

POST /store-recipients

Sender stores encrypted recipient + amount data against an intent. The relayer decrypts inside its trusted environment; only the winning solver can later fetch via GET /get-recipients/:intentId. Body (preferred, encrypted):
{
  "intentId": "...",
  "chainId": 8453,
  "encryptedData": "0x..."
}
encryptedData is hex-encoded ECIES ciphertext over the JSON {"recipients": ["0x...", ...], "amounts": ["1000000", ...]} using the relayer’s ECIES public key (from GET /ecies-pubkey). Legacy (plaintext, deprecated):
{
  "intentId": "...",
  "chainId": 8453,
  "recipients": ["0x..."],
  "amounts":    ["1000000"]
}
200 response:
{
  "success": true,
  "intentId": "...",
  "message": "Recipients stored successfully"
}

POST /settle

Solver (or relayer) calls this after the destination-chain transaction has confirmed. The relayer verifies fulfillment and triggers settlement on the source chain. Body:
{
  "intentId": "...",
  "network": "base_mainnet",
  "chain2IntentId": "...",
  "solverAddress": "0x...",
  "destinationChain": "base_mainnet",
  "depositTxHash": "0x...",
  "solveTxHash":   "0x..."
}
200 response:
{
  "success": true,
  "settleTxHash": "0x...",
  "depositTxHash": "0x...",
  "solveTxHash":   "0x...",
  "blockNumber": 123456,
  "network": "horizen_mainnet",
  "chainId": 26514,
  "intentId": "...",
  "chain2IntentId": "...",
  "solverAddress": "0x..."
}

POST /register-solver

A solver announces itself and the routes it can fill. Body:
{
  "solverAddress": "0x...",
  "routes": [
    { "sourceChain": "horizen_mainnet", "destChain": "base_mainnet", "tokenA": "0x...", "tokenB": "0x..." }
  ]
}
200 response:
{
  "success": true,
  "solverAddress": "0x...",
  "routesCount": 1,
  "balances": [{ "chain": "base_mainnet", "token": "0x...", "balance": "1000000000" }]
}

Recipient (stealth-address) endpoints

POST /recipient/register

Recipient onboards: provides their EOA + signature; the relayer generates and stores their viewing/spending key pair (keys never leave the relayer’s trusted environment) and returns the public components. Body:
{
  "recipientAddress": "0x...",
  "signature": "0x..."
}
The signature must cover the message REGISTER_STEALTH:<address>. 200 response:
{
  "success": true,
  "spendPubKey": "04...",
  "viewPubKey":  "04...",
  "stealthAddresses": []
}
Calling again with the same address returns the existing keys (no new generation).

GET /recipient/addresses

Lists all stealth addresses for a recipient. Signature-protected. Query:
  • address (required), recipient EOA
  • signature (required), same EIP-191 signature as registration
200 response:
{
  "success": true,
  "stealthAddresses": [
    {
      "address": "0xStealth1...",
      "ephemeralPubKey": "04...",
      "chainId": "8453",
      "intentId": "...",
      "safeDeployed": true,
      "safeAddress": "0xSafe...",
      "createdAt": 1745000000
    }
  ]
}

POST /recipient/generate-stealth

Internal endpoint used by senders/relayer to derive a fresh stealth address for a given recipient + intent. Returns both the stealth EOA and its predicted Safe address. Body:
{
  "recipientAddress": "0x...",
  "chainId": "8453",
  "intentId": "..."
}
200 response:
{
  "success": true,
  "stealthAddress": "0xStealth...",
  "safeAddress":   "0xSafe..."
}

POST /recipient/derive-stealth-key

Returns the stealth private key for a specific stealth address. Only callable by the recipient who owns it (signature required). Body:
{
  "recipientAddress": "0x...",
  "stealthAddress":   "0xStealth...",
  "signature": "0x..."
}
The signature must cover DERIVE_STEALTH_KEY:<recipientAddress>:<stealthAddress>. 200 response:
{
  "success": true,
  "stealthAddress": "0xStealth...",
  "stealthPrivateKey": "abcd1234..."
}
The stealth private key controls the funds at the stealth address. Never log it; persist only client-side, encrypted at rest.

POST /recipient/deploy-safe

Deploys a Safe at the stealth address (the predicted address from generate-stealth). Anyone can broadcast it, but the request must include a signature from the recipient’s spend private key. Body:
{
  "stealthAddress": "0xStealth...",
  "signature": "0x...",
  "chainId":   "8453"
}
The signature must cover DEPLOY_SAFE:<stealthAddress>:<chainId>. 200 response:
{
  "success": true,
  "safeAddress": "0xSafe...",
  "txHash": "0x..."
}

POST /recipient/relay-proxy

Broadcasts a pre-signed Safe transaction on the recipient’s behalf. The recipient derives the stealth key, signs the Safe tx hash locally, and sends the signature here; the relayer pays gas and calls execTransaction on the Safe. Body:
{
  "safeAddress": "0xSafe...",
  "chainId":     "8453",
  "to":          "0xTarget...",
  "value":       "0",
  "data":        "0x...",
  "operation":   0,
  "signature":   "0x..."
}
operation is 0 for Call, 1 for DelegateCall. signature is the 65-byte sig from the stealth key over the Safe tx hash. 200 response:
{
  "success": true,
  "txHash": "0x..."
}
This is the gasless sweep / spend path for stealth balances.

Admin endpoints (auth required)

These require the admin auth middleware and are not intended for integrators.
MethodPathPurpose
GET/list-stored-intentsDump all stored recipient bundles
DELETE/delete-recipients/:intentIdRemove a stored recipient bundle

Solver service endpoints

The solver runs its own HTTP service alongside the relayer. These are intended for solver operators, not integrators. Documented for completeness.
MethodPathPurpose
GET/healthSolver liveness
GET/statusDetailed solver status (running, networks, balances, active intents)
GET/active-intentsIntents the solver is currently bidding on
GET/intent-status/:intentIdStatus of a specific intent (across networks)
GET/intent-status/:intentId/:networkStatus on a specific network
POST/startStart the solver (admin)
POST/stopStop the solver (admin)

Webhooks

WIP. Webhook delivery for intent state transitions is on the roadmap. Until it ships, integrators should poll GET /intent-details/:intentId (typically every 2–5 seconds while an intent is live).

On-chain contract surface

The relayer is a façade over the on-chain BridgeIntentV2 contract. For low-level integrations that interact with the contract directly:
ChainBridge contractUSDC
Horizen Mainnet (chainId 26514)0x1809703DE921177cca0f1c80FB58D788E09AdDB40x52F77B624a9f20d41a60eF550e5792a00747262c
Base Mainnet (chainId 8453)0x52F77B624a9f20d41a60eF550e5792a00747262c0xfaAd7d5c3286B142d7854F75c9B0ad3F6A803F03
See supported chains for source chains reached via Near Intents and Relay.

SDK overview

How the WIP SDK maps onto these endpoints.