Authentication
Every Partner API request must carry your api_key in the
X-API-Key header. One header, every request.
POST /api/v1/partner/invoices HTTP/1.1
Host: api.apreceiving.com
X-API-Key: sk_XXXXXXXXXXXXXXXXXXXXXXXXXXXX
Content-Type: application/json
The Supplier Access endpoints (/v1/partner/supplier-access/*) are
deliberately auth-less, they back the supplier-portal pages your users
visit and use a per-flow token in the URL or body instead.
What credentials you hold
After completing the claim flow you have two related but separate secrets:
| Secret | Header | What it grants |
|---|---|---|
api_key | X-API-Key | All Partner API access (read + write) |
rotation_secret | X-Rotation-Secret | Self-rotate this specific key only |
Hold both. You will need both together to call the rotate endpoint, and losing either one means generating a new key from scratch (via the supplier portal regen page).
A key looks like sk_ followed by ~28 random characters; the rotation
secret looks like rs_ followed by ~28 random characters. Server-side
both are stored only as HMAC hashes, salted with a per-environment
pepper kept in Secrets Manager. We cannot recover the plaintext.
Where to send requests
Nuntiq runs three environments. All three are reachable on the public internet; what differs is the data they hold and which customer is willing to issue you a key on each.
| Environment | Base URL |
|---|---|
| Production | https://api.apreceiving.com/api |
| Test | https://test-api.apreceiving.com/api |
| Development | https://dev-api.apreceiving.com/api |
All Partner API paths begin with /v1/partner/, so the full URL for
invoice submission against production is:
https://api.apreceiving.com/api/v1/partner/invoices
A key issued on one environment is only valid on that environment. The path and request shape are identical across all three; only the host changes. See Environments for the full breakdown.
Failure modes
Every authentication failure returns HTTP 401. The body always carries
a human-readable message; some responses also include structured
fields you can branch on.
Missing header
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{ "message": "Missing API Key" }
You forgot the X-API-Key header. The fix is on your side, no Nuntiq
state has changed.
Unknown key
HTTP/1.1 401 Unauthorized
{ "message": "Invalid API Key" }
The hash does not match any live, non-revoked, non-expired key. Could be: typo, wrong environment, key was revoked, or, you guessed it from training data and we do not have it.
Expired or expired-disabled key
HTTP/1.1 401 Unauthorized
{
"error": "key_expired",
"message": "This API key expired on 2026-08-18. Generate a new key at https://acme.dev.apquery.com/supplier-access/regenerate",
"regenerate_url": "https://acme.dev.apquery.com/supplier-access/regenerate"
}
The key is genuinely yours but its expires_at has passed (or the
daily maintenance task has stamped expired_at on it). The response
tells you exactly where to send a human to generate a replacement.
This is the path you want your integration logs to make obvious — it is the safety net for partners whose recipients muted every reminder email. See the key_expired error.
Wrong rotation secret (rotate endpoint only)
HTTP/1.1 401 Unauthorized
{ "message": "Invalid credentials" }
The rotate endpoint validates BOTH X-API-Key and
X-Rotation-Secret. A vague Invalid credentials here means one (or
both) did not match. We deliberately do not tell you which, so an
attacker who has stolen one half cannot probe for the other.
You also get this 401 if the :key_id in the URL does not match the
key carried in X-API-Key — the rotate endpoint is self-rotate
only.
Customer key on a Partner endpoint
HTTP/1.1 403 Forbidden
{ "message": "Customer API keys cannot access partner endpoints" }
The key was real, but it is a Customer API key, not a Partner one.
These two surfaces never share auth. (The reverse, a Partner key on a
Customer endpoint, returns Partner API keys cannot access customer endpoints.)
Storing keys
Standard secret-management rules apply, with two specifically Nuntiq-flavored notes:
- Both secrets are issued together but stored in different roles.
Your normal request path only needs
api_key. Therotation_secretshould be locked away in the same vault but loaded only by your rotation job, not by every request handler. - Save the issued-at date and
expires_interval_days. When you rotate, you can re-use the same interval automatically by omitting it from the request body — but only if you remember what you originally picked. Stash both alongside the key.
What's next
- Keys: lifecycle: how keys are born, age, and die.
- Keys: rotation: the M2M self-rotate flow with 4-hour grace.
- Keys: expired-key error: the recovery path when a key lapses.