Error Handling & Status Codes

When working with the Pennylane API, you may encounter validation issues, missing permissions, or temporary rate limits. This guide explains how errors are returned, what the most common status codes mean, and how to handle them efficiently in your integration.

Pennylane uses standard HTTP status codes and a consistent JSON error schema, making failures predictable and easy to debug.

How Errors Are Structured

All errors returned by the API include:

  • an HTTP status code
  • a JSON error payload
  • optional details to help identify the field or rule causing the failure

Example:

{
  "error": "unprocessable_entity",
  "message": "Missing required field: customer_id",
  "details": {
    "field": "customer_id",
    "issue": "is required"
  }
}
💡

Tip: The details object is the most actionable part of the response for debugging validation errors `(422)``.

Most issues can be resolved by inspecting it carefully.

HTTP Status Code Families

Before diving into individual codes, here is how to interpret the main categories:

FamilyMeaningWhen it Happens
2xxSuccessThe request is valid and processed
4xxClient errorSomething must be fixed in the request
5xxServer errorTemporary issue on Pennylane’s side

HTTP Status Codes Overview

2xx - Success

CodeMeaning
200 OKThe request succeeded.
201 CreatedA new resource was created (invoice, ledger entry, attachment).
204 No ContentThe request succeeded without a response body (e.g., sending an invoice by email).

4xx - Client Errors

Errors caused by problems in your request: missing token, invalid scope, malformed payload, etc.

400 - Bad Request

Your request payload contains invalid or missing data.

Typical causes:

  • invalid JSON format
  • wrong field type (e.g., number instead of string)
  • unsupported field
  • amounts not sent as strings (e.g., "120.00")

How to fix: Validate your payload before sending it.

401 - Unauthorized

The access token is missing, invalid, or expired.

How to fix:

  • check the Authorization: Bearer <TOKEN> header
  • refresh or regenerate the token
  • ensure you’re using the correct token type (Company / Firm / OAuth)
403 - Forbidden

Your token is valid but does not include the required scope.

How to fix:

Regenerate a token that includes the missing scope (e.g., customer_invoices:all).

404 - Not Found

The resource does not exist or cannot be accessed.

Typical causes:

  • wrong or outdated ID
  • incorrect endpoint
  • accessing a record belonging to a different company
409 - Conflict

Your request conflicts with existing data.

Common example:

Importing a supplier or customer invoice using a PDF already present in Pennylane.

How to fix:

Avoid reusing the same file_attachment_id.

Only import each document once (idempotency is not enforced except for supplier invoice imports).

422 - Unprocessable Entity

The request is syntactically correct but violates a business validation rule.

Typical causes:

  • totals or VAT mismatch
  • unbalanced ledger entry lines
  • invalid VAT code
  • missing required business field
  • duplicate references in invoice creation

How to fix:

Inspect the response’s details field and correct the payload.

429 - Too Many Requests

You exceeded the API’s rate limit.

How to fix:

  • implement retry logic
  • respect the Retry-After header
  • reduce request bursts

5xx - Server Errors

These errors are rare and typically temporary.

CodeMeaning
500 Internal Server ErrorUnexpected server failure.
503 Service UnavailableTemporary outage or maintenance.

How to fix: Retry with exponential backoff.

Understanding the Error Payload

Most error responses include:

FieldDescription
errorMachine-readable code (unprocessable_entity, forbidden, etc.)
messageHuman-readable explanation
detailsAdditional context (invalid field, totals mismatch, duplicate reference):

Missing scope

{
  "error": "forbidden",
  "message": "Missing scope: customer_invoices:all"
}

Unbalanced ledger entry

{
  "error": "unprocessable_entity",
  "message": "Entry lines are not balanced",
  "details": {
    "debit_total": "100.00",
    "credit_total": "80.00"
  }
}

Duplicate supplier invoice

{
  "status": 409,
  "error": "A document with ID 2058167880 already exists with such attachment."
}

How Pennylane Validates Requests

To ensure data consistency across accounting and invoicing workflows, Pennylane performs:

  • schema validation (field types, required objects, JSON structure)
  • business validation (totals, VAT rates, date rules, ledger balance)

Most 422 errors originate from the second category.

Handling Errors in Your Integration

1. Validate before submitting

To avoid 400/422 responses:

  • check required fields
  • validate totals and VAT consistency
  • ensure debit/credit lines balance
  • use strings for all amount fields (e.g., "120.00")
  • verify that entity IDs exist before referencing them

2. Implement safe retry logic

Retry only when appropriate:

Should retry?Status codesReason
✅ Yes429, 500, 503Temporary or rate-limited errors
❌ No400, 401, 403, 404, 422Requires fixing the request

3. Avoid duplicate POST requests

Pennylane does not enforce idempotency on creation endpoints such as:

  • /customer_invoices
  • /ledger_entries

If the same request is sent twice, you may create duplicates.

4. Log full error bodies

Always store:

  • the status code
  • error and message
  • details (whenever available)

This makes debugging significantly easier.