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

# Errors

> Error codes and handling in the Widgetic API

The Widgetic API uses standard HTTP status codes and returns detailed error information in the response body. All errors follow a consistent format with machine-readable codes, human-readable messages, and actionable guidance.

## Error Response Format

```json theme={null}
{
  "success": false,
  "error": {
    "code": "AUTH_TOKEN_EXPIRED",
    "message": "The authentication token has expired",
    "correlationId": "req_123e4567-e89b-12d3-a456-426614174000",
    "timestamp": "2024-01-15T10:30:00.000Z",
    "docUrl": "https://docs.widgetic.com/docs/authentication",
    "suggestedAction": "Refresh your authentication token"
  }
}
```

| Field | Description |
| - | - |
| `code` | Machine-readable error code (use this for programmatic handling) |
| `message` | Human-readable error description |
| `correlationId` | Unique request ID for support inquiries |
| `timestamp` | ISO 8601 timestamp when the error occurred |
| `docUrl` | Link to relevant documentation |
| `suggestedAction` | Recommended action to resolve the error |

## HTTP Status Codes

| Status | Category | Description |
| - | - | - |
| 200 | Success | Request succeeded |
| 201 | Success | Resource created |
| 204 | Success | No content (successful deletion) |
| 400 | Client Error | Bad request / Validation error |
| 401 | Client Error | Authentication required or failed |
| 402 | Client Error | Payment required (credits/subscription) |
| 403 | Client Error | Forbidden (insufficient permissions) |
| 404 | Client Error | Resource not found |
| 409 | Client Error | Conflict (resource already exists) |
| 410 | Client Error | Gone (resource permanently removed) |
| 413 | Client Error | Payload too large (quota exceeded) |
| 422 | Client Error | Unprocessable entity (business logic error) |
| 429 | Client Error | Rate limit exceeded |
| 500 | Server Error | Internal server error |
| 502 | Server Error | Bad gateway (external service error) |
| 503 | Server Error | Service unavailable |
| 504 | Server Error | Gateway timeout |

***

## Error Code Reference

### Authentication Errors (401)

Errors related to verifying your identity.

| Code | Message | Suggested Action |
| - | - | - |
| `AUTH_REQUIRED` | Authentication required to access this resource | Provide valid authentication credentials |
| `AUTH_TOKEN_INVALID` | The provided authentication token is invalid | Provide a valid authentication token |
| `AUTH_TOKEN_EXPIRED` | The authentication token has expired | Refresh your authentication token |
| `AUTH_TOKEN_MALFORMED` | The authentication token is malformed | Ensure the token is properly formatted |
| `AUTH_CREDENTIALS_INVALID` | The provided credentials are invalid | Verify your username and password |
| `AUTH_API_KEY_INVALID` | The provided API key is invalid | Verify your API key is correct and active |
| `AUTH_API_KEY_EXPIRED` | The API key has expired | Generate a new API key or renew the existing one |

### Authorization Errors (403)

Errors related to permissions and access control.

| Code | Message | Suggested Action |
| - | - | - |
| `AUTHZ_INSUFFICIENT_PERMISSIONS` | You do not have permission to perform this action | Contact your administrator to request the necessary permissions |
| `AUTHZ_RESOURCE_ACCESS_DENIED` | You do not have permission to access this resource | Ensure you have the correct permissions for this resource |
| `AUTHZ_ORGANIZATION_ACCESS_DENIED` | You do not have permission to access this organization | Contact the organization owner for access |
| `AUTHZ_PLAN_RESTRICTION` | This feature is not available on your current plan | Upgrade your plan to access this feature |

#### Plan restrictions

Advanced analytics, A/B testing, translations and inviting teammates are part of the Teams plan. A request for one of them from an account on another plan fails with `AUTHZ_PLAN_RESTRICTION`, and the response says which capability was needed and what would unlock it:

```json theme={null}
{
  "success": false,
  "error": {
    "code": "AUTHZ_PLAN_RESTRICTION",
    "message": "A/B testing is part of the Teams plan. Upgrade to Teams to use it.",
    "details": {
      "feature": "experiments.ab_testing",
      "upgradeTo": "teams"
    },
    "correlationId": "req_123e4567-e89b-12d3-a456-426614174000"
  }
}
```

| `details` field | Description |
| - | - |
| `feature` | The capability the request needed: `analytics.advanced`, `experiments.ab_testing`, `experiments.translations` or `team.collaboration` |
| `upgradeTo` | The plan that includes it (`"teams"`), or `null` when buying a plan would not help. `null` is what a member of a team whose subscription has lapsed receives: the team's owner has to update billing |

### Validation Errors (400)

Errors related to request format and data validation.

