> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ticketnation.ph/llms.txt
> Use this file to discover all available pages before exploring further.

# Error Handling

> Error codes, the hint system, and troubleshooting guide.

## Error Response Format

All errors follow a consistent format with an optional `hint` field that provides actionable guidance:

```json theme={null}
{
  "error": {
    "code": "NOT_FOUND",
    "message": "Event not found: abc-123",
    "hint": "Check that the event ID is correct and belongs to your organization.",
    "details": []
  },
  "requestId": "req_a1b2c3d4e5f6"
}
```

The `requestId` is unique per request — include it in support tickets for faster debugging.

## Error Codes

| Code               | HTTP Status | Description             | Common Cause                                 |
| ------------------ | ----------- | ----------------------- | -------------------------------------------- |
| `VALIDATION_ERROR` | 400         | Input failed validation | Missing required fields, invalid format      |
| `UNAUTHORIZED`     | 401         | Authentication failed   | Missing/invalid/expired API key              |
| `FORBIDDEN`        | 403         | Not allowed             | Missing scope, IP not in allowlist           |
| `SCOPE_REQUIRED`   | 403         | Specific scope needed   | Key lacks the required scope                 |
| `NOT_FOUND`        | 404         | Resource not found      | Wrong ID, or resource belongs to another org |
| `RATE_LIMITED`     | 429         | Too many requests       | Exceeded rate limit for your tier            |
| `INTERNAL_ERROR`   | 500         | Server error            | Transient failure — retry with backoff       |

## The Hint System

Error responses include a `hint` field with a human-readable suggestion for how to resolve the issue. Hints are tailored to the specific error context.

<AccordionGroup>
  <Accordion title="VALIDATION_ERROR hints">
    ```json theme={null}
    {
      "error": {
        "code": "VALIDATION_ERROR",
        "message": "Validation failed",
        "hint": "The 'dateTime' field must be a valid ISO 8601 date string (e.g., '2025-06-15T18:00:00.000Z').",
        "details": [
          { "field": "name", "message": "name should not be empty" },
          { "field": "dateTime", "message": "dateTime must be a valid ISO 8601 date string" }
        ]
      },
      "requestId": "req_x1y2z3"
    }
    ```
  </Accordion>

  <Accordion title="SCOPE_REQUIRED hints">
    ```json theme={null}
    {
      "error": {
        "code": "SCOPE_REQUIRED",
        "message": "This endpoint requires the 'events:write' scope.",
        "hint": "Update your API key's scopes in the Organizer Dashboard under Settings > API Keys, or create a new key with 'events:write' enabled."
      },
      "requestId": "req_a1b2c3"
    }
    ```
  </Accordion>

  <Accordion title="NOT_FOUND hints">
    ```json theme={null}
    {
      "error": {
        "code": "NOT_FOUND",
        "message": "Event not found: abc-123",
        "hint": "Check that the event ID is correct and belongs to your organization. Use tn.events.list() to see your events."
      },
      "requestId": "req_d4e5f6"
    }
    ```
  </Accordion>

  <Accordion title="RATE_LIMITED hints">
    ```json theme={null}
    {
      "error": {
        "code": "RATE_LIMITED",
        "message": "Rate limit exceeded",
        "hint": "You have exceeded 60 requests per minute. Wait until the X-RateLimit-Reset timestamp before retrying. Consider upgrading to a higher tier for increased limits."
      },
      "requestId": "req_g7h8i9"
    }
    ```
  </Accordion>
</AccordionGroup>

## Validation Errors

When the code is `VALIDATION_ERROR`, the `details` array contains field-level information:

```json theme={null}
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Validation failed",
    "hint": "Fix the fields listed in 'details' and retry your request.",
    "details": [
      { "field": "name", "message": "name should not be empty" },
      { "field": "dateTime", "message": "dateTime must be a valid ISO 8601 date string" }
    ]
  },
  "requestId": "req_x1y2z3"
}
```

## SDK Error Handling

The SDK throws typed `TicketnationError` instances with all fields including `hint`:

```typescript theme={null}
import { TicketnationError } from 'ticketnation-sdk';

try {
  await tn.events.create({ name: '' });
} catch (error) {
  if (error instanceof TicketnationError) {
    console.log(`Code: ${error.code}`);         // 'VALIDATION_ERROR'
    console.log(`Status: ${error.status}`);     // 400
    console.log(`Message: ${error.message}`);   // 'Validation failed'
    console.log(`Hint: ${error.hint}`);         // 'Fix the fields listed in...'
    console.log(`Request ID: ${error.requestId}`);
    console.log(`Details:`, error.details);     // [{ field: 'name', message: '...' }]
  }
}
```

### Complete Error Handler Example

