Authentication & API Access
This integration crosses three separate identity boundaries: you (the Funding Party), your disbursement agent, and the pool-gate eligibility service. Each boundary has its own credential. None of them are interchangeable, and the pool-gate in particular never sees your identity at all, only a machine credential. This page is the single reference for every credential you'll encounter across Getting Started, Eligibility, and Disbursement.
Credentials at a glance
| Credential | Format | Gates | Sent as |
|---|---|---|---|
| Funding Party API key | lgk_live_..., capability-scoped | Your disbursement agent's /api/disburse, /api/validate, or (for holder.* capabilities) the transfer/send roles in Account Operations | Authorization: Bearer |
| SIWX session | Session cookie | /api/employers/onboard, /api/employers/eligibility/resync, /api/employers/holder/onboard, /api/employers/keys | Cookie: sessionId=... |
| Pool-gate OAuth (read) | OAuth 2.0 client-credentials, scope pool:read | Pool-gate whitelist/blacklist reads | Authorization: Bearer |
| Pool-gate OAuth (write) | OAuth 2.0 client-credentials, scope admin:whitelist:write | Pool-gate whitelist writes (platform-internal) | Authorization: Bearer |
| Pool-gate admin key | Static key | Fallback for pool-gate whitelist writes when OAuth isn't configured | X-API-Key |
| Agent loopback token | Static bearer you set | Fences the agent's local API from other processes on its host | Authorization: Bearer |
| Agent-to-platform edge token | Per-tenant bearer | The agent's outbound connection to the platform | Authorization: Bearer |
Funding Party API key
The credential your disbursement agent uses to authorize requests. Format: the literal prefix lgk_live_ followed by 40 base64url characters. Every key carries exactly one capability, and can only reach the routes that capability covers:
| Capability | Grants |
|---|---|
disburse | /api/disburse, /api/validate on your own agent (the Disbursement flow). |
holder.read | Reading your own pool subject's notes: /api/balance and the balance role. No ability to move funds. |
holder.transfer | The transfer role. |
holder.send | The send/withdraw role. |
roster.attest | Attaching recipients' W and registering their P — the attest role. Decides who may be paid, not who is paid. |
A key that can disburse cannot also transfer or send, and vice versa: this is enforced platform-side, not by convention, specifically because disburse's worst case (paying a whitelisted recipient) and transfer/send's worst case (moving or paying out the holder's whole balance) are different enough that a shared credential would silently widen whichever role holds it.
roster.attest is separated for the same reason in the other direction: fused with disburse, anything holding your payroll credential could add a wallet to the eligibility set. And holder.read is separated in a third direction — a holder.transfer key can already read your notes, so permitting it as a read credential would work, and would mean no deployment can be read-only. A reporting job should hold something that genuinely cannot move value.
Obtaining one. Minted at POST /api/employers/keys, SIWX-session-gated, body { "capability": "...", "name": "..." }. The plaintext is shown exactly once, in that response; only a hash is persisted server-side. Unlike account registration, minting is additive: it doesn't revoke any other live key on your wallet, so you hold one key per capability you actually use (up to 50 live keys per wallet). See Account Operations → Minting a scoped credential for a full example.
Rotation. There's no dedicated rotate call: mint a new key with POST /api/employers/keys, switch your agent over to it, then revoke the old one with DELETE /api/employers/keys/:id (its id comes back from the mint response, or from GET /api/employers/keys, which lists every key you've ever minted). Revocation takes effect on the agent's next request, no redeploy needed.
Sending it.
Authorization: Bearer lgk_live_...
against your own disbursement agent's /api/disburse or /api/validate. The agent validates it by forwarding to the platform's POST /api/employers/verify-key; if that verify call can't be reached, the agent fails closed (401) rather than accepting an unverifiable key.
Anyone holding this key can trigger disbursements against your funder wallet, gated only by whatever allowance and balance that wallet holds. Store it in a secrets manager, not in source control or agent config files checked into version control.
SIWX session
"Sign-in with X": a wallet-signature login, distinct from every credential above. It authenticates a human driving admin actions, never a disbursement call. It's required for:
POST /api/employers/onboardPOST /api/employers/eligibility/resyncPOST /api/employees/update-encryption-key
The session is a cookie (sessionId), backed by a server-side row with a default 24-hour TTL. Onboarding and eligibility-resync are further gated by an allowlist of wallet addresses configured for your deployment. An unconfigured allowlist closes these routes entirely; only wallets on it can call them.
Pool-gate OAuth
The pool-gate never receives your SIWX identity or your Funding Party API key; it only ever authenticates a machine principal, via OAuth 2.0 client-credentials (Cognito). There are two scopes:
| Scope | Purpose |
|---|---|
pool:read | Reading whitelist entries, blacklist non-membership intervals, and the pool-gate's public signing key. |
admin:whitelist:write | Writing new whitelist entries. Platform-internal: issued to the platform's own service credential, not to callers directly. |
A token is minted by POSTing client id/secret/scope to the configured token endpoint; scopes are namespaced (resourceserver/scope; a bare pool:read is rejected). If OAuth isn't configured for a deployment, whitelist writes fall back to a static X-API-Key admin credential instead.
How your agent gets a read token. Two options:
- Mint it yourself: configure the agent with the OAuth client-credentials directly, and it requests its own
pool:readtoken. - Have the platform vend one: call the platform's
/agent-edge/bootstrap, which returns a short-livedpool:readtoken scoped to your deployment. Preferred: your agent never needs to hold the raw OAuth client secret at all.
Agent loopback token
A bearer secret that fences your disbursement agent's local HTTP API off from other processes on the same host, unrelated to any Funding Party identity or to the pool-gate. Use this instead of (or alongside) Funding Party API key auth if the agent's /api/disburse needs to accept calls from a co-located scheduler that shouldn't need to hold your production lgk_live_... key.
If neither this nor Funding Party key verification is configured, the agent auto-generates an ephemeral token at boot and logs it. Fine for local testing, not for anything handling real funds.
Agent-to-platform edge token
A per-tenant bearer credential for the agent's own outbound, agent-initiated connection to the platform's /agent-edge. This is what lets the platform recognize which deployment's agent is submitting proved batches for settlement; it's provisioned alongside your deployment, separately from your Funding Party API key.
SIWX identity is never forwarded to the pool-gate. The pool-gate only ever sees a service credential: either the platform's own (for the SIWX-driven onboarding/resync paths) or your agent's own pool-gate credential (for the direct read path the agent uses before proving). In the direct-agent model there is no SIWX involved on the pool-gate side at all; the agent is a service principal end-to-end, and the read credential lives in your infrastructure, not the platform's.