Authentication
Darwin supports three authentication methods on the public API. Pick by audience:
| Method | Audience | Where used |
|---|---|---|
| JWT bearer token | end users (humans) | Captia operators, Tracium portal, dashboards |
| API key | server-to-server integrations | webhooks consumers, batch jobs, ERP connectors |
| Sign-In with Ethereum (SIWE) | wallet-based identity | Web3-native operators, advanced flows |
All three carry the tenant context plus scope-based permissions (see Tenants & identity).
In every example below, set BASE_URL to the API base URL provided in
your provisioning email (sandbox or production). Concrete domains are
not published here on purpose: contact the team at
tech@darwinevolution.io for
credentials and your environment base URL.
export BASE_URL="<API_BASE_URL>"JWT bearer (most common)
Section titled “JWT bearer (most common)”Step 1: Login
Section titled “Step 1: Login”POST /api/v2/auth/login (tenantId is optional):
curl -X POST "$BASE_URL/api/v2/auth/login" \ -H "Content-Type: application/json" \ -d '{ "email": "operator@example.com", "password": "your-password", "tenantId": "tnt_a1b2c3" }'Response:
{ "accessToken": "eyJhbGciOiJIUzI1NiIs...", "refreshToken": "eyJhbGciOiJIUzI1NiIs...", "partial": false}Response fields:
accessToken: signed JWT v2.refreshToken: to renew the access token.partial: true: appears when the access token is tenant-less (login withouttenantIdand the user has multiple memberships). You must call/select-tenantbefore using it.stale: true: appears if membership data changed and re-auth is recommended.
Step 2: Select tenant (if token came partial)
Section titled “Step 2: Select tenant (if token came partial)”If the token came partial: true, promote it:
curl -X POST "$BASE_URL/api/v2/auth/select-tenant" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "tenantId": "tnt_a1b2c3" }'Response includes a new full-scope accessToken.
To list the user’s memberships and choose a tenant:
curl "$BASE_URL/api/v2/auth/memberships" \ -H "Authorization: Bearer $ACCESS_TOKEN"Returns an array with slug, name, onChainTenantId,
tenantContractAddress per tenant the user belongs to.
Switch tenant during a session
Section titled “Switch tenant during a session”curl -X POST "$BASE_URL/api/v2/auth/switch-tenant" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "tenantId": "tnt_other" }'Step 3: Call API with bearer
Section titled “Step 3: Call API with bearer”curl "$BASE_URL/api/v1/events" \ -H "Authorization: Bearer $ACCESS_TOKEN"Refresh
Section titled “Refresh”JWT lifetime is short (1h typical). Use the refreshToken from login to
issue a new access token.
API key (server-to-server)
Section titled “API key (server-to-server)”For backend integrations: your ERP polling Tracium, an analytics job, a webhook consumer.
curl "$BASE_URL/api/v1/events" \ -H "X-API-Key: $API_KEY"API keys are tenant-scoped and role-scoped. Generate them from the Tracium admin portal. Rotate on compromise.
Sign-In with Ethereum (SIWE)
Section titled “Sign-In with Ethereum (SIWE)”For wallet-native operators: operators who already have an Ethereum wallet (MetaMask, WalletConnect, hardware wallet) and prefer to sign with their wallet rather than a password.
Step 1: Get a nonce
Section titled “Step 1: Get a nonce”curl "$BASE_URL/api/v2/auth/siwe/nonce"Response: a server-generated nonce string.
Step 2: Sign in the wallet
Section titled “Step 2: Sign in the wallet”In your front-end (or wallet integration), construct the SIWE message per EIP-4361, include the nonce, and have the user sign.
Step 3: Submit signed message
Section titled “Step 3: Submit signed message”curl -X POST "$BASE_URL/api/v2/auth/siwe" \ -H "Content-Type: application/json" \ -d '{ "message": "<the SIWE message>", "signature": "<wallet-signed hex>" }'Response: accessToken like the JWT bearer flow.
Process-scope grants
Section titled “Process-scope grants”Beyond role-based access, Darwin supports least-privilege grants per
process: an operator can be authorized for wool_shearing events
only, without unlocking the whole process map.
The JWT carries the process scope; calls to events outside the granted scope are rejected at the API layer.
Identifying yourself
Section titled “Identifying yourself”curl "$BASE_URL/api/v2/auth/me" \ -H "Authorization: Bearer $ACCESS_TOKEN"Returns the full JWT v2 payload: sub, email, wallet, did,
tid (tenant slug), tenantUuid, roles[], roleScopes
(process-scope grants in effect), profileComplete,
isPlatformAdmin, memberships[], username, orgs[], orgId.
Where to go next
Section titled “Where to go next”- Quickstart: submit an event with the prepared-transaction flow.
- Sandbox: request sandbox credentials for evaluation.
- Rate limits: usage quotas per tier.