Skip to content

Error Codes

This reference covers the error formats, HTTP status codes, and GraphQL error codes you may encounter when using the HappyColis API.


GraphQL Error Format

The HappyColis API follows the GraphQL specification for error responses. Errors are returned in the errors array alongside any partial data. The HTTP status code is always 200 for GraphQL responses — check the errors array to detect failures.

json
{
  "data": null,
  "errors": [
    {
      "message": "Shipment not found",
      "extensions": {
        "code": "NOT_FOUND"
      },
      "path": ["shipment"]
    }
  ]
}
FieldDescription
messageHuman-readable description of the error
extensions.codeMachine-readable error code (see below)
pathThe GraphQL field path where the error occurred

HTTP Status Codes

CodeWhen
200 OKAll GraphQL responses, including those containing errors
400 Bad RequestMalformed JSON body or invalid GraphQL syntax
401 UnauthorizedMissing, expired, or invalid access token (returned by the auth middleware before GraphQL executes)
429 Too Many RequestsRate limit exceeded (see Rate Limiting)
500 Internal Server ErrorUnexpected server-side failure

GraphQL Error Codes

UNAUTHORIZED

The request is missing a valid Authorization header or the token has expired.

Cause: No token provided, token signature invalid, or token past its exp claim.

Solution: Obtain a fresh access token (see Authentication). Implement proactive token refresh ~60 seconds before expiry.

json
{
  "message": "Unauthorized",
  "extensions": { "code": "UNAUTHORIZED" }
}

FORBIDDEN / INSUFFICIENT_SCOPE

The token is valid but lacks the required OAuth scope for the requested operation.

Cause: The access token was issued without the scope needed by the mutation or query (e.g. calling shipmentCreate without create_shipments).

Solution: Re-authenticate with the correct scopes, or contact your administrator to update the client's allowed scopes.

json
{
  "message": "Insufficient scope: create_shipments required",
  "extensions": { "code": "INSUFFICIENT_SCOPE" }
}

NOT_FOUND

The requested resource does not exist or is not accessible to the authenticated organization.

Cause: The ID passed does not correspond to any existing record, or the record belongs to a different organization.

Solution: Verify the resource ID. Ensure you are using the correct organization credentials.

json
{
  "message": "Order not found",
  "extensions": { "code": "NOT_FOUND" }
}

VALIDATION_ERROR

Input data failed validation — a required field is missing, a value is out of range, or the format is incorrect.

Cause: Invalid input in a mutation argument (e.g. malformed UUID, negative quantity, missing required field).

Solution: Review the input against the field definitions in the relevant mutation documentation. Check message for specific field details.

json
{
  "message": "deliveryOrderId is required",
  "extensions": { "code": "VALIDATION_ERROR" }
}

CONFLICT

The operation conflicts with the current state of the resource.

Cause: Attempting an invalid state transition (e.g. completing an already-completed shipment, opening a cancelled order), or a unique constraint violation.

Solution: Query the resource first to check its current state before mutating. Use webhooks to stay in sync with resource state.

json
{
  "message": "Shipment is already in COMPLETED state",
  "extensions": { "code": "CONFLICT" }
}

RATE_LIMITED

Too many requests have been made in a short period.

Cause: Your application exceeded the API rate limit.

Solution: Implement exponential backoff and retry logic. See Rate Limiting for limits and best practices.

json
{
  "message": "Too many requests. Please retry after 30 seconds.",
  "extensions": { "code": "RATE_LIMITED" }
}

INTERNAL_ERROR

An unexpected error occurred on the server side.

Cause: A bug or transient infrastructure issue in the HappyColis platform.

Solution: Retry the request with exponential backoff. If the error persists, contact HappyColis support with the request ID from the response headers.

json
{
  "message": "An internal error occurred. Please try again.",
  "extensions": { "code": "INTERNAL_ERROR" }
}

Token Error Responses

Authentication errors are returned as HTTP 401 responses before GraphQL executes, with a JSON body (not the standard GraphQL error format):

Expired or Invalid Token

json
{
  "statusCode": 401,
  "message": "Unauthorized"
}

Invalid Client Credentials

json
{
  "statusCode": 401,
  "message": "Invalid client ID and/or grant type is not allowed"
}

Invalid Refresh Token

json
{
  "statusCode": 401,
  "message": "Invalid refresh token"
}

Handling Errors in Code

Node.js — Check Both HTTP Status and GraphQL Errors

js
async function gqlRequest(accessToken, query, variables = {}) {
  const response = await fetch('https://api-v3.happycolis.com/graphql', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${accessToken}`,
    },
    body: JSON.stringify({ query, variables }),
  });

  // Auth errors arrive as non-200 HTTP responses
  if (response.status === 401) {
    throw new Error('UNAUTHORIZED: Token expired or invalid');
  }

  if (response.status === 429) {
    const retryAfter = response.headers.get('Retry-After') || '60';
    throw new Error(`RATE_LIMITED: retry after ${retryAfter}s`);
  }

  const result = await response.json();

  // GraphQL errors are in the errors array even when HTTP status is 200
  if (result.errors && result.errors.length > 0) {
    const err = result.errors[0];
    const code = err.extensions?.code || 'UNKNOWN';
    throw Object.assign(new Error(err.message), { code });
  }

  return result.data;
}

// Usage with error handling
try {
  const data = await gqlRequest(accessToken, query, variables);
} catch (err) {
  if (err.code === 'NOT_FOUND') {
    console.warn('Resource does not exist');
  } else if (err.code === 'CONFLICT') {
    console.warn('State conflict — check current resource state');
  } else if (err.code === 'INSUFFICIENT_SCOPE') {
    console.error('Missing OAuth scope — update client permissions');
  } else {
    console.error('Unexpected error:', err.message);
  }
}

Python — Structured Error Handling

python
import requests

class HappyColisError(Exception):
    def __init__(self, message, code=None):
        super().__init__(message)
        self.code = code

def gql_request(access_token, query, variables=None):
    response = requests.post(
        'https://api-v3.happycolis.com/graphql',
        headers={
            'Authorization': f'Bearer {access_token}',
            'Content-Type': 'application/json',
        },
        json={'query': query, 'variables': variables or {}},
    )

    if response.status_code == 401:
        raise HappyColisError('Token expired or invalid', code='UNAUTHORIZED')

    if response.status_code == 429:
        retry_after = response.headers.get('Retry-After', '60')
        raise HappyColisError(f'Rate limited, retry after {retry_after}s', code='RATE_LIMITED')

    result = response.json()

    if 'errors' in result and result['errors']:
        err = result['errors'][0]
        code = err.get('extensions', {}).get('code', 'UNKNOWN')
        raise HappyColisError(err['message'], code=code)

    return result['data']

HappyColis API Documentation