API Reference
Download OpenAPI Spec
Authentication
The API accepts two types of Bearer tokens:
- JWT — Obtain one instantly by completing the Sign-In with Ethereum (SIWE) flow below (GET /nonce → POST /verify). JWTs are short-lived session tokens.
- API Key — Long-lived platform keys for server-to-server integrations. Contact us at support@clkd.xyz to request one.
Pass either token in the Authorization header — the server auto-detects the format.
Important: The address used for authentication must be the address derived from your private spending key (privateKeyToAccount(p_spend)), NOT your connected wallet address. The server identity is this derived auth address — your wallet address never touches the server.
Endpoints marked with 🔒 require a valid Bearer token.
Get HPKE public key
/v1/.well-known/hpke-public-keyRetrieve the server's HPKE public key. Clients must encrypt stealth key material with this key before submitting it during account creation or signer enrollment.
200Default Response
{
"publicKey": "0x...",
"publicKeyBase64": "...",
"format": "hex",
"kem": "X25519-HKDF-SHA256",
"aead": "AES-128-GCM"
}Try it
curl -X GET \
"https://api-stg.clkd.xyz/v1/.well-known/hpke-public-key"Get nonce
/v1/nonceGenerate a one-time nonce tied to the given address. This is the first step of Sign-In with Ethereum (SIWE) — the nonce must be included in the SIWE message passed to verifySignin. Nonces expire after 5 minutes.
| Name | In | Type | Description |
|---|---|---|---|
address* | query | string | The auth address to tie the nonce to. This must be the address derived from your private spending key (i.e. `privateKeyToAccount(p_spend).address`), not your connected wallet address. |
200Random nonce string
"a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"400Default Response
{
"error": "Bad request",
"message": "string",
"code": "BAD_REQUEST",
"available": "0",
"minAmount": "0.00036 ETH",
"maxSendable": "0.018 ETH"
}429Default Response
{
"error": "Too Many Requests",
"message": "Rate limit exceeded. Maximum 20 requests per 1 minute."
}Try it
addresscurl -X GET \
"https://api-stg.clkd.xyz/v1/nonce"Verify sign-in
/v1/verifyComplete Sign-In with Ethereum by submitting the signed SIWE message. Returns a JWT session token and the associated accountId if the address already has an account, or null if the user still needs to register.
200Default Response
{
"ok": true,
"address": "0x...",
"token": "string",
"accountId": "string"
}400Default Response
{
"error": "Bad request",
"message": "string",
"code": "BAD_REQUEST",
"available": "0",
"minAmount": "0.00036 ETH",
"maxSendable": "0.018 ETH"
}422Default Response
{
"error": "Unprocessable Entity",
"message": "string",
"code": "UNPROCESSABLE_ENTITY"
}429Default Response
{
"error": "Too Many Requests",
"message": "Rate limit exceeded. Maximum 10 requests per 1 minute."
}Try it
curl -X POST \
-H "Content-Type: application/json" \
-d '{
"message": "",
"signature": ""
}' \
"https://api-stg.clkd.xyz/v1/verify"Logout
/v1/logoutClear the server-side cache for the authenticated user. JWT tokens are stateless, so the client should also discard the token. Auth is optional — unauthenticated calls succeed without clearing any cache.
200Default Response
{
"ok": true
}Try it
curl -X POST \
"https://api-stg.clkd.xyz/v1/logout"Account Management
Account creation, signers, subdomains, and setup
Check subdomain availability
/v1/subdomain/checkCheck whether a subdomain name is available for registration. Public endpoint — no authentication required. Use before calling setSubdomain to avoid conflicts.
| Name | In | Type | Description |
|---|---|---|---|
name* | query | string | — |
inviteCode | query | string | — |
200Default Response
{
"available": true,
"reason": "string"
}400Default Response
{
"error": "Bad request",
"message": "string",
"code": "BAD_REQUEST",
"available": "0",
"minAmount": "0.00036 ETH",
"maxSendable": "0.018 ETH"
}Try it
nameinviteCodecurl -X GET \
"https://api-stg.clkd.xyz/v1/subdomain/check"Create account
/v1/accounts/🔒Register a new account by submitting HPKE-encrypted key material. The caller must already have a JWT from the SIWE sign-in flow, which proves ownership of the Ethereum address. The server decrypts and stores the keys, enabling payment address generation for this account. Requires an invite code when gated access is enabled. Returns the new accountId, or indicates if the address already has an account.
201Default Response
{
"accountId": "string",
"alreadyExisted": true
}Try it
curl -X POST \
-H "Content-Type: application/json" \
-d '{
"ciphertext": "",
"encapsulatedKey": "",
"inviteCode": ""
}' \
"https://api-stg.clkd.xyz/v1/accounts/"Get account
/v1/accounts/{accountId}🔒Retrieve account metadata including the owner address, registration status, and ENS subdomain. Useful for determining onboarding state (e.g., whether the user still needs to claim a subdomain).
| Name | In | Type | Description |
|---|---|---|---|
accountId* | path | string (uuid) | Account ID |
200Default Response
{
"accountId": "string",
"address": "string",
"isRegistered": true,
"subdomain": "string",
"lastConsumedNonce": 0,
"cloakie": {
"active": true,
"deposits": [
{
"tokenId": "string",
"imageUrl": "string",
"depositAddress": "string"
}
]
},
"hasPoolDeposits": true
}Try it
accountIdcurl -X GET \
"https://api-stg.clkd.xyz/v1/accounts/{accountId}"Get funded addresses
/v1/accounts/{accountId}/funded-addresses🔒List stealth addresses with non-zero balances, enriched with token metadata and dApp usage history.
| Name | In | Type | Description |
|---|---|---|---|
accountId* | path | string (uuid) | Account ID |
200Default Response
{
"addresses": [
{
"address": "string",
"nonce": "string",
"usedOrigins": [
"string"
],
"balances": [
{
"chainId": 0,
"chainName": "string",
"token": "string",
"tokenSymbol": "string",
"decimals": 0,
"logoUrl": "string",
"amount": "string",
"usdAmount": 0,
"pricePerToken": 0
}
]
}
]
}Try it
accountIdcurl -X GET \
"https://api-stg.clkd.xyz/v1/accounts/{accountId}/funded-addresses"Claim subdomain
/v1/accounts/{accountId}/subdomain🔒Claim an ENS subdomain (e.g. alice.clkd.eth) for this account so senders can pay via a human-readable name instead of a raw address. Each account may claim one subdomain.
| Name | In | Type | Description |
|---|---|---|---|
accountId* | path | string (uuid) | Account ID |
200Default Response
{
"success": true,
"message": "string",
"subdomain": "string"
}Try it
accountIdcurl -X POST \
-H "Content-Type: application/json" \
-d '{
"subdomain": ""
}' \
"https://api-stg.clkd.xyz/v1/accounts/{accountId}/subdomain"Generate subdomain
/v1/accounts/{accountId}/subdomain/generate🔒Generate a random available subdomain for the user to preview during onboarding. The name is not reserved — call setSubdomain to claim it.
| Name | In | Type | Description |
|---|---|---|---|
accountId* | path | string (uuid) | Account ID |
200Default Response
{
"subdomain": "example-123.clkd.eth"
}Try it
accountIdcurl -X GET \
"https://api-stg.clkd.xyz/v1/accounts/{accountId}/subdomain/generate"Receive
Payment address generation and ENS resolution
Create payment address
/v1/accounts/{accountId}/payment-address🔒Derive a one-time payment address so a sender can transfer tokens to this account without revealing the recipient on-chain.
| Name | In | Type | Description |
|---|---|---|---|
accountId* | path | string (uuid) | Account ID |
idempotency-key | header | string | Client-generated unique key (e.g. UUID). If the server has already processed a request with this key for the same account and body, it returns the cached response instead of re-executing. Keys expire after 24 hours. |
201Default Response
{
"address": "string",
"nonce": "string"
}Try it
accountIdidempotency-keycurl -X POST \
-H "Content-Type: application/json" \
-d '{}' \
"https://api-stg.clkd.xyz/v1/accounts/{accountId}/payment-address"Balance & Activity
Balance queries, transaction history, and supported tokens
List supported chains
/v1/supported-chainsList every chain the platform supports, including explorer URLs, logo base names, and testnet/mainnet mapping. Use to populate chain pickers or build explorer links.
200Default Response
[
{
"name": "string",
"chainId": 0,
"isTestnet": true,
"explorerUrl": "string",
"explorerTxPath": "string",
"mainnetChainId": 0,
"logoBaseName": "string",
"isSquareLogo": true
}
]Try it
curl -X GET \
"https://api-stg.clkd.xyz/v1/supported-chains"Get token catalog
/v1/token-catalogReturn the full curated token list (Uniswap default list + native ETH + testnet extras), pinned symbols for the swap picker, and testnet-to-mainnet chain-ID mapping.
200Default Response
{
"tokens": [
{
"address": "string",
"symbol": "string",
"name": "string",
"decimals": 0,
"chainId": 0,
"logoURI": "string",
"isClanker": true
}
],
"pinnedSymbols": [
"string"
],
"testnetToMainnet": null
}Try it
curl -X GET \
"https://api-stg.clkd.xyz/v1/token-catalog"Lookup token
/v1/token-lookupLook up token metadata by contract address. Checks cached sources first, then queries the Clanker API and on-chain ERC-20 metadata.
| Name | In | Type | Description |
|---|---|---|---|
address* | query | string | — |
chainId* | query | number | — |
200Default Response
{
"address": "string",
"symbol": "string",
"name": "string",
"decimals": 0,
"chainId": 0,
"logoURI": "string",
"isClanker": true
}400Default Response
{
"error": "Bad request",
"message": "string",
"code": "BAD_REQUEST",
"available": "0",
"minAmount": "0.00036 ETH",
"maxSendable": "0.018 ETH"
}404Default Response
{
"error": "Not found",
"message": "string"
}Try it
addresschainIdcurl -X GET \
"https://api-stg.clkd.xyz/v1/token-lookup"Get balances
/v1/accounts/{accountId}/balance🔒Retrieve token balances across every supported chain for this account. Each balance contains visible (standard on-chain) available and pending amounts. Returns a totalUsdAmount summarizing all holdings.
| Name | In | Type | Description |
|---|---|---|---|
accountId* | path | string (uuid) | Account ID |
200Default Response
{
"balances": [
{
"chainId": 8453,
"chainName": "Base",
"token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"tokenSymbol": "USDC",
"decimals": 6,
"logoUrl": "https://assets.coingecko.com/coins/images/6319/small/usdc.png",
"visible": {
"available": "1000000",
"pending": "500000"
},
"incognito": {
"pooled": {
"available": "750000",
"pendingApproval": "250000",
"declined": "0"
}
},
"usdAmount": 1.5,
"pricePerToken": 2000.42,
"priceStale": false,
"spam": false
}
],
"totalUsdAmount": 1.5
}401Default Response
{
"error": "Unauthorized",
"message": "string",
"code": "UNAUTHORIZED"
}404Default Response
{
"error": "Not found",
"message": "string"
}429Default Response
{
"error": "Too Many Requests",
"message": "Rate limit exceeded. Maximum 60 requests per 1 minute."
}Try it
accountIdcurl -X GET \
"https://api-stg.clkd.xyz/v1/accounts/{accountId}/balance"Get chain balances
/v1/accounts/{accountId}/balance/{chainId}🔒Retrieve token balances filtered to a single chain. Same response shape as getBalances (visible available/pending) but scoped to the given chainId.
| Name | In | Type | Description |
|---|---|---|---|
accountId* | path | string (uuid) | Account ID |
chainId* | path | string | Chain ID (e.g., 8453 for Base) |
200Default Response
{
"balances": [
{
"chainId": 8453,
"chainName": "Base",
"token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"tokenSymbol": "USDC",
"decimals": 6,
"logoUrl": "https://assets.coingecko.com/coins/images/6319/small/usdc.png",
"visible": {
"available": "1000000",
"pending": "500000"
},
"incognito": {
"pooled": {
"available": "750000",
"pendingApproval": "250000",
"declined": "0"
}
},
"usdAmount": 1.5,
"pricePerToken": 2000.42,
"priceStale": false,
"spam": false
}
],
"totalUsdAmount": 1.5
}400Default Response
{
"error": "Bad request",
"message": "string",
"code": "BAD_REQUEST",
"available": "0",
"minAmount": "0.00036 ETH",
"maxSendable": "0.018 ETH"
}401Default Response
{
"error": "Unauthorized",
"message": "string",
"code": "UNAUTHORIZED"
}404Default Response
{
"error": "Not found",
"message": "string"
}429Default Response
{
"error": "Too Many Requests",
"message": "Rate limit exceeded. Maximum 60 requests per 1 minute."
}Try it
accountIdchainIdcurl -X GET \
"https://api-stg.clkd.xyz/v1/accounts/{accountId}/balance/{chainId}"Get token balance
/v1/accounts/{accountId}/balance/{chainId}/{token}🔒Retrieve the balance for a single token on a specific chain. Returns visible available and pending amounts. Returns a zero-balance object if the token has never been received.
| Name | In | Type | Description |
|---|---|---|---|
accountId* | path | string (uuid) | Account ID |
chainId* | path | string | Chain ID |
token* | path | string | Token address (0x...) |
200Balance for a single token on a single chain. Contains visible available and pending amounts for standard on-chain stealth address holdings.
{
"chainId": 8453,
"chainName": "Base",
"token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"tokenSymbol": "USDC",
"decimals": 6,
"logoUrl": "https://assets.coingecko.com/coins/images/6319/small/usdc.png",
"visible": {
"available": "1000000",
"pending": "500000"
},
"incognito": {
"pooled": {
"available": "750000",
"pendingApproval": "250000",
"declined": "0"
}
},
"usdAmount": 1.5,
"pricePerToken": 2000.42,
"priceStale": false,
"spam": false
}400Default Response
{
"error": "Bad request",
"message": "string",
"code": "BAD_REQUEST",
"available": "0",
"minAmount": "0.00036 ETH",
"maxSendable": "0.018 ETH"
}401Default Response
{
"error": "Unauthorized",
"message": "string",
"code": "UNAUTHORIZED"
}404Default Response
{
"error": "Not found",
"message": "string"
}429Default Response
{
"error": "Too Many Requests",
"message": "Rate limit exceeded. Maximum 60 requests per 1 minute."
}Try it
accountIdchainIdtokencurl -X GET \
"https://api-stg.clkd.xyz/v1/accounts/{accountId}/balance/{chainId}/{token}"Get activities
/v1/accounts/{accountId}/activities🔒List confirmed (on-chain) transactions for the account with cursor-based pagination. The response uses a discriminated union on kind: SEND/RECEIVE/SELF/INCOGNITO_*/NFT_WITHDRAW include a transfer object, SWAP includes a swap object with source and dest token info, BRIDGE includes a bridge object with source, dest, and chain info. For in-flight transactions, use GET /activities/pending.
| Name | In | Type | Description |
|---|---|---|---|
limit | query | string | Maximum number of activities to return (1-500, default: 100) |
cursor | query | string | Base64-encoded cursor for pagination |
accountId* | path | string (uuid) | Account ID |
200Default Response
{
"activity": [
{
"txHash": "0x...",
"quoteId": "string",
"chainId": 8453,
"chainName": "Base",
"date": "string",
"kind": "string",
"lifecycle": {
"state": "string"
},
"isLikelySpam": false,
"fee": {
"tokenAddress": "0x...",
"decimals": 18,
"tokenSymbol": "ETH",
"logoUrl": "string",
"value": "1000000000000000",
"usdAmount": 0.001
},
"transfer": {
"tokenAddress": "0x...",
"decimals": 6,
"tokenSymbol": "USDC",
"logoUrl": "string",
"fromAddress": "0x...",
"toAddress": "0x...",
"value": "1000000",
"usdAmount": 1
},
"swap": {
"sourceTokenAddress": "0x...",
"sourceDecimals": 6,
"sourceTokenSymbol": "USDC",
"sourceLogoUrl": "string",
"sourceAmount": "1000000",
"sourceUsdAmount": 1,
"destTokenAddress": "0x...",
"destTokenSymbol": "WETH",
"destDecimals": 18,
"destLogoUrl": "string",
"destAmount": "500000000000000",
"destUsdAmount": 0.5,
"outputRecipient": "0x..."
},
"bridge": {
"sourceTokenAddress": "0x...",
"sourceDecimals": 6,
"sourceTokenSymbol": "USDC",
"sourceLogoUrl": "string",
"sourceAmount": "1000000",
"sourceUsdAmount": 1,
"destTokenAddress": "0x...",
"destTokenSymbol": "USDC",
"destDecimals": 6,
"destLogoUrl": "string",
"destAmount": "1000000",
"destUsdAmount": 1,
"outputRecipient": "0x...",
"bridgeStatus": "pending",
"destChainId": 8453,
"destChainName": "Base",
"estimatedFillTimeMs": 0,
"destTxHash": "0x..."
},
"pool": {
"poolAddress": "0x...",
"tokenAddress": "0x...",
"decimals": 18,
"tokenSymbol": "ETH",
"logoUrl": "string",
"amount": "1000000000000000",
"usdAmount": 1,
"aspStatus": "string",
"commitmentId": "string",
"vettingFee": "string",
"vettingFeeUsd": 0,
"depositFee": "string",
"depositFeeUsd": 0
},
"dappMeta": {
"origin": "string",
"description": "string",
"connectedAddress": "string"
},
"calldata": "string",
"offRamp": {
"peerDepositId": "string",
"paymentMethod": "venmo",
"escrowStatus": "string",
"depositId": "string",
"escrowAmount": "string",
"usdAmount": 0,
"estimatedFiatAmount": 0,
"tokenAddress": "string",
"decimals": 0,
"tokenSymbol": "string",
"logoUrl": "string",
"filledAmount": "string",
"serviceFee": "string",
"serviceFeeUsd": 0
}
}
],
"pagination": {
"limit": 100,
"nextCursor": "string"
}
}400Default Response
{
"error": "Bad request",
"message": "string",
"code": "BAD_REQUEST",
"available": "0",
"minAmount": "0.00036 ETH",
"maxSendable": "0.018 ETH"
}401Default Response
{
"error": "Unauthorized",
"message": "string",
"code": "UNAUTHORIZED"
}404Default Response
{
"error": "Not found",
"message": "string"
}Try it
accountIdlimitcursorcurl -X GET \
"https://api-stg.clkd.xyz/v1/accounts/{accountId}/activities"Get pending activities
/v1/accounts/{accountId}/activities/pending🔒List in-flight relay transactions (queued, pending, stuck) and recently confirmed/failed transactions for the account. The response uses the same shape as GET /activities: same kind values, same payload sub-objects. The lifecycle.state discriminates between 'in_flight', 'indexed', and 'failed'. Recently confirmed transactions are included for up to 5 minutes so the client can show continuous state while the transaction is indexed.
| Name | In | Type | Description |
|---|---|---|---|
accountId* | path | string (uuid) | Account ID |
200Default Response
{
"pending": [
{
"txHash": "0x...",
"quoteId": "string",
"chainId": 8453,
"chainName": "Base",
"date": "string",
"kind": "string",
"lifecycle": {
"state": "string"
},
"isLikelySpam": false,
"fee": {
"tokenAddress": "0x...",
"decimals": 18,
"tokenSymbol": "ETH",
"logoUrl": "string",
"value": "1000000000000000",
"usdAmount": 0.001
},
"transfer": {
"tokenAddress": "0x...",
"decimals": 6,
"tokenSymbol": "USDC",
"logoUrl": "string",
"fromAddress": "0x...",
"toAddress": "0x...",
"value": "1000000",
"usdAmount": 1
},
"swap": {
"sourceTokenAddress": "0x...",
"sourceDecimals": 6,
"sourceTokenSymbol": "USDC",
"sourceLogoUrl": "string",
"sourceAmount": "1000000",
"sourceUsdAmount": 1,
"destTokenAddress": "0x...",
"destTokenSymbol": "WETH",
"destDecimals": 18,
"destLogoUrl": "string",
"destAmount": "500000000000000",
"destUsdAmount": 0.5,
"outputRecipient": "0x..."
},
"bridge": {
"sourceTokenAddress": "0x...",
"sourceDecimals": 6,
"sourceTokenSymbol": "USDC",
"sourceLogoUrl": "string",
"sourceAmount": "1000000",
"sourceUsdAmount": 1,
"destTokenAddress": "0x...",
"destTokenSymbol": "USDC",
"destDecimals": 6,
"destLogoUrl": "string",
"destAmount": "1000000",
"destUsdAmount": 1,
"outputRecipient": "0x...",
"bridgeStatus": "pending",
"destChainId": 8453,
"destChainName": "Base",
"estimatedFillTimeMs": 0,
"destTxHash": "0x..."
},
"pool": {
"poolAddress": "0x...",
"tokenAddress": "0x...",
"decimals": 18,
"tokenSymbol": "ETH",
"logoUrl": "string",
"amount": "1000000000000000",
"usdAmount": 1,
"aspStatus": "string",
"commitmentId": "string",
"vettingFee": "string",
"vettingFeeUsd": 0,
"depositFee": "string",
"depositFeeUsd": 0
},
"dappMeta": {
"origin": "string",
"description": "string",
"connectedAddress": "string"
},
"calldata": "string",
"offRamp": {
"peerDepositId": "string",
"paymentMethod": "venmo",
"escrowStatus": "string",
"depositId": "string",
"escrowAmount": "string",
"usdAmount": 0,
"estimatedFiatAmount": 0,
"tokenAddress": "string",
"decimals": 0,
"tokenSymbol": "string",
"logoUrl": "string",
"filledAmount": "string",
"serviceFee": "string",
"serviceFeeUsd": 0
}
}
]
}401Default Response
{
"error": "Unauthorized",
"message": "string",
"code": "UNAUTHORIZED"
}404Default Response
{
"error": "Not found",
"message": "string"
}Try it
accountIdcurl -X GET \
"https://api-stg.clkd.xyz/v1/accounts/{accountId}/activities/pending"Send, Swap, Bridge, Convert
Sending, swapping, bridging, and converting to incognito all follow the same flow: get a quote, then submit.
Get quote signer public key
/v1/.well-known/quote-signer-public-keyRetrieve the server's P-256 ECDSA public key so clients can verify that quote responses were authentically signed by the server and haven't been tampered with.
200Default Response
{
"publicKey": "04...",
"format": "hex",
"curve": "P-256",
"algorithm": "ECDSA"
}Try it
curl -X GET \
"https://api-stg.clkd.xyz/v1/.well-known/quote-signer-public-key"List supported pools
/v1/supported-pools🔒List privacy pools available to the authenticated user, including pool contract addresses, accepted tokens, deposit limits, and ASP (Association Set Provider) details. Feature-flagged pools are only included when the flag is enabled for the account.
200Default Response
[
{
"poolAddress": "0x...",
"chainId": 1,
"chainName": "Ethereum",
"token": "0x...",
"tokenSymbol": "ETH",
"decimals": 18,
"logoUrl": "https://...",
"minDeposit": "10000000000000000",
"maxDeposit": "100000000000000000000",
"totalBalance": "2659000000000000000000",
"scope": "12345678901234567890",
"asp": {
"name": "0xbow",
"policyUrl": "https://0xbow.io/policy"
},
"maxRelayFeeBPS": 1000,
"withdrawalFeePerProofWei": "95000000000000"
}
]Try it
curl -X GET \
"https://api-stg.clkd.xyz/v1/supported-pools"Create quote
/v1/accounts/{accountId}/quote🔒Unified quote endpoint. For type=send: reserves balances and returns signing data. For type=swap: reserves balances and returns swap intents via Uniswap.
| Name | In | Type | Description |
|---|---|---|---|
accountId* | path | string (uuid) | Account ID |
idempotency-key | header | string | Client-generated unique key (e.g. UUID). If the server has already processed a request with this key for the same account and body, it returns the cached response instead of re-executing. Keys expire after 24 hours. |
200Default Response
{
"intents": [
{
"chainId": 0,
"eoa": "string",
"executionData": "string",
"nonce": "string",
"derivationNonce": "string",
"payer": "string",
"paymentToken": "string",
"paymentMaxAmount": "string",
"combinedGas": "string",
"encodedPreCalls": [
"string"
],
"encodedFundTransfers": [
"string"
],
"settler": "string",
"expiry": "string",
"isMultichain": true,
"funder": "string",
"funderSignature": "string",
"settlerContext": "string",
"paymentAmount": "string",
"paymentRecipient": "string",
"paymentSignature": "string",
"supportedAccountImplementation": "string",
"domain": {
"name": "string",
"version": "string",
"chainId": 0,
"verifyingContract": "string"
},
"types": null,
"primaryType": "string"
}
],
"delegations": [
{
"chainId": 0,
"address": "string",
"contractAddress": "string",
"derivationNonce": 0,
"authorizationNonce": 0
}
],
"quoteId": "string",
"expiresAt": "string",
"signature": "string",
"expectedOutput": "string",
"minimumOutput": "string",
"outputToken": "string",
"outputDecimals": 0,
"outputSymbol": "string",
"outputRecipient": "string",
"slippageBps": 0,
"routing": "string",
"protocolFeeBps": 0,
"protocolFeeAmount": "string",
"amountIn": "string",
"priceImpact": 0,
"estimatedFillTimeMs": 0,
"fillDeadline": 0,
"planId": "string",
"fees": {
"network": "string",
"dust": "string",
"service": "string",
"vetting": "string",
"deposit": "string",
"total": "string",
"waived": true
}
}400Default Response
{
"error": "Bad request",
"message": "string",
"code": "BAD_REQUEST",
"available": "0",
"minAmount": "0.00036 ETH",
"maxSendable": "0.018 ETH"
}401Default Response
{
"error": "Unauthorized",
"message": "string",
"code": "UNAUTHORIZED"
}403Default Response
{
"error": "Forbidden",
"message": "string"
}409Default Response
{
"error": "Conflict",
"message": "string",
"code": "QUOTE_LOCK_CONFLICT"
}429Default Response
{
"error": "Too Many Requests",
"message": "Rate limit exceeded. Maximum 30 requests per 1 minute."
}502Default Response
{
"error": "Bad Gateway",
"message": "string",
"code": "SWAP_UNAVAILABLE"
}503Default Response
{
"error": "Service Unavailable",
"message": "string"
}Try it
accountIdidempotency-keycurl -X POST \
-H "Content-Type: application/json" \
-d '{
"type": "",
"chainId": 0,
"token": "",
"amount": "",
"decimals": 0,
"destinationAddress": "",
"maxSend": true,
"ttl": 0
}' \
"https://api-stg.clkd.xyz/v1/accounts/{accountId}/quote"Submit transaction
/v1/accounts/{accountId}/submit🔒Submit client-signed intents and delegations from a quote to relay the transaction on-chain. Validates signatures, checks price slippage, and submits via the server relayer so the user pays no gas directly.
| Name | In | Type | Description |
|---|---|---|---|
accountId* | path | string (uuid) | Account ID |
idempotency-key | header | string | Client-generated unique key (e.g. UUID). If the server has already processed a request with this key for the same account and body, it returns the cached response instead of re-executing. Keys expire after 24 hours. |
200Default Response
{
"success": true,
"quoteId": "string",
"status": "string",
"message": "string"
}400Default Response
{
"error": "Bad request",
"message": "string",
"code": "BAD_REQUEST",
"available": "0",
"minAmount": "0.00036 ETH",
"maxSendable": "0.018 ETH"
}401Default Response
{
"error": "Unauthorized",
"message": "string",
"code": "UNAUTHORIZED"
}404Default Response
{
"error": "Not found",
"message": "string"
}409Default Response
{
"error": "Conflict",
"message": "string",
"code": "QUOTE_LOCK_CONFLICT"
}Try it
accountIdidempotency-keycurl -X POST \
-H "Content-Type: application/json" \
-d '{
"intents": [
{
"chainId": 0,
"eoa": "",
"executionData": "",
"nonce": "",
"derivationNonce": "",
"payer": "",
"paymentToken": "",
"paymentMaxAmount": "",
"combinedGas": "",
"encodedPreCalls": [
""
],
"encodedFundTransfers": [
""
],
"settler": "",
"expiry": "",
"isMultichain": true,
"funder": "",
"funderSignature": "",
"settlerContext": "",
"paymentAmount": "",
"paymentRecipient": "",
"paymentSignature": "",
"supportedAccountImplementation": "",
"domain": {
"name": "",
"version": "",
"chainId": 0,
"verifyingContract": ""
},
"types": null,
"primaryType": "",
"signature": ""
}
],
"delegations": [
{
"chainId": 0,
"address": "",
"contractAddress": "",
"derivationNonce": 0,
"authorizationNonce": 0,
"signature": ""
}
],
"quoteId": ""
}' \
"https://api-stg.clkd.xyz/v1/accounts/{accountId}/submit"Get relay status
/v1/accounts/{accountId}/relay-status/{quoteId}🔒Get the relay transaction status and hash for a submitted quote.
| Name | In | Type | Description |
|---|---|---|---|
accountId* | path | string (uuid) | — |
quoteId* | path | string | — |
200Default Response
{
"status": "string",
"txHash": "string",
"confirmedTxHash": "string"
}404Default Response
{
"error": "Not found",
"message": "string"
}Try it
accountIdquoteIdcurl -X GET \
"https://api-stg.clkd.xyz/v1/accounts/{accountId}/relay-status/{quoteId}"Unlock quote
/v1/accounts/{accountId}/unlock🔒Release the lock held by a quote so the funds become available for a new transaction. Use when the user cancels a send or the client decides not to submit.
| Name | In | Type | Description |
|---|---|---|---|
accountId* | path | string (uuid) | Account ID |
200Default Response
{
"success": true,
"message": "string"
}400Default Response
{
"error": "Bad request",
"message": "string",
"code": "BAD_REQUEST",
"available": "0",
"minAmount": "0.00036 ETH",
"maxSendable": "0.018 ETH"
}404Default Response
{
"error": "Not found",
"message": "string"
}Try it
accountIdcurl -X POST \
-H "Content-Type: application/json" \
-d '{
"quoteId": ""
}' \
"https://api-stg.clkd.xyz/v1/accounts/{accountId}/unlock"Get max spendable
/v1/accounts/{accountId}/max-spendable🔒Calculate the maximum spendable amount for a token, accounting for relay fees, swap gas, and pool fees when applicable. Use this to power the "max" button in send, swap, and pool UIs.
| Name | In | Type | Description |
|---|---|---|---|
accountId* | path | string (uuid) | Account ID |
200Default Response
{
"maxAmount": "string",
"feeEstimate": "string",
"spendableCount": 0,
"grossAmount": "string",
"fees": {
"network": "string",
"vetting": "string",
"deposit": "string",
"service": "string",
"total": "string"
},
"protocolFeeBps": 0,
"protocolFeeAmount": "string"
}400Default Response
{
"error": "Bad request",
"message": "string",
"code": "BAD_REQUEST",
"available": "0",
"minAmount": "0.00036 ETH",
"maxSendable": "0.018 ETH"
}Try it
accountIdcurl -X POST \
-H "Content-Type: application/json" \
-d '{
"chainId": 0,
"token": "",
"type": "",
"tokenOut": "",
"slippageBps": 0,
"tokenOutChainId": 0
}' \
"https://api-stg.clkd.xyz/v1/accounts/{accountId}/max-spendable"Create swap preview
/v1/accounts/{accountId}/swap-preview🔒Get a swap preview (price discovery) without reserving balances.
| Name | In | Type | Description |
|---|---|---|---|
accountId* | path | string (uuid) | Account ID |
200Default Response
{
"expectedOutput": "string",
"minimumOutput": "string",
"outputToken": "string",
"outputDecimals": 0,
"outputSymbol": "string",
"routing": "string",
"slippageBps": 0,
"feeEstimate": "string",
"estimatedFillTimeMs": 0,
"protocolFeeBps": 0,
"protocolFeeAmount": "string",
"priceImpact": 0,
"rateOnly": true
}400Default Response
{
"error": "Bad request",
"message": "string",
"code": "BAD_REQUEST",
"available": "0",
"minAmount": "0.00036 ETH",
"maxSendable": "0.018 ETH"
}401Default Response
{
"error": "Unauthorized",
"message": "string",
"code": "UNAUTHORIZED"
}429Default Response
{
"error": "Too Many Requests",
"message": "Rate limit exceeded. Maximum 30 requests per 1 minute."
}502Default Response
{
"error": "Bad Gateway",
"message": "string",
"code": "SWAP_UNAVAILABLE"
}503Default Response
{
"error": "Service Unavailable",
"message": "string"
}Try it
accountIdcurl -X POST \
-H "Content-Type: application/json" \
-d '{
"chainId": 0,
"tokenIn": "",
"tokenOut": "",
"amountIn": "",
"slippageBps": 0,
"tokenOutChainId": 0
}' \
"https://api-stg.clkd.xyz/v1/accounts/{accountId}/swap-preview"Recover conversion prepare
/v1/accounts/{accountId}/pool-recover/prepare🔒Build an unsigned Porto intent and delegation for a pool recover (ragequit). The client calls this after generating the commitment proof, signs the returned intent and delegation, then submits via the standard submit endpoint.
| Name | In | Type | Description |
|---|---|---|---|
accountId* | path | string | — |
200Default Response
Try it
accountIdcurl -X POST \
-H "Content-Type: application/json" \
-d '{
"quoteId": "",
"recoverCalldata": ""
}' \
"https://api-stg.clkd.xyz/v1/accounts/{accountId}/pool-recover/prepare"Cashout withdraw prepare
/v1/accounts/{accountId}/cashout/prepare🔒Build an unsigned Porto intent and delegation for an incognito cashout. The single intent contains pool withdrawal proofs + Across bridge calls. Client signs and submits via the standard submit endpoint.
| Name | In | Type | Description |
|---|---|---|---|
accountId* | path | string | — |
200Default Response
Try it
accountIdcurl -X POST \
-H "Content-Type: application/json" \
-d '{
"quoteId": "",
"withdrawals": [
{
"commitmentId": "",
"calldata": "",
"changeNullifierHash": ""
}
]
}' \
"https://api-stg.clkd.xyz/v1/accounts/{accountId}/cashout/prepare"Get pool state
/v1/accounts/{accountId}/pool/state🔒Get the current incognito pool state for an account and token. Returns the Merkle tree, ASP leaves, and your commitments — everything the client needs to build ZK withdrawal proofs.
| Name | In | Type | Description |
|---|---|---|---|
chainId* | query | number | Chain ID of the pool |
token* | query | string | Token address accepted by the pool (0x...) |
accountId* | path | string (uuid) | Account ID |
200Default Response
{
"leaves": [
"string"
],
"currentRoot": "string",
"treeSize": 0,
"aspLeaves": [
"string"
],
"spentNullifiers": [
{
"nullifierHash": "string",
"withdrawnValue": "string",
"newCommitment": "string"
}
],
"nextDepositIndex": 0,
"commitments": [
{
"id": "string",
"depositIndex": 0,
"withdrawalIndex": 0,
"commitment": "string",
"label": "string",
"value": "string",
"aspStatus": "string"
}
]
}400Default Response
{
"error": "Bad request",
"message": "string",
"code": "BAD_REQUEST",
"available": "0",
"minAmount": "0.00036 ETH",
"maxSendable": "0.018 ETH"
}401Default Response
{
"error": "Unauthorized",
"message": "string",
"code": "UNAUTHORIZED"
}Try it
accountIdchainIdtokencurl -X GET \
"https://api-stg.clkd.xyz/v1/accounts/{accountId}/pool/state"Cloakie
Cloakie NFT verification and withdrawal
Verify cloakie deposit
/v1/accounts/{accountId}/cloakie/verify🔒Scan recent unused stealth addresses for Cloakie NFTs on Base. Records any newly discovered deposits and activates the fee waiver.
| Name | In | Type | Description |
|---|---|---|---|
accountId* | path | string | — |
200Default Response
{
"active": true,
"deposits": [
{
"depositAddress": "string",
"tokenId": "string",
"imageUrl": "string"
}
]
}400Default Response
{
"error": "Bad request",
"message": "string",
"code": "BAD_REQUEST",
"available": "0",
"minAmount": "0.00036 ETH",
"maxSendable": "0.018 ETH"
}401Default Response
{
"error": "Unauthorized",
"message": "string",
"code": "UNAUTHORIZED"
}Try it
accountIdcurl -X POST \
"https://api-stg.clkd.xyz/v1/accounts/{accountId}/cloakie/verify"Withdraw cloakie
/v1/accounts/{accountId}/cloakie/withdraw🔒Build an intent to transfer a Cloakie NFT from a deposit address back to the user. Returns intents and delegations for client signing.
| Name | In | Type | Description |
|---|---|---|---|
accountId* | path | string | — |
200Default Response
{
"quoteId": "string",
"intents": [
{
"chainId": 0,
"eoa": "string",
"executionData": "string",
"nonce": "string",
"derivationNonce": "string",
"payer": "string",
"paymentToken": "string",
"paymentMaxAmount": "string",
"combinedGas": "string",
"encodedPreCalls": [
"string"
],
"encodedFundTransfers": [
"string"
],
"settler": "string",
"expiry": "string",
"isMultichain": true,
"funder": "string",
"funderSignature": "string",
"settlerContext": "string",
"paymentAmount": "string",
"paymentRecipient": "string",
"paymentSignature": "string",
"supportedAccountImplementation": "string",
"domain": {
"name": "string",
"version": "string",
"chainId": 0,
"verifyingContract": "string"
},
"types": null,
"primaryType": "string"
}
],
"delegations": [
{
"chainId": 0,
"address": "string",
"contractAddress": "string",
"derivationNonce": 0,
"authorizationNonce": 0
}
],
"expiresAt": "string",
"signature": "string",
"depositAddress": "string",
"recipientAddress": "string",
"tokenId": "string"
}400Default Response
{
"error": "Bad request",
"message": "string",
"code": "BAD_REQUEST",
"available": "0",
"minAmount": "0.00036 ETH",
"maxSendable": "0.018 ETH"
}401Default Response
{
"error": "Unauthorized",
"message": "string",
"code": "UNAUTHORIZED"
}404Default Response
{
"error": "Not found",
"message": "string"
}Try it
accountIdcurl -X POST \
-H "Content-Type: application/json" \
-d '{
"depositAddress": "",
"recipientAddress": "",
"tokenId": ""
}' \
"https://api-stg.clkd.xyz/v1/accounts/{accountId}/cloakie/withdraw"Relayer
Relayer details
/relayer/detailsGet relayer fee info for a given chain and asset
| Name | In | Type | Description |
|---|---|---|---|
chainId* | query | number | Chain ID |
assetAddress* | query | string | Asset address |
200Default Response
{
"feeBPS": "string",
"feeReceiverAddress": "string",
"chainId": 0,
"assetAddress": "string",
"minWithdrawAmount": "string",
"maxGasPrice": "string"
}400Default Response
{
"error": "Bad request",
"message": "string",
"code": "BAD_REQUEST",
"available": "0",
"minAmount": "0.00036 ETH",
"maxSendable": "0.018 ETH"
}503Default Response
{
"error": "Service Unavailable",
"message": "string"
}Try it
chainIdassetAddresscurl -X GET \
"https://api-stg.clkd.xyz/relayer/details"Relayer quote
/relayer/quoteGet a fee commitment for relaying a privacy pool withdrawal
200Default Response
{
"baseFeeBPS": "string",
"feeBPS": "string",
"gasPrice": "string",
"feeCommitment": {
"expiration": 0,
"asset": "string",
"withdrawalData": "string",
"signedRelayerCommitment": "string",
"extraGas": true,
"amount": "string"
},
"detail": {
"relayTxCost": {
"gas": "string",
"eth": "string"
},
"extraGasFundAmount": {
"gas": "string",
"eth": "string"
},
"extraGasTxCost": {
"gas": "string",
"eth": "string"
}
}
}400Default Response
{
"error": "Bad request",
"message": "string",
"code": "BAD_REQUEST",
"available": "0",
"minAmount": "0.00036 ETH",
"maxSendable": "0.018 ETH"
}503Default Response
{
"error": "Service Unavailable",
"message": "string"
}Try it
curl -X POST \
-H "Content-Type: application/json" \
-d '{
"chainId": 0,
"amount": "",
"asset": "",
"recipient": "",
"extraGas": true
}' \
"https://api-stg.clkd.xyz/relayer/quote"Relayer request
/relayer/requestSubmit a privacy pool withdrawal for relay
200Default Response
{
"success": true,
"txHash": "string",
"timestamp": 0,
"requestId": "string"
}400Default Response
{
"error": "Bad request",
"message": "string",
"code": "BAD_REQUEST",
"available": "0",
"minAmount": "0.00036 ETH",
"maxSendable": "0.018 ETH"
}500Default Response
{
"error": "string",
"message": "string"
}503Default Response
{
"error": "Service Unavailable",
"message": "string"
}Try it
curl -X POST \
-H "Content-Type: application/json" \
-d '{
"withdrawal": {
"processooor": "",
"data": ""
},
"proof": {
"pi_a": [
""
],
"pi_b": [
[
""
]
],
"pi_c": [
""
],
"protocol": "",
"curve": ""
},
"publicSignals": [
""
],
"scope": "",
"chainId": 0,
"feeCommitment": {
"expiration": 0,
"asset": "",
"withdrawalData": "",
"signedRelayerCommitment": "",
"extraGas": true,
"amount": ""
}
}' \
"https://api-stg.clkd.xyz/relayer/request"Simulation
Simulate transaction
/v1/simulate🔒Simulate a transaction via Tenderly to preview asset changes before signing.
200Default Response
{
"success": true,
"gasUsed": 0,
"assetChanges": [
{
"type": "string",
"token": {
"address": "string",
"symbol": "string",
"decimals": 0,
"name": "string"
},
"from": "string",
"to": "string",
"amount": "string",
"rawAmount": "string"
}
],
"error": "string"
}400Default Response
{
"error": "Bad request",
"message": "string",
"code": "BAD_REQUEST",
"available": "0",
"minAmount": "0.00036 ETH",
"maxSendable": "0.018 ETH"
}403Default Response
{
"error": "Forbidden",
"message": "string"
}Try it
curl -X POST \
-H "Content-Type: application/json" \
-d '{
"chainId": 0,
"from": "",
"to": "",
"value": "",
"data": ""
}' \
"https://api-stg.clkd.xyz/v1/simulate"Utilities
Lookup function signatures
/v1/function-signatures🔒Batch-resolve 4-byte function selectors to human-readable signatures. Uses a server-side cache backed by openchain.xyz.
200Default Response
{
"signatures": null
}403Default Response
{
"error": "Forbidden",
"message": "string"
}Try it
curl -X POST \
-H "Content-Type: application/json" \
-d '{
"selectors": [
""
]
}' \
"https://api-stg.clkd.xyz/v1/function-signatures"
