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

# Error Handling

> Understand HTTP status codes and the error response structure returned by the API.

# Error Handling

The API uses standard HTTP status codes and returns consistent JSON error bodies for all failure cases.

***

## HTTP status codes

| Code  | Meaning               | Common cause                                         |
| ----- | --------------------- | ---------------------------------------------------- |
| `200` | OK                    | Request succeeded                                    |
| `201` | Created               | Resource was created                                 |
| `204` | No Content            | Resource was deleted                                 |
| `400` | Bad Request           | Malformed request body                               |
| `401` | Unauthorized          | Missing or invalid `Authorization` header            |
| `403` | Forbidden             | Token valid but insufficient permissions             |
| `404` | Not Found             | Resource does not exist or belongs to another tenant |
| `422` | Unprocessable Entity  | Validation failed (see `errors` field)               |
| `429` | Too Many Requests     | Rate limit exceeded                                  |
| `500` | Internal Server Error | Unexpected server error                              |

***

## Error response body

All error responses return a JSON body with `success: false`. The structure varies by error type.

### Validation error (422)

```json theme={null}
{
  "success": false,
  "message": "The given data was invalid.",
  "errors": {
    "email": ["The email field is required.", "The email must be a valid email address."],
    "course_uuid": ["The selected course uuid is invalid."]
  }
}
```

The `errors` object maps field names to an array of human-readable messages.

### Authentication error (401)

```json theme={null}
{
  "success": false,
  "message": "Unauthenticated."
}
```

### Not found (404)

```json theme={null}
{
  "success": false,
  "message": "Resource not found."
}
```

### Generic server error (500)

```json theme={null}
{
  "success": false,
  "message": "Server Error"
}
```

***

## Handling errors in code

<CodeGroup>
  ```javascript JavaScript theme={null}
  async function createCertificate(payload) {
    const response = await fetch('https://api.dokstamp.com/certificates', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${TOKEN}`,
        'Accept': 'application/json',
        'Content-Type': 'application/json',
        'X-Tenant': TENANT,
      },
      body: JSON.stringify(payload),
    });

    if (!response.ok) {
      const error = await response.json();

      if (response.status === 422) {
        // Validation error — inspect error.errors for field-level detail
        console.error('Validation failed:', error.errors);
      } else if (response.status === 401) {
        // Token expired or missing — request a new service token
        await renewToken();
      } else {
        throw new Error(error.message);
      }
    }

    return response.json();
  }
  ```

  ```php PHP theme={null}
  use Illuminate\Support\Facades\Http;

  $response = Http::withToken($token)
      ->withHeaders(['X-Tenant' => $tenant, 'Accept' => 'application/json'])
      ->post('https://api.dokstamp.com/certificates', $payload);

  if ($response->failed()) {
      $error = $response->json();

      if ($response->status() === 422) {
          // Field-level validation errors
          foreach ($error['errors'] as $field => $messages) {
              logger()->warning("$field: " . implode(', ', $messages));
          }
      }

      throw new RuntimeException($error['message'] ?? 'API error');
  }

  $certificate = $response->json('data');
  ```
</CodeGroup>

***

## Common mistakes

<AccordionGroup>
  <Accordion title="Missing X-Tenant header">
    Returns `401` or `404` depending on the endpoint. Always include `X-Tenant` on resource endpoints.
  </Accordion>

  <Accordion title="File already in use">
    When creating a certificate, the `file_uuid` must reference a file that has not yet been attached to another certificate. Once a file is used, it cannot be reused.
  </Accordion>

  <Accordion title="Wrong UUID format">
    All UUID fields must be in standard v4 format: `550e8400-e29b-41d4-a716-446655440000`. Passing an integer where a UUID is expected returns `422`.
  </Accordion>

  <Accordion title="Referencing entities from another tenant">
    If you pass a `course_uuid` or `student_uuid` that belongs to a different tenant, the API returns `422` with `"The selected ... is invalid."` — the entity lookup is always tenant-scoped.
  </Accordion>
</AccordionGroup>
