Skip to main content

Relayer REST API

The Telos Privacy relayer is an intermediary between clients and the ZKTelosPool contract. It accepts transactions, builds the Merkle tree proof, and submits them on-chain. The relayer exposes a REST API you can use directly — useful if you're building a custom client without the SDK, or need low-level control.

Relayer URL

Contact the Telos Foundation or check the zkWallet source for the current production relayer URL.

Pool Addresses (Telos EVM, Chain ID: 40)

PoolContract (proxy)Token
WTLOS0xB5340818eE78D6221f631495346E2e55DA5BcA580xD102cE6A4dB07D247fcc28F366A623Df0938CA9E
USDC.e0xe47A4F0099cA16d61C678Dc75911F91e11deDAa30xF1815bd50389c46847f0Bda824eC8da914045D14

Send a Transaction

POST /transaction

Validates the transaction, builds the zkSNARK Merkle tree proof, and queues it for submission to the ZKTelosPool contract. Returns a jobId immediately — transactions are processed serially.

Request body:

FieldTypeRequiredDescription
proofObjectZK proof built by the client
memoStringMemo block, Base64-encoded
tx_typeInteger0 = deposit, 1 = transfer, 2 = withdrawal
depositSignatureStringNullifier signature with the caller's EVM private key (required for deposit transactions)

Response 201:

{
"jobId": "42"
}

Response 400:

{
"error": "Error while parsing the input JSON",
"description": "tx_type is incorrect"
}

Get Job Status

GET /job/:id

Poll the status of a submitted transaction by its jobId.

Response 200:

{
"state": "mined",
"txHash": "0xabc123..."
}

Possible state values:

StateDescription
waitingQueued, not yet processed
provingBuilding the Merkle proof
sentSubmitted to Telos EVM
minedConfirmed on-chain
failedTransaction failed

Response 404:

"Job 2 not found"

Query Transactions

GET /transactions/:limit/:offset

Fetch memo blocks and out-commits for a range of transactions. Used by clients to synchronize local account state with the pool.

ParamTypeDescription
limitIntegerNumber of transactions to return
offsetIntegerStarting index in the Merkle tree (must be a multiple of 128)

Response 200: Array of transaction buffers (or null for empty slots).


Get Merkle Tree Info

GET /info

Returns the current Merkle tree root and the next available index.

Response 200:

{
"root": "11469701942666298368112882412133877458305516134926649826543144744382391691533",
"deltaIndex": 128
}

Get Next Merkle Index

GET /delta_index

Returns the next available index in the Merkle tree as a plain integer.

Response 200:

128

Get Merkle Proof at Index

GET /merkle/proof?index=<n>

Returns the Merkle proof for a specific index. Used when building transaction proofs on the client side.

Response 200:

{
"root": "114697...",
"deltaIndex": 128,
"proofs": [...]
}

Response 404: "Incorrect index" — index doesn't exist yet.


Get Merkle Root at Index

GET /merkle/root/:index

Returns the historical Merkle tree root at a specific index. Useful for validating proofs against past pool states.

Response 200:

"11469701942666298368112882412133877458305516134926649826543144744382391691533"

Calculate Transaction Proof (Debug Only)

POST /proof_tx

Development Only

This endpoint exposes secret transaction inputs to the relayer — never use in production. It is intended for debugging and local development only.

Builds a zkSNARK proof server-side given public and secret inputs. Reduces client computation overhead during development.

Request body:

FieldTypeDescription
pubObjectPublic circuit inputs
secObjectSecret circuit inputs

Response 200:

{
"proof": { ... }
}

Error Format

All error responses follow this structure:

{
"error": "Human-readable error message",
"description": "Optional detail"
}

Example: Full Deposit Flow

// 1. Build transaction proof client-side (using zkbob-client-js or raw circuits)
const { proof, memo } = await buildDepositProof(amount, userAddress);

// 2. Sign the deposit
const depositSignature = await signer.signMessage(nullifierHash);

// 3. Submit to relayer
const response = await fetch('https://relayer.telos.net/transaction', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
proof,
memo: btoa(memo),
tx_type: 0,
depositSignature,
}),
});
const { jobId } = await response.json();

// 4. Poll for confirmation
let status;
do {
await new Promise(r => setTimeout(r, 2000));
const res = await fetch(`https://relayer.telos.net/job/${jobId}`);
status = await res.json();
} while (status.state === 'waiting' || status.state === 'proving' || status.state === 'sent');

console.log('Final status:', status.state, status.txHash);