```typescript theme={null}
import { TicketnationError } from 'ticketnation-sdk';

async function safeCreateEvent(params: CreateEventParams) {
  try {
    return await tn.events.createAndPublish(params);
  } catch (error) {
    if (!(error instanceof TicketnationError)) {
      throw error; // Not a Ticketnation error
    }

    switch (error.code) {
      case 'VALIDATION_ERROR':
        console.error('Fix these fields:', error.details);
        if (error.hint) console.error('Hint:', error.hint);
        break;

      case 'UNAUTHORIZED':
        console.error('Check your API key');
        if (error.hint) console.error('Hint:', error.hint);
        break;

      case 'SCOPE_REQUIRED':
        console.error('Missing scope:', error.message);
        if (error.hint) console.error('Hint:', error.hint);
        break;

      case 'RATE_LIMITED':
        console.error('Slow down — retry after a pause');
        if (error.hint) console.error('Hint:', error.hint);
        break;

      case 'NOT_FOUND':
        console.error('Resource not found:', error.message);
        if (error.hint) console.error('Hint:', error.hint);
        break;

      case 'TIMEOUT':
        console.error('Request timed out — retry');
        break;

      case 'NETWORK_ERROR':
        console.error('Check your internet connection');
        break;

      default:
        console.error(`${error.code}: ${error.message}`);
        if (error.hint) console.error('Hint:', error.hint);
    }

    return null;
  }
}
```

## TicketnationError Properties

| Property    | Type   | Description                                              |
| ----------- | ------ | -------------------------------------------------------- |
| `code`      | string | Error code (e.g., `VALIDATION_ERROR`, `NOT_FOUND`)       |
| `status`    | number | HTTP status code (0 for client-side errors like TIMEOUT) |
| `message`   | string | Human-readable error message                             |
| `requestId` | string | Unique request identifier for support                    |
| `details`   | array  | Field-level errors (for `VALIDATION_ERROR`)              |
| `hint`      | string | Actionable suggestion for resolving the error            |

## SDK-Only Error Codes

These codes are generated by the SDK itself, not the API:

| Code            | Status | Description                                  | Fix                                            |
| --------------- | ------ | -------------------------------------------- | ---------------------------------------------- |
| `TIMEOUT`       | 0      | Request exceeded the configured timeout      | Increase `timeout` in config, or check network |
| `NETWORK_ERROR` | 0      | DNS/connection failure                       | Verify `baseUrl` is reachable                  |
| `HTTP_ERROR`    | varies | Server returned error with no parseable body | Transient — retry                              |

## Automatic Retries

The SDK automatically retries on **5xx server errors** with exponential backoff:

* Attempt 1: immediate
* Attempt 2: after 1 second
* Attempt 3: after 2 seconds

**Not retried:** 4xx errors (400, 401, 403, 404, 429) — these are client errors that need to be fixed.

Configure retries:

```typescript theme={null}
const tn = new Ticketnation({
  apiKey: '...',
  retries: 3,   // max retry attempts (default: 2)
});
```

## Rate Limit Headers

Every response includes rate limit information:

| Header                  | Description                           |
| ----------------------- | ------------------------------------- |
| `X-RateLimit-Limit`     | Max requests for your tier            |
| `X-RateLimit-Remaining` | Requests remaining in current window  |
| `X-RateLimit-Reset`     | Unix timestamp when the window resets |

When you hit the limit, the response is `429` with a `RATE_LIMITED` error. Wait until `X-RateLimit-Reset` before retrying.

## Troubleshooting

<AccordionGroup>
  <Accordion title="UNAUTHORIZED on every request">
    * Verify your API key is correct and not expired
    * Check the `api-key` header name (not `Authorization`)
    * Ensure the key has not been deleted from the dashboard
  </Accordion>

  <Accordion title="SCOPE_REQUIRED when calling an endpoint">
    * Check which scope the endpoint needs (see [API Reference](/developers/api-reference))
    * Performers, schedules, and brands require `events:write`
    * Update your API key's scopes in the dashboard, or create a new key with the required scopes
    * Check the `error.hint` for specific guidance
  </Accordion>

  <Accordion title="NOT_FOUND for a resource you created">
    * Events/tickets are scoped to your organization — you can only access resources owned by the org associated with your API key
    * Double-check the UUID format
    * Use `tn.events.list()` to list your events and verify the ID
  </Accordion>

  <Accordion title="Requests timing out">
    * Default timeout is 30 seconds — increase it if needed
    * Check if `baseUrl` is correct (no trailing slash)
    * For local development, use `http://localhost:4000`
  </Accordion>

  <Accordion title="Performers, schedules, or brands returning 403">
    * These resources require the `events:write` scope
    * Create a new API key with `events:write` enabled if your current key does not have it
  </Accordion>
</AccordionGroup>
