Errors & Troubleshooting
OpesCare uses standard HTTP status codes and returns a consistent JSON error body
for every failure. Always check the error field for a machine-readable code
and the message field for a human-readable explanation.
Error Response Format
{
"error": "invalid_scope",
"message": "The requested scope 'patient:records:write' is not permitted for this client.",
"status": 403
}
HTTP Status Codes
| Status | Meaning | Common Causes |
|---|---|---|
200 | OK | Request succeeded |
201 | Created | Resource created (subscriptions, consents) |
204 | No Content | Successful deletion (webhook unsubscribe) |
400 | Bad Request | Missing required fields, malformed JSON, invalid date format |
401 | Unauthenticated | Token missing, expired, or malformed — re-authenticate |
403 | Forbidden | Insufficient scope, consent not granted, sandbox restriction |
404 | Not Found | Patient not found, invalid health ID, resource deleted |
409 | Conflict | Duplicate webhook subscription endpoint |
422 | Unprocessable | Validation failed — wrong data type, value out of range |
429 | Rate Limited | Too many requests — back off and retry after the Retry-After header value |
500 | Server Error | Unexpected server error — check the status page |
Machine-Readable Error Codes
| Error Code | HTTP | Description | Fix |
|---|---|---|---|
invalid_client | 401 | Wrong client_id or client_secret | Check credentials in the developer portal |
token_expired | 401 | Bearer token has expired (1-hour TTL) | Request a new token using client_credentials grant |
token_invalid | 401 | Malformed or revoked token | Re-authenticate from scratch |
invalid_scope | 403 | Scope not granted to your client | Check allowed scopes in the developer portal |
consent_required | 403 | Patient has not granted consent to your client | Call the consent/grant endpoint first |
patient_not_found | 404 | No patient matches the given Health ID | Verify the Health ID is in the correct format (OPC-YYYY-XXXXX) |
facility_not_found | 404 | Facility ID does not exist | Verify your facility ID in the developer portal |
bridge_token_invalid | 401 | Bridge token missing or revoked | Re-generate the bridge token in the developer portal |
sdk_token_inactive | 401 | SDK token has been deactivated | Generate a new SDK token in the portal |
rate_limit_exceeded | 429 | Too many requests in a short window | Respect the Retry-After response header |
sandbox_only | 403 | Your account is restricted to sandbox | Request production access via the developer portal |
Error Handling Best Practices
$response = Http::withToken($token)
->get('https://opescare.test/api/v1/connect/patient/search', [
'health_id' => $healthId,
]);
if ($response->status() === 401) {
// Re-fetch token and retry once
$token = getNewToken();
$response = Http::withToken($token)
->get('https://opescare.test/api/v1/connect/patient/search', [
'health_id' => $healthId,
]);
}
if ($response->failed()) {
$error = $response->json();
// $error['error'] is the machine-readable code
// $error['message'] is the human-readable description
throw new \RuntimeException("OpesCare error: {$error['error']} — {$error['message']}");
}
$patient = $response->json();
async function searchPatient(healthId, token) {
const res = await fetch(
`https://opescare.test/api/v1/connect/patient/search?health_id=${healthId}`,
{ headers: { Authorization: `Bearer ${token}` } }
);
if (res.status === 429) {
const retryAfter = res.headers.get('Retry-After') || 5;
await new Promise(r => setTimeout(r, retryAfter * 1000));
return searchPatient(healthId, token); // retry once
}
if (!res.ok) {
const err = await res.json();
throw new Error(`OpesCare [${err.error}]: ${err.message}`);
}
return res.json();
}
import time
import requests
def search_patient(health_id: str, token: str, retry: int = 1):
resp = requests.get(
'https://opescare.test/api/v1/connect/patient/search',
params={'health_id': health_id},
headers={'Authorization': f'Bearer {token}'},
)
if resp.status_code == 429 and retry > 0:
time.sleep(int(resp.headers.get('Retry-After', 5)))
return search_patient(health_id, token, retry - 1)
resp.raise_for_status()
return resp.json()
If you're hitting persistent
500 errors, check the OpesCare system status page. For integration issues, contact developer support.