Errors
Handle API errors effectively with comprehensive error codes, types, and troubleshooting guidance
Errors
The GetPaidHQ API uses conventional HTTP status codes to indicate success or failure and returns detailed error information in a consistent JSON format.
HTTP status codes
The API returns these HTTP status codes:
Code | Description |
---|---|
200 | OK - Request succeeded |
201 | Created - Resource created successfully |
204 | No Content - Request succeeded, no content returned |
400 | Bad Request - Invalid request parameters |
401 | Unauthorized - Invalid or missing authentication |
403 | Forbidden - Insufficient permissions |
404 | Not Found - Resource doesn't exist |
409 | Conflict - Resource already exists or conflicting state |
422 | Unprocessable Entity - Valid request but semantic errors |
429 | Too Many Requests - Rate limit exceeded |
500 | Internal Server Error - Server error |
502 | Bad Gateway - Gateway error |
503 | Service Unavailable - Service temporarily unavailable |
Error response format
All errors return a consistent JSON structure:
{
"error": {
"type": "validation_error",
"message": "The provided email address is invalid",
"field": "email",
"code": "invalid_email_format",
"request_id": "req_1234567890abcdef"
}
}
Error object properties
type
: The category of error (see types below)message
: Human-readable error descriptionfield
: The specific field that caused the error (validation errors only)code
: Machine-readable error code for programmatic handlingrequest_id
: Unique identifier for debugging with support
Error types
validation_error
Request contains invalid or missing required parameters.
{
"error": {
"type": "validation_error",
"message": "Email is required",
"field": "email",
"code": "missing_required_field"
}
}
Common validation error codes:
missing_required_field
invalid_email_format
invalid_currency_code
amount_too_small
invalid_date_format
authentication_error
API key is missing, invalid, or expired.
{
"error": {
"type": "authentication_error",
"message": "Invalid API key provided",
"code": "invalid_api_key"
}
}
Common authentication error codes:
invalid_api_key
api_key_expired
missing_api_key
organization_suspended
permission_error
Valid authentication but insufficient permissions for the requested operation.
{
"error": {
"type": "permission_error",
"message": "Insufficient permissions to access this resource",
"code": "insufficient_permissions"
}
}
not_found_error
The requested resource doesn't exist or has been deleted.
{
"error": {
"type": "not_found_error",
"message": "Customer not found",
"code": "customer_not_found"
}
}
rate_limit_error
Too many requests in a given time period. See Rate Limits for details.
{
"error": {
"type": "rate_limit_error",
"message": "Rate limit exceeded. Retry after 60 seconds",
"code": "rate_limit_exceeded"
}
}
conflict_error
Request conflicts with the current state of the resource.
{
"error": {
"type": "conflict_error",
"message": "Customer with this email already exists",
"code": "customer_already_exists"
}
}
payment_error
Payment processing failures.
{
"error": {
"type": "payment_error",
"message": "Payment method declined by issuer",
"code": "card_declined",
"payment_error": {
"decline_code": "insufficient_funds",
"issuer_message": "Not sufficient funds"
}
}
}
Common payment error codes:
card_declined
expired_card
invalid_cvc
processing_error
insufficient_funds
server_error
Internal server errors. These should be rare and are automatically logged.
{
"error": {
"type": "server_error",
"message": "An internal error occurred",
"code": "internal_server_error"
}
}
Error handling best practices
Check HTTP status codes
Always check the HTTP status code before processing the response:
try {
const customer = await getpaidhq.customers.create(customerData);
console.log('Customer created:', customer.id);
} catch (error) {
if (error.status === 400) {
console.log('Validation error:', error.message);
} else if (error.status === 409) {
console.log('Customer already exists');
} else {
console.log('Unexpected error:', error);
}
}
Handle specific error types
Use the error type and code for specific handling:
import { GetPaidHQError } from '@getpaidhq/node';
try {
const payment = await getpaidhq.payments.create(paymentData);
} catch (error) {
if (error instanceof GetPaidHQError) {
switch (error.type) {
case 'payment_error':
handlePaymentError(error);
break;
case 'rate_limit_error':
scheduleRetry(paymentData, error.retryAfter);
break;
case 'validation_error':
showValidationError(error.field, error.message);
break;
default:
logError(error);
}
}
}
function handlePaymentError(error) {
switch (error.code) {
case 'card_declined':
showMessage('Payment declined. Please try a different card.');
break;
case 'expired_card':
showMessage('Card expired. Please update your payment method.');
break;
case 'insufficient_funds':
showMessage('Insufficient funds. Please try a different payment method.');
break;
default:
showMessage('Payment failed. Please try again.');
}
}
Implement retry logic
For transient errors, implement exponential backoff:
async function apiCallWithRetry(apiCall, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await apiCall();
} catch (error) {
// Don't retry validation or authentication errors
if (error.type === 'validation_error' || error.type === 'authentication_error') {
throw error;
}
// Retry server errors and rate limits
if (error.status >= 500 || error.status === 429) {
if (attempt < maxRetries - 1) {
const delay = Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
}
throw error;
}
}
}
Log errors for debugging
Always log errors with the request ID:
function logError(error, context = {}) {
console.error('API Error:', {
type: error.type,
message: error.message,
code: error.code,
requestId: error.requestId,
status: error.status,
context
});
// Send to error tracking service
errorTracker.captureException(error, {
tags: {
errorType: error.type,
errorCode: error.code
},
extra: {
requestId: error.requestId,
context
}
});
}
Common error scenarios
Creating duplicate resources
// Request
POST /api/customers
{
"email": "existing@example.com",
"name": "John Doe"
}
// Response: 409 Conflict
{
"error": {
"type": "conflict_error",
"message": "Customer with this email already exists",
"code": "customer_already_exists",
"field": "email"
}
}
Invalid subscription state changes
// Request: Cancel already canceled subscription
DELETE /api/subscriptions/sub_123
// Response: 422 Unprocessable Entity
{
"error": {
"type": "validation_error",
"message": "Cannot cancel subscription in 'canceled' state",
"code": "invalid_subscription_state"
}
}
Payment method failures
// Request
POST /api/payments
{
"amount": 5000,
"currency": "USD",
"payment_method": "pm_declined_card"
}
// Response: 402 Payment Required
{
"error": {
"type": "payment_error",
"message": "Your card was declined",
"code": "card_declined",
"payment_error": {
"decline_code": "generic_decline",
"issuer_message": "Do not honor"
}
}
}
SDK error handling
Official SDKs provide structured error objects:
Node.js
import { GetPaidHQError } from '@getpaidhq/node';
try {
const customer = await getpaidhq.customers.create(data);
} catch (error) {
if (error instanceof GetPaidHQError) {
console.log('Error type:', error.type);
console.log('Error code:', error.code);
console.log('Request ID:', error.requestId);
}
}
Python
from getpaidhq import GetPaidHQError
try:
customer = client.customers.create(**data)
except GetPaidHQError as e:
print(f"Error type: {e.type}")
print(f"Error code: {e.code}")
print(f"Request ID: {e.request_id}")
Getting help
When contacting support about errors:
- Include the request ID from the error response
- Provide the full error response (remove sensitive data)
- Describe what you were trying to accomplish
- Include relevant request parameters (remove sensitive data)
The request ID helps our support team quickly locate the specific API call in our logs for faster resolution.