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

# Requests & Responses

> Request format, response structure, and error handling for the Gumnut API

This page covers the request and response formats used across the Gumnut API.

## Request Format

### Headers

All requests should include:

```http theme={null}
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
```

For file uploads, use `multipart/form-data`:

```http theme={null}
Authorization: Bearer YOUR_API_KEY
Content-Type: multipart/form-data
```

### Request Body

Send JSON payloads for most endpoints:

```json theme={null}
{
  "name": "Summer Vacation 2024",
  "description": "Photos from our trip to Hawaii"
}
```

### Query Parameters

Use query parameters for filtering, pagination, and opt-in expansions:

```http theme={null}
GET /api/assets?limit=50&library_id=lib_123&include=metadata&include=variants
```

### Asset expansions with `include`

Asset responses are intentionally lean by default. Pass `include` when you need additional fields:

* `metadata` for camera, EXIF, GPS, and location fields
* `faces` for automatic and manual face boxes
* `people` for deduplicated people records
* `metrics` for ML-generated quality scores
* `file_data` for device IDs, timestamps, checksums, and file size
* `variants` for non-thumbnail `asset_urls` rungs such as `small`, `preview`, `fullsize`, and `original`. For video assets, the rendered-image rungs use `_image` suffixes such as `thumbnail_image` and `preview_image`, while `original` stays the playable video file.

You can repeat `include` or send a comma-delimited value. For example, `include=faces&include=people` and `include=faces,people` are equivalent.

When present, each face row includes a `source` field so you can distinguish `automatic` detections from `manual` user-drawn boxes.

If your client renders anything larger than the default thumbnail, or offers a download-original action, request `include=variants`. The API reference already marks those richer `asset_urls` fields as opt-in, so sending the token keeps your integration aligned with the lean response model.

If you expose a browser download button, link to `asset_urls.original.url`. A plain top-level navigation or `<a href>` saves the original file with its original filename. The same URL still works for inline video playback and `fetch` requests, so you do not need a separate download-only field.

## Response Format

### Successful Responses

Successful requests return JSON with appropriate HTTP status codes:

```json theme={null}
{
  "id": "asset_abc123",
  "mime_type": "image/jpeg",
  "original_file_name": "photo.jpg",
  "local_datetime": "2024-07-15T12:00:00",
  "created_at": "2024-07-15T19:04:12Z",
  "asset_urls": {
    "thumbnail": {
      "url": "...",
      "mimetype": "image/webp"
    }
  },
  "metadata": null,
  "faces": null,
  "people": null
}
```

Expanded fields stay `null` or absent until you request them with `include`.

### Asset timestamp fields

Gumnut uses different timestamps for different jobs:

* `local_datetime` is Gumnut's best local capture timestamp for the asset.
* If Gumnut knows the capture offset, `local_datetime` includes it, for example `2024-07-15T12:00:00-07:00`.
* If the source only records a wall-clock capture time and not its offset, `local_datetime` is returned without a timezone suffix, for example `2024-07-15T12:00:00`.
* If the upload has no embedded capture datetime, Gumnut can derive `local_datetime` from file timestamps instead of echoing raw UTC file time, so the asset still lands on the expected local calendar day.
* `created_at` is when Gumnut created the asset record. It is not the capture time.
* `file_data.file_created_at` and `file_data.file_modified_at` describe the uploaded file on the source device. Request them with `include=file_data` when you need file-level timestamps or when you need to compare the raw file time with Gumnut's inferred `local_datetime`.

```json theme={null}
{
  "local_datetime": "2024-07-15T12:00:00",
  "created_at": "2024-07-15T19:04:12Z",
  "file_data": {
    "file_created_at": "2024-07-15T12:03:44-07:00",
    "file_modified_at": "2024-07-15T12:05:10-07:00"
  }
}
```

Use `local_datetime` when you want to group or filter by when an asset was captured. Use `created_at` when you need to track when the asset record arrived in Gumnut.

Status codes:

* `200 OK` - Request succeeded
* `201 Created` - Resource created
* `204 No Content` - Request succeeded with no content

### Error Responses

Errors return a consistent JSON structure:

```json theme={null}
{
  "error": {
    "code": "validation_error",
    "message": "Invalid request parameters",
    "details": {
      "field": "album_name",
      "issue": "Required field missing"
    }
  }
}
```

Status codes:

* `400 Bad Request` - Invalid request
* `401 Unauthorized` - Authentication required
* `403 Forbidden` - Insufficient permissions
* `404 Not Found` - Resource not found
* `429 Too Many Requests` - Rate limit exceeded (see [Rate Limiting](./rate-limiting))
* `500 Internal Server Error` - Server error

## Best Practices

### Error Handling

* Implement exponential backoff for retries on 429 and 5xx errors
* Handle rate limits gracefully using the `Retry-After` header (see [Rate Limiting](./rate-limiting))
* Log errors with the request ID for debugging
* Validate input before sending requests

### Security

* Never expose API keys in client-side code
* Use HTTPS for all requests
* Implement proper [authentication flows](../authentication/overview)
