API Documentation
Navigation

Error Codes

Every error response uses the same envelope, carries a stable code, a human-readable message, a request_id you can send to support, and a doc_url linking back to this page.

The error envelope

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid request body",
    "details": { "fieldErrors": { "to_details": ["Required"] } },
    "doc_url": "https://www.generateinvoice.io/docs/errors#validation_error",
    "request_id": "req_a1b2c3d4e5f6a7b8c9d0"
  }
}

The same request_id is also returned as the X-Request-Id response header. Every error response carries it; on successes it is rolling out endpoint by endpoint (invoices first) and is always present in the JSON meta.request_id field.

All error codes

CodeHTTPMeaningHow to fix
UNAUTHORIZED401No API key was provided, or session auth failed.Send your key in the Authorization header: Bearer gi_live_… (or X-API-Key).
INVALID_API_KEY401The key format is wrong or the key does not exist.Keys start with gi_live_ or gi_test_. Copy the full key from Settings → API Keys.
API_KEY_EXPIRED401The key has an expiry date that has passed.Create a new key in the dashboard and rotate your integration.
API_KEY_DISABLED401The key was deactivated.Re-enable it in the dashboard or create a new key.
USER_NOT_FOUND401The account behind the key no longer exists.Contact support@generateinvoice.io with your request_id.
VALIDATION_ERROR400The request body failed validation.Inspect error.details for per-field messages and correct the payload.
USAGE_LIMIT_EXCEEDED403Your monthly document quota is used up.Upgrade your plan, or wait for the next billing period.
RATE_LIMIT_EXCEEDED429Too many API requests this hour for your plan.Honor the Retry-After header, then retry. See Rate Limits.
NOT_FOUND404The requested document or resource does not exist (or is not yours).Check the id — resources are scoped to your account.
INVALID_STATE400/409The operation is not allowed in the document’s current status.Check the document status first (e.g. only quotes in status "sent" can be accepted).
QUOTE_EXPIRED400The quote’s valid_until date has passed.Create a new quote or extend valid_until before converting.
LIMIT_EXCEEDED403A plan limit other than documents (bulk jobs, rows, webhooks) was hit.Reduce the request size or upgrade your plan.
INVALID_REFERENCE400A referenced resource (e.g. related_invoice_id) was not found.Check error.details.field and pass the id of an existing resource you own.
QUEUE_ERROR500A bulk job could not be queued for processing.Retry the request; if it persists, contact support with the request_id.
CANCEL_FAILED500A bulk job cancellation could not be processed.Check the job status; jobs that already completed cannot be cancelled.
FEATURE_DISABLED404The endpoint exists but the feature is not available yet.Nothing to fix — watch the changelog for availability.
INTERNAL_ERROR500Something failed on our side.Retry with backoff. If it persists, email support with the request_id.

Handling errors

Branch on error.code, never on the message text — messages can change, codes are stable. A minimal handler:

const res = await fetch('https://www.generateinvoice.io/api/v1/invoices', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.GENERATEINVOICE_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(payload),
});

const body = await res.json();

if (!body.success) {
  switch (body.error.code) {
    case 'RATE_LIMIT_EXCEEDED': {
      const retryAfter = Number(res.headers.get('Retry-After') ?? 60);
      await new Promise((r) => setTimeout(r, retryAfter * 1000));
      return retry();
    }
    case 'VALIDATION_ERROR':
      console.error('Fix these fields:', body.error.details);
      break;
    default:
      // Log the request_id — support can trace the exact request with it.
      console.error(body.error.code, body.error.request_id);
  }
}

Validation error details

VALIDATION_ERROR responses include a details object with fieldErrors (per-field messages) and formErrors (top-level messages). Line-item errors currently report at the line_items level; per-index paths are on the roadmap.