Security profile

How the partner API authenticates each call and signs each webhook. The values below are generated from the code the API runs on. A section marked “At launch” describes what takes effect when the partner security platform opens; everything else is in effect now.

API keys

Send a key as Authorization: Bearer <key>. The quickstart shows a first call.

v2 keys At launch

  • sa_live_ or sa_test_, then 30 base62 characters, then a 6-character base62 CRC-32 checksum: 44 characters in all. The checksum lets a mistyped key be refused before any lookup; it proves nothing about a key's authenticity.
  • A key holds only the permissions named on it: referrals:write, referrals:read, referrals.contact:read, reporting:read, plans:read, plans:write, members:activation-link.
  • After you roll a key, the old one keeps working for at most 7 days, and never past its own expiry. A key neither used nor created in 90 days is flagged idle.

IP allowlists At launch

A key's allowlist holds at most 20 entries. The widest an entry may be is an IPv4 /16 or an IPv6 /32, and all of a key's entries together cover at most 65,536 IPv4 addresses and 2^96 IPv6 addresses.

Legacy keys

sa_gap_ keys (sa_gap_test_ for test) keep working until they're revoked or expire. At launch, an institution that requires signed requests refuses them, and a LIVE key's referral create waits for the institution's Administrator of Record to be verified.

Signed requests At launch

Instead of a key, an institution can register its own public key and sign each request. The signature follows RFC 9421 (HTTP Message Signatures) and RFC 9530 (Content-Digest).

  • Algorithms: ed25519 or ecdsa-p256-sha256. A signature is 64 bytes.
  • Signature label sa, tag gap-v2. Methods: GET, HEAD, POST, PATCH. No other method is signed, and a signed request carries no Authorization header.
  • Covered components, in order. POST and PATCH: "@method" "@target-uri" "content-digest" "idempotency-key" "x-sa-environment". GET and HEAD: "@method" "@target-uri" "x-sa-environment", or "@method" "@target-uri" "idempotency-key" "x-sa-environment" when an Idempotency-Key is sent.
  • Content-Digest: sha-256, on POST and PATCH.
  • Window: created at most 300 seconds old and 30 seconds ahead.
  • Nonce: 16 to 128 characters from [A-Za-z0-9_-]. Each nonce is single-use for its credential, held until at least 331 seconds after created.
  • X-SA-Environment: TEST or PRODUCTION. Idempotency-Key: 1 to 255 visible ASCII characters (! to ~), required on POST and PATCH.
  • After a signed credential is replaced, the old one keeps working for at most 30 days, and never past its own expiry.

Webhooks

Signature

X-SecondAppraisal-Signature: t=<unix seconds>,v1=<hex>: HMAC-SHA256 over <t>.<raw body>. Verifying webhooks has the full steps and code.

Standard Webhooks headers At launch

webhook-id, webhook-timestamp, webhook-signature, sent to an endpoint with a Standard Webhooks secret.

Signing secrets

  • whsec_gap_: the HMAC key is the secret's text.
  • At launchwhsec_: a Standard Webhooks secret of 24 to 64 bytes. The HMAC key is the base64-decoded bytes after the prefix.

Secret rotation At launch

After a rotation, X-SecondAppraisal-Signature stays signed with the previous secret for 24 hours, unless you choose a shorter overlap or promote the new secret sooner, and then switches to the new one. An overlap is at most 168 hours. During an overlap, webhook-signature carries a signature from each Standard Webhooks secret in force.

Retention At launch

  • The events feed lists the last 30 days of events; older events are deleted.
  • 30 days after a delivery is created, a delivered or exhausted delivery's payload is replaced by a tombstone that keeps its SHA-256.
  • Each record of a read of partner data is deleted after 395 days.
  • An institution under a retention hold keeps its records until the hold is lifted.

These periods may change before launch.