Error Handling Guide
The mCards API uses standard HTTP status codes and returns structured error responses. This guide covers common errors and best practices for handling them.
HTTP Status Codes
| Code | Meaning | Description |
|---|---|---|
200 | OK | Request succeeded |
201 | Created | Resource created successfully |
400 | Bad Request | Invalid request parameters |
401 | Unauthorized | Missing or invalid authentication |
403 | Forbidden | Valid auth but insufficient permissions |
404 | Not Found | Resource does not exist |
422 | Unprocessable Entity | Validation error |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Server-side error |
Error Response Format
json
{
"error": "Resource not found",
"message": "No wallet found with UUID: abc-123",
"code": "not_found",
"details": {}
}Common Error Scenarios
Authentication Errors (401)
json
{
"error": "Unauthorized",
"message": "HMAC signature verification failed",
"code": "invalid_signature"
}Permission Errors (403)
json
{
"error": "Forbidden",
"message": "Token scope 'partner:read' does not include 'cards:write'",
"code": "insufficient_scope"
}Validation Errors (422)
json
{
"error": "Validation failed",
"message": "One or more fields are invalid",
"code": "validation_error",
"details": {
"cardholder_uuid": ["is required"],
"program_uuid": ["must be a valid UUID"]
}
}Rate Limit Errors (429)
json
{
"error": "Rate limit exceeded",
"message": "120 requests per minute exceeded",
"code": "rate_limited",
"details": {
"retry_after": 45,
"limit": 120,
"used": 120
}
}Handling Errors in the SDKs
TypeScript
typescript
const result = await client.cards.get('nonexistent-uuid');
if (!result.ok) {
switch (result.status) {
case 401:
console.error('Authentication failed');
break;
case 403:
console.error('Insufficient permissions');
break;
case 404:
console.error('Card not found');
break;
case 429:
const retryAfter = result.headers['retry-after'] || '60';
console.error(\`Rate limited — retry after \${retryAfter}s\`);
break;
default:
console.error(\`Error: \${result.status} — \${result.error}\`);
}
return;
}
console.log(result.data);Python
python
from mcards_sdk.exceptions import McardsSdkError
# Check-based
result = client.cards.get("nonexistent-uuid")
if not result.ok:
if result.status == 401:
print("Authentication failed")
elif result.status == 404:
print("Card not found")
elif result.status == 429:
retry_after = result.headers.get("Retry-After", "60")
print(f"Rate limited — retry after {retry_after}s")
# Exception-based
try:
result = client.cards.get("nonexistent-uuid")
result.raise_for_error()
except McardsSdkError as e:
print(f"API error: {e} (status={e.status})")Retry Strategy
typescript
async function withRetry(fn, maxRetries = 3, baseDelay = 1000) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const result = await fn();
if (result.ok || (result.status >= 400 && result.status < 500 && result.status !== 429)) {
return result;
}
if (attempt === maxRetries) return result;
const delay = result.status === 429
? (parseInt(result.headers['retry-after'] || '60', 10) * 1000)
: baseDelay * Math.pow(2, attempt) * (0.5 + Math.random() * 0.5);
await new Promise(resolve => setTimeout(resolve, delay));
}
}Best Practices
- Always check
result.okbefore accessingresult.data - Handle 401 by refreshing credentials — Bearer tokens expire after 1 hour
- Implement exponential backoff for 429 and 5xx errors
- Log error details including status, error message, and request context
- Use idempotency keys for write operations to safely retry
- Set reasonable timeouts — do not wait indefinitely for API responses
- Monitor error rates — a spike in 5xx errors may indicate a platform issue