Relay REST API¶
The Relay REST API submits signed Kuru trading actions without requiring the trading wallet to hold native gas tokens.
POST https://api.relay.testnet.kuru.io/relay
Authorization: Bearer <JWT bound to the trading wallet>
Content-Type: application/json
The REST surface has two authentication endpoints and one transaction endpoint. First obtain a wallet-bound JWT from /auth/challenge and /auth/token; then send typed actions to /relay. On /relay, the method field selects the action and payload contains that method's signed data.
Recommended integration¶
Use two wallets with different responsibilities:
| Identity | Responsibility |
|---|---|
| Main wallet | Owns or administers the AccountCore account. Keeps custody and grants or revokes trading permission. |
| Secondary trading EOA | Controlled by a passkey or embedded wallet. Receives only TRADE, delegates itself through EIP-7702, and signs trading intents. |
| Relay sponsor | Pays gas and broadcasts the outer transaction. It cannot create or modify the user's signed intent. |
Do not delegate the user's main wallet merely to enable one-click trading. A separate trading EOA limits the effect of a lost session key and lets the main wallet revoke trading rights independently.
The secondary wallet provider is your choice. An embedded or passkey-backed EOA from a provider such as Privy or Mera can be used if it can sign the required secp256k1 EIP-712 messages and EIP-7702 authorization.
Complete flow¶
1. Create the trading wallet¶
Create a fresh secondary EOA. In static-allowlist deployments, the operator must admit it first. In allow-all deployments, every valid nonzero EOA is admitted automatically and can proceed directly to authentication.
Request a challenge from the relay, sign its exact message with the secondary EOA, and exchange the signature for a short-lived JWT. See Authentication and JWTs for the complete request and response flow.
2. Onboard it¶
The main wallet signs an AccountCore authorization granting the secondary EOA TRADE. The secondary EOA signs an EIP-7702 authorization delegating itself to KuruTradingWallet.
Submit both in one account_core.authorize_account_signer_by_sig request. See Onboard a trading wallet.
3. Confirm onboarding¶
Wait for the transaction receipt and verify both:
- the secondary EOA contains the expected EIP-7702 delegation indicator; and
- AccountCore emitted
AccountSignerAuthorizedfor that EOA withTRADEpermission.
Do not send orders merely because the relay returned BROADCAST.
4. Trade¶
The secondary EOA signs KuruTradingWallet EIP-712 intents and submits them with either:
wallet.execute_batchfor readable native orders and slot cancellations; orwallet.execute_replace_by_slot_packedfor the compact, lower-calldata format.
5. Track the transaction¶
Store the relay requestId, returned txHash, intent nonce, and clientOrderId. Follow the receipt independently and verify IntentExecuted plus the expected orderbook change.
6. Revoke when the session ends¶
The AccountCore owner or administrator revokes the secondary EOA's trading permission through AccountCore. Revocation is not currently exposed as a public relay method, so integrations must submit the appropriate AccountCore revocation transaction through their normal wallet transaction flow.
Available methods¶
| Method | Purpose | Testnet |
|---|---|---|
account_core.authorize_account_signer_by_sig |
Grant the secondary EOA trading permission; can install its EIP-7702 delegation in the same transaction. | Enabled |
wallet.execute_batch |
Place readable native orders, cancel slots, or combine both. | Enabled |
wallet.execute_replace_by_slot_packed |
Place, replace, and cancel specific maker slots using compact 32-byte operations. | Enabled |
wallet.create_replace_trigger |
Register a conditional packed replacement. | Disabled |
wallet.create_batch_trigger |
Register a conditional native-order batch. | Disabled |
wallet.cancel_trigger |
Cancel an active trigger. | Enabled |
Trigger creation is part of the versioned API but is not routable on the current testnet deployment. See Conditional orders.
Request envelope¶
Every REST request has the same outer shape:
{
"requestId": "018f5ef2-88a1-7b41-a826-4b679010f87f",
"method": "wallet.execute_batch",
"wallet": "0x1111111111111111111111111111111111111111",
"payload": {},
"authorization7702": null
}
| Field | Meaning |
|---|---|
requestId |
A new lowercase UUIDv7 used for correlation. It is not durable idempotency. |
method |
One exact method name from the table above. |
wallet |
The secondary trading EOA. It must match the wallet claim in the JWT. |
payload |
The method-specific signed fields. |
authorization7702 |
null, except while installing or changing delegation as part of the same sponsored transaction. |
All integer fields in JSON are unsigned decimal strings. Addresses and byte strings use exact-width 0x hexadecimal. Unknown and duplicate JSON fields are rejected.
Submit a completed request with:
curl --fail-with-body \
--request POST \
--url https://api.relay.testnet.kuru.io/relay \
--header "Authorization: Bearer $KURU_RELAY_JWT" \
--header "Content-Type: application/json" \
--data @request.json
Responses¶
{
"requestId": "018f5ef2-88a1-7b41-a826-4b679010f87f",
"status": "BROADCAST",
"txHash": "0x...",
"sponsorAddress": "0x...",
"sponsorNonce": "42",
"transactionType": "DYNAMIC_FEE"
}
transactionType is SET_CODE when the request includes an accepted EIP-7702 authorization and DYNAMIC_FEE otherwise.
Read Responses and retries before implementing automatic retries. Use the OpenAPI YAML for the complete machine-readable schemas.