| Code | Message | Suggested Action |
| - | - | - |
| `VALIDATION_FIELD_REQUIRED` | A required field is missing | Provide all required fields in your request |
| `VALIDATION_FIELD_INVALID` | A field contains an invalid value | Check the field format and try again |
| `VALIDATION_FIELD_TYPE_MISMATCH` | A field has an incorrect data type | Ensure the field matches the expected data type |
| `VALIDATION_FIELD_LENGTH` | A field exceeds the maximum allowed length | Reduce the field length to meet the requirements |
| `VALIDATION_JSON_MALFORMED` | The request body contains malformed JSON | Ensure your JSON is properly formatted |
| `VALIDATION_SCHEMA_VIOLATION` | The request does not match the expected schema | Review the API schema and adjust your request |

### Resource Errors (404, 409, 410)

Errors related to resource existence and conflicts.

| Code | Status | Message | Suggested Action |
| - | - | - | - |
| `RESOURCE_NOT_FOUND` | 404 | The requested resource was not found | Verify the resource ID and try again |
| `RESOURCE_WIDGET_NOT_FOUND` | 404 | The specified widget was not found | Check the widget ID and ensure it exists |
| `RESOURCE_COMPOSITION_NOT_FOUND` | 404 | The specified composition was not found | Check the composition ID and ensure it exists |
| `RESOURCE_ORGANIZATION_NOT_FOUND` | 404 | The specified organization was not found | Check the organization ID and ensure it exists |
| `RESOURCE_USER_NOT_FOUND` | 404 | The specified user was not found | Check the user ID and ensure it exists |
| `RESOURCE_ALREADY_EXISTS` | 409 | A resource with the same identifier already exists | Use a different identifier or update the existing resource |
| `RESOURCE_GONE` | 410 | The requested resource is no longer available | This resource has been permanently removed |

### Rate Limiting Errors (429)

Errors related to request frequency limits.

| Code | Message | Suggested Action | Retry-After |
| - | - | - | - |
| `RATE_LIMIT_EXCEEDED` | Rate limit exceeded | Wait before making more requests | 60s |
| `RATE_LIMIT_API_KEY_EXCEEDED` | API key rate limit exceeded | Wait before making more requests or upgrade your plan | 60s |
| `RATE_LIMIT_USER_EXCEEDED` | User rate limit exceeded | Wait before making more requests | 60s |
| `RATE_LIMIT_WEBHOOK_EXCEEDED` | Webhook rate limit exceeded | Check your webhook configuration and reduce frequency | 60s |

> [!TIP]
>
> When you receive a 429 response, check the `Retry-After` header for the number of seconds to wait before retrying.

### Quota Errors (402, 413, 429)

Errors related to usage limits and billing.

