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

# API Usage

> Authenticate and interact with the LinguLink REST API.

The public REST API lives under `/api/v1` and is authenticated with an API key.

## Base URL

```txt theme={null}
https://linguolink.dev/api/v1
```

> The base URL follows your deployment's `NEXT_PUBLIC_APP_URL`. On a self-hosted
> instance, replace the host accordingly.

## Authentication

Send your API key as a Bearer token:

```http theme={null}
Authorization: Bearer YOUR_API_KEY
```

API keys are prefixed with `ll_` followed by 64 hex characters. The full key is
shown only once at creation time — see [API Keys](/api/api-keys).

## Quick Test

```bash theme={null}
curl -H "Authorization: Bearer YOUR_API_KEY" \
  https://linguolink.dev/api/v1/test
```

Returns the authenticated key's name, organization, scopes, rate limit, and
usage count.

## Pull Example

```bash theme={null}
curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://linguolink.dev/api/v1/pull?project_id=YOUR_PROJECT_ID&language=en&format=json" \
  -o ./locales/en.json
```

The response is returned as a downloadable file (`Content-Disposition: attachment`).

## Available Endpoints

```txt theme={null}
GET  /api/v1/test                                            # verify authentication (no scope required)
GET  /api/v1/project                                         # authenticated key/org info (no scope required)
GET  /api/v1/project?project_id=...                          # project details: base language, target languages
GET  /api/v1/projects                                        # scope: translations:read — list every project in your org
GET  /api/v1/pull?project_id=...&language=en&format=json     # scope: export:read
POST /api/v1/push                                            # scope: translations:write — see Import Translations
GET  /api/v1/jobs/{jobId}                                     # scope: translations:read — poll a background import job
GET  /api/v1/coverage?project_id=...                          # scope: translations:read — per-locale completeness
GET  /api/v1/api-keys?limit=10&offset=0                      # scope: admin
POST /api/v1/api-keys                                        # scope: admin
```

> `GET /api/v1/export` and `POST /api/v1/import` still work as deprecated
> aliases for `/api/v1/pull` and `/api/v1/push` — existing integrations don't
> break, but point new code at the current names.

> There is currently no public endpoint for editing an individual translation
> by ID. `POST /api/v1/push` creates/updates translations in bulk, keyed by
> key + language — see [Import Translations](/api/import-translations) and the
> [CLI](/api/cli). Per-record editing still happens in the dashboard.

### Pull query parameters

| Parameter      | Required | Description                                                                                    |
| -------------- | -------- | ---------------------------------------------------------------------------------------------- |
| `project_id`   | yes      | Target project UUID                                                                            |
| `language`     | yes      | Locale code (e.g. `en`, `fr`, `en-US`)                                                         |
| `format`       | no       | `json` (default), `csv`, `xliff`, `xml`, or `yaml`                                             |
| `environment`  | no       | Apply environment-specific overrides (see [Environment Overrides](/api/environment-overrides)) |
| `selected_ids` | no       | JSON array of translation IDs to export a subset, e.g. `["id1","id2"]`                         |

## Rate Limiting

Each API key has an hourly request limit (default 1000, configurable 1–10000).
Every response includes:

```txt theme={null}
X-RateLimit-Limit:     total requests allowed per hour
X-RateLimit-Remaining: requests remaining in the current window
X-RateLimit-Reset:     Unix timestamp (seconds) when the window resets
```

## Error Handling

| Status | Meaning                                                          |
| ------ | ---------------------------------------------------------------- |
| `400`  | Missing/invalid parameter (e.g. `project_id` or `language`)      |
| `401`  | Missing, malformed, inactive, expired, or invalid API key        |
| `402`  | Translation quota exceeded (push only)                           |
| `403`  | Key lacks the required scope                                     |
| `404`  | No translations found, or the project doesn't belong to your org |
| `409`  | Conflict (e.g. an API key with that name already exists)         |
| `413`  | Push payload too large (12 MB / 50,000 rows)                     |
| `429`  | Rate limit exceeded — back off until `X-RateLimit-Reset`         |
| `500`  | Internal error                                                   |

Implement retry with exponential backoff for `429` and transient `5xx` failures.

For the full interactive reference, see the API docs at `/api-docs`.

## Next Steps

* Skip the raw HTTP calls with the [CLI](/api/cli)
* Apply this in [Integration Examples](/api/integration-examples)
* Choose output shape in [Export Formats](/api/export-formats)
