Error Codes & Troubleshooting
All ComplianceGrid API errors follow a consistent JSON format. This page covers HTTP status codes, application error codes, and common troubleshooting steps.
Error Response Format
All error responses return a consistent JSON structure with a success: false flag, an error code, a human-readable message, and for validation errors a details object that maps each field path to its problem. Authentication and rate-limit errors use the shorter form listed in the table below.
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed: parties.0.name: Required",
"details": {
"parties.0.name": "Required"
}
}
}X-Compliance-Grid-Request-Id response header — include it when contacting support for faster debugging.HTTP Status Codes
200Request succeeded. Response body contains the requested data.
201Resource created successfully (e.g., AES filing draft).
400Invalid request body, missing required fields, or malformed parameters.
401Missing or invalid API key / Bearer token.
402A production call needs more prepaid credit than the account has. The response gives the balance and a link to add credit.
403Valid credentials but insufficient permissions or unsubscribed API.
404Endpoint or resource does not exist.
409Resource already exists or state conflict (e.g., duplicate filing).
422Request is well-formed but semantically invalid (e.g., invalid HTS code format).
429Rate limit exceeded. Check Retry-After header.
500Unexpected server error. Retry with exponential backoff.
502Upstream government data source temporarily unavailable.
503API is temporarily down for maintenance. Check /status.
Application Error Codes
These codes appear in the error.code field and provide more specific context than the HTTP status alone.
| Code | HTTP | Description | Fix |
|---|---|---|---|
| authentication_required | 401 | No API key or Bearer token was sent. Authentication errors use the short form {"error": "<code>", "message": "..."} rather than the success/error envelope. | Send your key in the x-api-key header or a Bearer token in the Authorization header. |
| invalid_api_key | 401 | The API key is malformed, unknown or revoked. | Check the key prefix (cg_sk_ or cg_pk_) and that the key is active in the Developer Portal. |
| invalid_token | 401 | The Bearer token is invalid or has expired. | Request a new token via POST /oauth/token. |
| insufficient_credit | 402 | Not enough prepaid credit for this production call (the freight API returns the same condition as a payment_required problem). The response has balanceCents, requiredCents and billingUrl. | Add credit in the dashboard under Billing. Sandbox calls need no credit. |
| not_subscribed | 403 | Your account is not subscribed to this API in this environment. The response includes apiSlug and environment. | Subscribe to the API in the Developer Portal. |
| environment_mismatch | 403 | A sandbox key was used on the production endpoint, or a production key on the sandbox endpoint. | Use cg_sk_ keys with sandbox.api.compliancegrid.ai and cg_pk_ keys with api.compliancegrid.ai. |
| rate_limit_exceeded | 429 | Too many requests in the current window. The response carries Retry-After and the X-RateLimit-* headers. | Wait for Retry-After and back off exponentially. |
| VALIDATION_ERROR | 400 | One or more fields failed validation. error.details maps each field path to its problem, for example {"usppi.ein": "Required"}. | Fix the fields named in error.details. |
| INVALID_JSON | 400 | The request body is not valid JSON. | Send a well-formed JSON body with Content-Type: application/json. |
| PAYLOAD_TOO_LARGE | 413 | The request body is larger than 1 MB. | Split the request, for example into smaller batches. |
| NOT_FOUND | 404 | The endpoint, filing, screening or other record does not exist. | Check the path and the ID. |
| HTS_CODE_RETIRED | 422 | The HTS number was retired; the message names the replacement codes. | Use a replacement code from the message and calculate again. |
| NOT_READY | 409 | Batch results were requested before the job finished. | Poll GET /v1/risk/batch/{jobId} until the status is COMPLETE or PARTIAL. |
| IDEMPOTENT_REQUEST_IN_PROGRESS | 409 | A request with the same Idempotency-Key is still being processed. | Wait and retry with the same key. |
| AI_DISABLED | 403 | The request needs an AI feature but AI is switched off (aiMode off or the x-ai-mode header). | Remove the switch, or use the non-AI endpoint. |
| AI_PROVIDER_UNAVAILABLE | 503 | The AI provider could not be reached. No result was produced. | Retry later, or use the non-AI endpoint. |
| *_UNAVAILABLE | 502 | A government data source could not be reached (for example FMCSA_OOS_UNAVAILABLE). The message says so and the absence of a result must not be read as a clean result. | Retry after a few seconds. |
| INTERNAL_ERROR | 500 | An unexpected error. The message carries a reference id; the detail is in our logs. | Retry with exponential backoff and quote the reference if you contact support. |
Common Troubleshooting
Getting 401 but my key looks correct
- Ensure you're passing a valid Bearer token in the Authorization header (e.g., Authorization: Bearer <token>).
- Check for trailing whitespace or newline characters in the key.
- Verify the key hasn't been revoked in the Developer Portal.
- Sandbox keys must hit sandbox.api.compliancegrid.ai, not the production endpoint.
Getting 403 Subscription Required
- Go to Developer Portal → Subscriptions.
- Subscribe to the specific API vertical you're trying to call.
- Or click 'Subscribe to All' to enable all 12 verticals at once.
- Note: Subscription changes take effect immediately.
Getting empty results from sandbox
- Sandbox returns canned mock data for specific test queries.
- Try screening 'Huawei Technologies' for guaranteed hits.
- Check the response meta.environment field to confirm you're hitting sandbox.
Getting 502 errors intermittently
- This means an upstream government data source is temporarily unavailable.
- Implement retry logic with exponential backoff (see Rate Limits docs).
- Check the /status page for known outages.
- The API automatically falls back to cached data when possible.
Handling errors
const res = await fetch("https://api.compliancegrid.ai/v1/compliance/restricted-party-screening", {
method: "POST",
headers: { "x-api-key": process.env.CG_API_KEY!, "Content-Type": "application/json" },
body: JSON.stringify({ parties: [{ name: "Huawei", country: "CN" }] }),
});
const body = await res.json();
if (res.ok) {
console.log(body.data.overallResult);
} else if (res.status === 429) {
const wait = Number(res.headers.get("retry-after") ?? 1);
console.log("Rate limited, retry after", wait, "seconds");
} else if (res.status === 401) {
// authentication errors are {"error": "invalid_api_key", "message": "..."}
console.log("Authentication failed:", body.error);
} else {
// other errors are {"success": false, "error": {"code", "message", "details"}}
console.error("API error:", body.error.code, body.error.message, body.error.details);
console.error("Request id:", res.headers.get("x-compliance-grid-request-id"));
}import os, requests
res = requests.post(
"https://api.compliancegrid.ai/v1/compliance/restricted-party-screening",
headers={"x-api-key": os.environ["CG_API_KEY"]},
json={"parties": [{"name": "Huawei", "country": "CN"}]},
)
body = res.json()
if res.ok:
print(body["data"]["overallResult"])
elif res.status_code == 429:
print("Rate limited, retry after", res.headers.get("retry-after"), "seconds")
elif res.status_code == 401:
print("Authentication failed:", body["error"])
else:
err = body["error"]
print("API error:", err["code"], err["message"], err.get("details"))
print("Request id:", res.headers.get("x-compliance-grid-request-id"))Limits, headers, and retry strategies
API keys and OAuth 2.0 flow