Authentication
Every request to A8 Core™ is signed. Signing proves who is calling and that the bytes were not altered in flight — it does not encrypt them, so all traffic also travels over TLS.
The model
A8 Core™ authenticates requests with HMAC-SHA256 over a canonical signing base. Your key id identifies which signing secret to use; the signature proves the request came from you and arrived intact. You pass the result in the Authorization header as HMAC keyId:signature:timestamp. Because a signature authenticates rather than encrypts, you always call over HTTPS.
| Component | Purpose |
|---|---|
keyId | Your key id — tells A8 Core™ which signing secret to verify against (for example key_live_8fa2c1e4). |
signature | Base64 HMAC-SHA256 over the canonical signing base. |
timestamp | Unix seconds at signing time; requests outside the freshness window are rejected, which defeats replay. |
Build the signing base
Concatenate the HTTP method, the request URL, the timestamp, and the raw JSON body, each on its own line. Compute the base identically on both sides and the HMAC will match.
POST
https://api.a8core.io/v1/accounts
1782925451
{"type":"individual","currency":"USD"}Authorization: HMAC key_live_8fa2c1e4:9Hf2...Qe1c:1782925451The 2026 profile — RFC 9421
A8 Core™ also offers RFC 9421 HTTP Message Signatures as a negotiable profile that runs alongside the baseline. It covers named components with a content-digest of the body and is the same signature format A8 Core™ uses on outbound webhook deliveries, so adopting it is a configuration change rather than a rewrite.
"@method": POST "@path": /v1/accounts "content-digest": sha-256=:X48E9qO...: "@signature-params": ("@method" "@path" "content-digest");created=1782925451;keyid="a8core-prod-2026a";alg="hmac-sha256"
Signature-Input: sig1=("@method" "@path" "content-digest");created=1782925451;keyid="a8core-prod-2026a";alg="hmac-sha256" Signature: sig1=:9Hf2...Qe1c:
Key rotation
Keys are identified by keyid, so you can rotate without downtime: we issue the new key, you start signing with it, and the old key stays valid through a short overlap before it is retired. Always send the keyid you signed with — never assume a single static key.
Store your signing secret in a secrets manager or vault, never in source control or client-side code. Anyone with the secret can sign as you.
Provider isolation
Your credentials scope every request to your provider. There is no cross-provider data access: a key can only read and write the clients, accounts, and transactions that belong to it. This isolation is enforced on every call, not just at login.
Common errors
| Symptom | Likely cause | Fix |
|---|---|---|
401 invalid signature | Signing base differs from the server’s | Re-derive the base exactly — same component order, same digest algorithm. |
401 stale request | created outside the allowed window | Sync your clock (NTP); the timestamp guards against replay. |
| Signature mismatch on POST | Body changed after signing, or digest computed over a different encoding | Compute content-digest over the exact bytes you send. |
Best practices
- Compare signatures in constant time to avoid timing leaks.
- Sign on the server; never ship the secret to a browser or mobile client.
- Keep client clocks in sync — the
createdwindow is your replay defense. - Log the
RequestIdfrom each response so failures are traceable end to end.
Where to next
Talk to a human.
Stuck on an integration? Our team answers developer questions directly.