| Code | Status | Message | Suggested Action |
| - | - | - | - |
| `QUOTA_CREDITS_EXHAUSTED` | 402 | Your credit quota has been exhausted | Purchase additional credits or upgrade your plan. A partner account buys extra credits by invoice: see [Getting More Credits](https://widgetic.com/docs/partners/credits-billing.md#getting-more-credits) |
| `QUOTA_STORAGE_EXCEEDED` | 413 | Storage quota exceeded | Delete some files or upgrade your storage plan |
| `QUOTA_API_CALLS_EXCEEDED` | 429 | Monthly API call quota exceeded | Upgrade your plan or wait for quota reset |

### Business Logic Errors (409, 422)

Errors related to business rules and state conflicts.

| Code | Status | Message | Suggested Action |
| - | - | - | - |
| `BUSINESS_OPERATION_INVALID` | 422 | The requested operation is not valid in the current context | Review the operation requirements and current state |
| `BUSINESS_STATE_CONFLICT` | 409 | The operation conflicts with the current resource state | Refresh the resource state and try again |
| `CONFLICT_IDEMPOTENCY_IN_PROGRESS` | 409 | A request with this idempotency key is still being processed | Wait for the `Retry-After` seconds, then retry with the **same** `Idempotency-Key` |
| `CONFLICT_IDEMPOTENCY_ANSWER_UNAVAILABLE` | 409 | This request was already carried out, but its answer is no longer available to replay | Do not send it again under this `Idempotency-Key`. Read the current state of what it changed; if it is safe to repeat, repeat it under a new key |
| `BUSINESS_WIDGET_ALREADY_PUBLISHED` | 409 | The widget is already published | Unpublish the widget first or create a new version |
| `BUSINESS_SUBSCRIPTION_REQUIRED` | 402 | A subscription is required to perform this action | Subscribe to a plan to access this feature |

### Partner Errors (402, 403, 404, 409, 422, 429, 502, 503)

Errors a [partner integration](https://widgetic.com/docs/partners/overview.md) meets: the standing of the account, its storage, its customers and what they may spend. Branch on `error.code`; `error.details` carries the machine-readable facts. Each page of the guide lists the errors of its own calls too.

| Code | Status | Meaning | Read more |
| - | - | - | - |
| `API_KEY_SCOPE_MISSING` | 403 | The key is limited to some scopes and the request needs more. `details.missingScopes` lists them, and `details.fullAccessRequired` is `true` when only a key with full access would do | [Limit What a Key Can Do](https://widgetic.com/docs/authentication.md#limit-what-a-key-can-do) |
| `PARTNER_SUSPENDED` | 403 | The partner account is paused. `details.partnerStatus` and `details.reason` say why | [Account Status](https://widgetic.com/docs/partners/account-status.md) |
| `PARTNER_PAYMENT_ARREARS` | 403 | An invoice of the partner's contract is unpaid after its due date. `details.partnerStatus` is `payment_arrears` and `details.overdueSince` is the due date of the oldest unpaid one. Paying it ends the stop | [Account Status](https://widgetic.com/docs/partners/account-status.md) |
| `PARTNER_INACTIVE` | 403 | The partner account has not been activated yet | [Account Status](https://widgetic.com/docs/partners/account-status.md#getting-activated) |
| `EDITOR_SESSIONS_DISABLED_FOR_PARTNER` | 403 | Widgetic switched editor sessions off for this account alone | [Editor Sessions](https://widgetic.com/docs/partners/editor-sessions.md#settings-that-can-differ-for-your-account) |
| `PARTNER_STORAGE_REQUIRED` | 409 | The call needs the partner's own storage destination and there is none | [Storage](https://widgetic.com/docs/partners/storage.md) |
| `STORAGE_DESTINATION_UNVERIFIED` | 422 | The check of a storage destination failed. `details.step` and `details.reason` say where and why | [Storage](https://widgetic.com/docs/partners/storage.md#the-check) |
| `STORAGE_DESTINATION_WRITE_FAILED` | 502 | The partner's bucket rejected a file | [Storage](https://widgetic.com/docs/partners/storage.md) |
| `STORAGE_DESTINATION_UNAVAILABLE` | 503 | A destination is saved but cannot be used | [Storage](https://widgetic.com/docs/partners/storage.md) |
| `PARTNER_STORAGE_DISABLED` | 503 | Storage destinations are not switched on for the server | [Storage](https://widgetic.com/docs/partners/storage.md) |
| `PARTNER_STORAGE_NOT_SOLD` | 403 | Extra Widgetic storage is not sold to partner accounts: a partner's files are kept in its own storage destination and use no Widgetic storage | [Credits & Billing](https://widgetic.com/docs/partners/credits-billing.md#storage) |
| `WEBHOOK_SIGNING_UNAVAILABLE` | 503 | The server cannot sign webhooks yet | [Notifications](https://widgetic.com/docs/partners/notifications.md) |
| `MANAGED_USER_NOT_FOUND` | 404 | The managed user is not one of the partner's | [Managed Users](https://widgetic.com/docs/partners/managed-users.md) |
| `MANAGED_USER_INACTIVE` | 409 | The managed user is switched off | [Managed Users](https://widgetic.com/docs/partners/managed-users.md) |
| `BILLING_INSUFFICIENT_CREDITS` | 402 | The partner account does not have the credits for the action | [Credits & Billing](https://widgetic.com/docs/partners/credits-billing.md) |
| `EDITOR_SESSION_CREDIT_LIMIT_REACHED` | 402 | An editor session spent the `max_credits` it was given | [Editor Sessions](https://widgetic.com/docs/partners/editor-sessions.md#a-limit-for-one-session) |
| `COST_LIMIT_EXCEEDED` | 429 | A customer used up their allowance for the hour or the day | [Editor Sessions](https://widgetic.com/docs/partners/editor-sessions.md#credits-and-limits) |

### External Service Errors (502, 503, 504)

Errors related to third-party dependencies.

| Code | Status | Message | Retry-After |
| - | - | - | - |
| `EXTERNAL_SERVICE_UNAVAILABLE` | 503 | An external service is temporarily unavailable | 300s |
| `EXTERNAL_SERVICE_TIMEOUT` | 504 | An external service request timed out | 60s |

### System Errors (500, 503)

Internal system errors.

| Code | Status | Message | Suggested Action |
| - | - | - | - |
| `SYSTEM_INTERNAL_ERROR` | 500 | An internal server error occurred | Contact support if the problem persists |
| `SYSTEM_MAINTENANCE` | 503 | The system is temporarily under maintenance | Try again later |
| `SERVICE_UNAVAILABLE` | 503 | The service is temporarily unavailable | Try again later |
| `SERVICE_DEGRADED` | 503 | The service is experiencing degraded performance | Some features may be slower than usual |

***

## Handling Errors

### JavaScript/TypeScript

The SDK throws a `ResponseError` for every answer that is not a success. The HTTP status is `error.response.status`, the response headers are `error.response.headers`, and the body is the error format shown above: read it with `await error.response.json()`. `error.code` holds the machine-readable `code` from that body.

```javascript theme={null}
import { CompositionsApi, ResponseError } from '@widgetic/api-sdk-ts';

const compositions = new CompositionsApi('YOUR_API_KEY');

try {
  const composition = await compositions.getCompositionById({
    id: '123e4567-e89b-12d3-a456-426614174000'
  });
} catch (error) {
  // Anything that is not a ResponseError is not an answer from the API (for example, a network failure)
  if (!(error instanceof ResponseError)) throw error;

  // The body is the error format above. It may be missing if something in front of the API answered
  const errorBody = (await error.response.json().catch(() => null))?.error;

  switch (error.response.status) {
    case 401:
      console.log('Authentication failed:', errorBody?.code);
      // Re-authenticate or refresh token
      break;
    case 403:
      console.log('Access denied:', errorBody?.suggestedAction);
      break;
    case 404:
      console.log('Resource not found');
      break;
    case 429: {
      const retryAfter = error.response.headers.get('Retry-After') ?? 60;
      console.log(`Rate limited. Retry after ${retryAfter} seconds`);
      break;
    }
    default:
      console.error('Error:', errorBody?.message);
      console.error('Correlation ID:', errorBody?.correlationId);
  }
}
```

### Using Correlation IDs

Every error response includes a `correlationId`. Include this when contacting support:

```javascript theme={null}
catch (error) {
  if (!(error instanceof ResponseError)) throw error;

  const errorBody = (await error.response.json().catch(() => null))?.error;
  const correlationId = errorBody?.correlationId;
  console.error(`Error [${correlationId}]:`, errorBody?.message);
  
  // Log for support requests
  logger.error('API Error', {
    correlationId,
    code: errorBody?.code,
    status: error.response.status
  });
}
```

***

## Retry Strategies

### Exponential Backoff

For transient errors (429, 503, 504), implement exponential backoff:

```javascript theme={null}
import { ResponseError } from '@widgetic/api-sdk-ts';

async function withRetry(fn, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await fn();
    } catch (error) {
      // Only an answer from the API carries a status; anything else is thrown as it is
      if (!(error instanceof ResponseError)) throw error;

      const isRetryable = [429, 503, 504].includes(error.response.status);
      
      if (isRetryable && attempt < maxRetries - 1) {
        const retryAfter = error.response.headers.get('Retry-After');
        const delay = retryAfter 
          ? parseInt(retryAfter, 10) * 1000 
          : Math.pow(2, attempt) * 1000; // 1s, 2s, 4s
        
        console.log(`Retrying in ${delay}ms (attempt ${attempt + 1})`);
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }
      throw error;
    }
  }
}

const composition = await withRetry(() => 
  compositions.getCompositionById({ id: 'composition-id' })
);
```

### Idempotent Retries

For POST/PUT operations, use idempotency keys to safely retry:

```javascript theme={null}
import { randomUUID } from 'node:crypto';
import { WidgetsApi } from '@widgetic/api-sdk-ts';

const widgets = new WidgetsApi('YOUR_API_KEY');

// One key for the operation: every retry sends the same one
const idempotencyKey = randomUUID();

const widget = await withRetry(() => 
  widgets.createWidget({
    idempotencyKey,
    newWidget: { name: 'My Widget', type: 'chart', content: {} }
  })
);
```

> [!NOTE]
>
> See [Idempotency](https://widgetic.com/docs/reference/idempotency.md) for more details on safe retries.

> [!NOTE]
>
> A `409` with the code `CONFLICT_IDEMPOTENCY_IN_PROGRESS` means your earlier request with the same key is still running. It is safe to retry: wait for the `Retry-After` header and resend with the **same** key. A `409` with the code `CONFLICT_IDEMPOTENCY_ANSWER_UNAVAILABLE` means that request already succeeded and was **not** run again, but its response can no longer be returned: do not retry it with the same key; see [When the stored response is no longer available](https://widgetic.com/docs/reference/idempotency.md#when-the-stored-response-is-no-longer-available). Any other `409` is not retryable as-is.

***

## Best Practices

> [accordion] Always Handle Errors
>
> Never assume API calls will succeed. Always wrap calls in try/catch and handle specific error codes.

> [accordion] Log Correlation IDs
>
> Store correlation IDs in your logs for debugging and include them in support requests for faster resolution.

> [accordion] Implement Backoff for Rate Limits
>
> For rate limiting (429), use exponential backoff with jitter. Always check the `Retry-After` header.

> [accordion] Validate Before Sending
>
> Validate data client-side before making API calls to catch validation errors early and reduce unnecessary requests.

> [accordion] Handle Plan Restrictions Gracefully
>
> When you receive `AUTHZ_PLAN_RESTRICTION` or `QUOTA_*` errors, provide users with clear upgrade paths or alternatives.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.