For the complete documentation index, see llms.txt. This page is also available as Markdown.

Authentication

The two headers that authenticate every request, and the three request tiers.

The API uses two headers. There's no OAuth, no token exchange, and no partner-signed JWT — your backend holds one API key and identifies users by the same id you already use for them. The only signature anywhere in the flow is the user's one-time SIWS at onboarding.

Header
Required on
Purpose

X-Titan-Key

every request

Authenticates your integration (your tenant). Keep it server-side; never ship it to a browser.

X-Titan-User

every user-scoped request

Your stable id for the end-user — the same value you onboarded as sub. Titan maps it to that user's manager.

Every header originates on your backend. Nothing goes from the end-user's browser directly to Titan.

Header
Value

X-Titan-Key

Your partner API key. Never expose to browsers.

X-Titan-User

Your stable id for the user the request acts on. Required on user-scoped routes.

Content-Type

application/json on POST/PATCH.

X-Idempotency-Key

Optional on selected POSTs. A stable, unique-per-operation string. See Idempotency.

X-Request-Id

Optional. If set, Titan keeps it in logs and echoes it back as x-request-id. Otherwise one is generated.

Request tiers

Tier
Headers
Endpoints

Public

none

GET /health

Partner-only

X-Titan-Key

POST /partner/onboard, GET /partners/me/* (reporting)

User-scoped

X-Titan-Key + X-Titan-User

Everything that acts on a specific user — balances, orders, withdrawals, GET /me.

Reporting is tenant-scoped, not user-header-scoped. The /partners/me/* endpoints use X-Titan-Key only and return rows across your whole tenant. To narrow them to one user, pass ?userId=<the userId returned by POST /partner/onboard> — that userId is the opaque Titan id, not your sub / X-Titan-User. This is the main reason to store the userId onboarding returns.

A user's external wallet is bound to their manager by a SIWS signature collected once at POST /partner/onboard. After that, you act on their behalf within the on-chain policy by sending X-Titan-User — no further per-request user signature. The policy pins the manager to order-execution swaps — DCA cycles and trigger fills — plus withdrawals only to that user's own external wallet, so neither you nor Titan can move funds anywhere else.

Auth errors

These apply to every authenticated endpoint:

HTTP

error.code

When

401

INVALID_API_KEY

Missing or unknown X-Titan-Key.

401

KEY_REVOKED

Your key was revoked.

401

ENV_MISMATCH

Key issued for a different environment.

401

UNAUTHORIZED

On a user-scoped route: X-Titan-User is missing, or the supplied id was never onboarded. Call POST /partner/onboard for that user first.

403

PRODUCT_DISABLED

The product is disabled on your key.

403

PRODUCT_EXPIRED

Your product grant has expired.

403

TENANT_SUSPENDED

Your tenant is suspended (recoverable; contact Titan).

403

TENANT_DELETED

Your tenant is deleted.

403

TENANT_NOT_PROVISIONED

Key valid, but no tenant row yet — onboarding step missing on Titan's side.

Verify your plumbing

GET /me resolves the identity for the current request and is the quickest smoke test that X-Titan-Key + X-Titan-User map to the user you expect:

sessionId is always empty for partner integrations — ignore it. Rely on userId / walletAddress, and treat both as opaque strings (the field names are stable; their format may change).

Last updated