Skip to content

Error Handling

This guide covers the error response format and common error codes you may encounter when using the Veriglob API.

All error responses follow this structure:

{
"status": "error",
"message": "Error category",
"error": "Detailed error message"
}
FieldDescription
statusAlways "error" for error responses
messageA brief category or summary of the error
errorDetailed, human-readable error description
CodeNameDescription
400Bad RequestInvalid request body, missing required fields, or malformed data
401UnauthorizedMissing or invalid API key/authentication token
403ForbiddenValid authentication but insufficient permissions
404Not FoundRequested resource doesn’t exist
409ConflictResource already exists (e.g., duplicate email on registration)
429Too Many RequestsRate limit exceeded
CodeNameDescription
500Internal Server ErrorUnexpected server error
502Bad GatewayUpstream service unavailable
503Service UnavailableService temporarily unavailable

Missing API Key (401)

{
"status": "error",
"message": "Unauthorized",
"error": "API key is required"
}

Invalid API Key (401)

{
"status": "error",
"message": "Unauthorized",
"error": "Invalid API key"
}

Expired Token (401)

{
"status": "error",
"message": "Unauthorized",
"error": "Token has expired"
}

Missing Required Field (400)

{
"status": "error",
"message": "Validation Error",
"error": "issuer_did is required"
}

Invalid DID Format (400)

{
"status": "error",
"message": "Bad Request",
"error": "Invalid DID format: must start with 'did:key:'"
}

Invalid Credential (400)

{
"status": "error",
"message": "Bad Request",
"error": "Invalid credential: signature verification failed"
}

DID Not Found (404)

{
"status": "error",
"message": "Not Found",
"error": "DID not found"
}

Credential Not Found (404)

{
"status": "error",
"message": "Not Found",
"error": "Credential with ID 'urn:uuid:...' not found"
}

Rate Limit Exceeded (429)

{
"status": "error",
"message": "Rate limit exceeded",
"error": "You have exceeded your rate limit of 10 requests per minute. Please wait 45 seconds before retrying."
}
async function createDID() {
try {
const response = await fetch('https://api.veriglob.com/v1/did', {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
});
const data = await response.json();
if (!response.ok) {
// Handle error based on status code
switch (response.status) {
case 401:
throw new Error('Authentication failed: ' + data.error);
case 429:
// Implement retry with backoff
const retryAfter = response.headers.get('X-RateLimit-Reset');
throw new Error(`Rate limited. Retry after ${retryAfter}`);
default:
throw new Error(data.error || 'Unknown error occurred');
}
}
return data;
} catch (error) {
console.error('API Error:', error.message);
throw error;
}
}
import requests
from time import sleep
def create_did(api_key):
headers = {
'Authorization': f'Bearer {api_key}',
'Content-Type': 'application/json'
}
response = requests.post(
'https://api.veriglob.com/v1/did',
headers=headers
)
if response.status_code == 429:
# Handle rate limiting with retry
retry_after = int(response.headers.get('X-RateLimit-Reset', 60))
sleep(retry_after)
return create_did(api_key) # Retry
response.raise_for_status()
return response.json()
func createDID(apiKey string) (*DIDResponse, error) {
req, _ := http.NewRequest("POST", "https://api.veriglob.com/v1/did", nil)
req.Header.Set("Authorization", "Bearer "+apiKey)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode == 429 {
// Handle rate limiting
retryAfter := resp.Header.Get("X-RateLimit-Reset")
return nil, fmt.Errorf("rate limited, retry after: %s", retryAfter)
}
if resp.StatusCode != 201 {
var errResp ErrorResponse
json.NewDecoder(resp.Body).Decode(&errResp)
return nil, fmt.Errorf("API error: %s", errResp.Error)
}
var result DIDResponse
json.NewDecoder(resp.Body).Decode(&result)
return &result, nil
}

For transient errors (5xx, 429), implement exponential backoff:

async function fetchWithRetry(url, options, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(url, options);
if (response.status === 429 || response.status >= 500) {
const delay = Math.pow(2, i) * 1000; // Exponential backoff
await new Promise((resolve) => setTimeout(resolve, delay));
continue;
}
return response;
} catch (error) {
if (i === maxRetries - 1) throw error;
}
}
}
  1. Always check the status code before processing the response body
  2. Log errors with context including request ID, endpoint, and timestamp
  3. Implement retry logic for transient errors with exponential backoff
  4. Handle rate limits gracefully by respecting the X-RateLimit-Reset header
  5. Validate input on the client side to catch errors early
  6. Provide user-friendly messages by mapping error codes to actionable guidance