Error Codes
This page documents all error codes returned by the Optropic API, along with their meanings and recommended actions.
Error Response Format
All errors follow this structure:
{
"error": {
"code": "ERROR_CODE",
"message": "Human-readable error description",
"details": {
// Additional context (optional)
}
},
"meta": {
"requestId": "req_abc123",
"timestamp": "2026-02-18T10:30:00Z"
}
}
Authentication Errors (401)
| Code | Message | Action |
|---|---|---|
MISSING_API_KEY | No API key provided | Add x-api-key header |
INVALID_API_KEY | API key is invalid or malformed | Check key format, create new key |
EXPIRED_API_KEY | API key has expired | Create a new API key |
REVOKED_API_KEY | API key was revoked | Create a new API key |
Example
{
"error": {
"code": "INVALID_API_KEY",
"message": "The provided API key is invalid or does not exist"
}
}
Validation Errors (400)
| Code | Message | Action |
|---|---|---|
INVALID_GTIN | GTIN is not valid | Provide 14-digit GTIN |
INVALID_SERIAL | Serial number is invalid | Check serial format |
INVALID_URL | URL is malformed | Provide valid GS1 Digital Link URL |
MISSING_SIGNATURE | No signature in URL | Include sig parameter |
INVALID_SIGNATURE_FORMAT | Signature is malformed | Check signature encoding |
MISSING_REQUIRED_FIELD | Required field missing | Include all required fields |
INVALID_JSON | Request body is not valid JSON | Fix JSON syntax |
Example
{
"error": {
"code": "INVALID_GTIN",
"message": "GTIN must be exactly 14 digits",
"details": {
"field": "gtin",
"provided": "1234567890",
"expected": "14 digits, numeric only"
}
}
}
Resource Errors (404, 409)
| Code | HTTP | Message | Action |
|---|---|---|---|
KEY_NOT_FOUND | 404 | Signing key not found | Register the key first |
CODE_NOT_FOUND | 404 | Code not found | Check serial/GTIN |
DUPLICATE_SERIAL | 409 | Serial already exists | Use unique serial |
DUPLICATE_KEY | 409 | Public key already registered | Key already exists |
Example
{
"error": {
"code": "DUPLICATE_SERIAL",
"message": "A code with this GTIN and serial already exists",
"details": {
"gtin": "04260799580008",
"serial": "SN-001",
"existingCodeId": "code_abc123"
}
}
}
Rate Limit Errors (429)
| Code | Message | Action |
|---|---|---|
RATE_LIMITED | Too many requests | Wait and retry with backoff |
DAILY_LIMIT_EXCEEDED | Daily quota exhausted | Wait until midnight UTC |
BURST_LIMIT_EXCEEDED | Too many requests per second | Slow down request rate |
Example
{
"error": {
"code": "RATE_LIMITED",
"message": "Rate limit exceeded. Retry after 3600 seconds.",
"details": {
"limit": 1000,
"window": "daily",
"remaining": 0,
"retryAfter": 3600
}
}
}
Verification Errors
These aren't HTTP errors, but verification-specific results:
| Code | Verdict | Meaning |
|---|---|---|
SIGNATURE_INVALID | COUNTERFEIT | Cryptographic signature doesn't match |
KEY_REVOKED | SUSPICIOUS | Signing key was revoked |
EXCESSIVE_SCANS | SUSPICIOUS | Unusually high scan count |
GEOGRAPHIC_ANOMALY | SUSPICIOUS | Impossible location pattern |
Example
{
"verdict": "COUNTERFEIT",
"confidence": 0.0,
"checks": {
"signature": {
"passed": false,
"error": "SIGNATURE_INVALID",
"message": "Signature does not match any registered key"
}
}
}
Server Errors (500)
| Code | Message | Action |
|---|---|---|
INTERNAL_ERROR | Internal server error | Retry; contact support if persistent |
DATABASE_ERROR | Database unavailable | Retry after a few seconds |
SIGNING_ERROR | Code signing failed | Retry; contact support if persistent |
Example
{
"error": {
"code": "INTERNAL_ERROR",
"message": "An unexpected error occurred. Please try again.",
"details": {
"requestId": "req_abc123"
}
}
}
Include Request ID in Support Tickets
When contacting support, always include the requestId from the error response. This helps us trace the issue.
Error Handling Best Practices
1. Check HTTP Status First
const response = await fetch(url, options);
if (!response.ok) {
const error = await response.json();
switch (response.status) {
case 401:
// Handle authentication error
refreshApiKey();
break;
case 429:
// Handle rate limit
await sleep(error.error.details.retryAfter * 1000);
break;
case 400:
// Handle validation error
console.error('Invalid request:', error.error.message);
break;
default:
// Log and retry
console.error('API error:', error);
}
}
2. Log Errors with Context
function logError(error, context) {
console.error({
code: error.error?.code,
message: error.error?.message,
requestId: error.meta?.requestId,
context,
timestamp: new Date().toISOString(),
});
}
3. Display User-Friendly Messages
Map error codes to user-friendly messages:
const userMessages = {
INVALID_GTIN: 'Please enter a valid 14-digit product code.',
RATE_LIMITED: 'Too many requests. Please wait a moment and try again.',
SIGNATURE_INVALID: 'This product could not be verified as authentic.',
};
function getUserMessage(errorCode) {
return userMessages[errorCode] || 'An error occurred. Please try again.';
}