Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no cardYour first API call in 2 minutes →
Troubleshooting API errors
The errors you meet while building, with the exact message and a fix for each: 401 missing or invalid key, 403 scope or ownership, 404, 422 references and idempotency, 429 rate limits.
The errors you are most likely to meet while building on Anpheros, with the exact message the API returns and a request that works. The full list of status codes is in the error catalogue.
How to read an error:
| Where | Error body |
|---|---|
/v1/… and /admin/… |
{"error": {"type": "login", "message": "Invalid API key."}} |
/fhir/R4/… |
{"resourceType": "OperationOutcome", "issue": [{"severity": "error", "code": "login", "diagnostics": "…"}]} |
Every response, error or not, carries an Anpheros-Request-Id header. Quote it when you write to
[email protected] and we can find your request.
curl -i https://platform.anpheros.com/v1/patients -H "Authorization: Bearer $ANPHEROS_KEY"
# -i shows the status line and the headers, including Anpheros-Request-Id
401 Unauthorized: the API does not know who you are
Missing credentials
{"error":{"type":"login","message":"Missing credentials: send an API key or an OAuth access token as 'Authorization: Bearer <token>'."}}
The Authorization header is missing, or it has the key without the word Bearer, or your
variable is empty.
This is the error people meet most often, usually in the API reference
before the key is pasted: press Authorize at the top of the page, paste your sk_test_… key and
press Authorize again, then Try it out. In your own code:
# wrong: no "Bearer"
curl https://platform.anpheros.com/v1/patients -H "Authorization: $ANPHEROS_KEY"
# right
curl https://platform.anpheros.com/v1/patients -H "Authorization: Bearer $ANPHEROS_KEY"
# check the variable is set in this terminal
echo "$ANPHEROS_KEY"
Invalid API key
{"error":{"type":"login","message":"Invalid API key."}}
The key is incomplete (cut off when copied), has a space, a line break or quotes in it, or was
deleted. Copy it again from where you saved it. Keys are shown only once: if you no longer have it,
create a new key in the dashboard.
The response also carries WWW-Authenticate: Bearer realm="anpheros", error="invalid_token".
This API key has been revoked
{"error":{"type":"login","message":"This API key has been revoked."}}
Someone on your team revoked the key in the dashboard. Create a new one and replace it wherever the old one was used.
This key does not match its project's environment
{"error":{"type":"login","message":"This key does not match its project's environment."}}
A test key (sk_test_…) only works on a sandbox project, and a live key (sk_live_…) only on a
production project. Use the key of the project you are calling.
Access token expired or revoked (OAuth)
{"error":{"type":"login","message":"Access token expired or revoked."}}
Access tokens are short-lived. Use the refresh token at POST /oauth/token with
grant_type=refresh_token; if the person revoked access, send them through the consent screen again.
Both SDKs refresh once on a 401 for you. Other OAuth messages: The consent behind this token is no
longer active. (the person withdrew consent) and The application behind this token is not active.
(the app was disabled). Details: Authentication and OAuth.
403 Forbidden: the API knows you, but this is not allowed
Missing scope
{"error":{"type":"forbidden","message":"This credential does not have the 'write' scope."}}
The key was created with fewer scopes than the call needs: for example a read-only key used for a
POST. Create a key with read and write in the dashboard, or through the Admin API:
curl -X POST https://platform.anpheros.com/admin/projects/proj_…/keys \
-H "Authorization: Bearer $FIREBASE_ID_TOKEN" -H 'content-type: application/json' \
-d '{"name":"local dev","scopes":["read","write"]}'
Written by another organization
{"error":{"type":"forbidden","message":"This Observation was written by another organization and cannot be changed or deleted by yours. Write your own resource instead."}}
You can read what other organizations wrote to a record you have access to, but only the author can
change or delete it. Create your own resource, and use derived_from or a note to point to the
original if needed. The same rule inside your organization: Only the project that created this
Observation can change it.
The consent does not allow it (OAuth)
{"error":{"type":"forbidden","message":"The consent behind this token does not allow 'write' on Observation."}}
The person approved fewer SMART scopes than the call needs, for example patient/Observation.rs
(read and search) and not .c (create). Ask for the scope you need in the authorization request;
the person approves it on the consent screen.
404 Not Found
The resource does not exist for you
{"error":{"type":"not-found","message":"…"}}
Projects are isolated: a patient created by another project does not exist for you, so you get 404,
never 403. Ids are also pairwise: the same person has a different id in every project. Use the ids
your own project received, for example from GET /v1/patients.
No such endpoint
{"error":{"type":"not-found","message":"No such endpoint: GET /v1/patient. Reference: https://developers.anpheros.com/docs"}}
A typo in the path, or the wrong method. Collections are plural (/v1/patients,
/v1/patients/{id}/observations). Paths start directly with /v1, /fhir/R4 or /oauth: a path
like /api/v1/patients returns {"detail":"Not Found"}. Every path is in the
API reference.
422 Unprocessable: the request is well formed, but it cannot be applied
The referenced patient does not exist
{"resourceType":"OperationOutcome","issue":[{"severity":"error","code":"not-found","diagnostics":"The referenced Patient does not exist."}]}
The subject of the resource points to a patient that does not exist for your project, often an id
from another project or from before a sandbox reset (reset gives the synthetic patients new ids). Read
the id again:
curl "https://platform.anpheros.com/fhir/R4/Patient?identifier=https://anpheros.com/fhir/sid/sandbox-persona|p02" \
-H "Authorization: Bearer $ANPHEROS_KEY"
Each synthetic patient keeps the same sandbox-persona identifier across resets (p02 is always
Elena Ionescu).
Idempotency-Key used with a different request
{"error":{"type":"conflict","message":"Idempotency-Key was already used with a different request."}}
An Idempotency-Key stands for one request. Repeat the same request with the same key and you get the
same answer without a duplicate; send a different body and you get this error. Use a new key for
each new write:
-H "Idempotency-Key: $(uuidgen)"
A resource cannot be moved to another patient
{"resourceType":"OperationOutcome","issue":[{"severity":"error","code":"invalid","diagnostics":"A resource cannot be moved to another patient."}]}
An update changed the subject of an existing resource. Delete it and create a new one for the
right patient instead.
429 Too Many Requests
{"error":{"type":"throttled","message":"Rate limit of 600 requests/minute exceeded for this credential."}}
You sent more requests in one minute than the limit for your key (600 a minute by default). The
response has a Retry-After header with the number of seconds to wait. Wait that long, then retry;
both SDKs do it for you with backoff. To need fewer calls: read pages of up to 200 items, use
_summary=count when you only need a number, and use webhooks instead of polling.
All limits: Limits and rate limits.
import time, requests
def get(url, key):
while True:
r = requests.get(url, headers={"Authorization": f"Bearer {key}"})
if r.status_code != 429:
return r
time.sleep(int(r.headers.get("Retry-After", "5")))
Still stuck?
Write to [email protected] with the Anpheros-Request-Id, the method and path, and the status you
got. Never send your key.
Frequently asked questions
Why do I get 404 and not 403 for another project's patient?
Projects are isolated, so another project's patients do not exist for you. A 403 would confirm that the patient exists, which the platform never does.
Does a sandbox key work in production?
No. Sandbox keys (sk_test_…) see only sandbox data, and production keys (sk_live_…) only production data. The base URL is the same.
How long is my access token valid?
Access tokens are short-lived and refresh tokens last longer; the exact lifetimes are in Limits and rate limits. The SDKs refresh tokens automatically.
Ask your AI
Paste this into Claude, ChatGPT, Cursor or Claude Code. Your assistant reads this guide and adapts it to your code.
Read https://developers.anpheros.com/guides/troubleshooting.md and help me find and fix the API error I am getting. Use the Anpheros sandbox (base URL https://platform.anpheros.com) with my API key from the ANPHEROS_KEY environment variable, never written in the code. Give me complete, runnable code, the response I should expect, and how to fix the errors in https://developers.anpheros.com/guides/troubleshooting.md if a call fails.Open in ClaudeOpen in ChatGPTThis guide as MarkdownBuild the whole integration with an AI coding tool
Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no cardYour first API call in 2 minutes →