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

# REST API

> Automate OrbitLab over HTTPS with API tokens.

The OrbitLab API gives programmatic access to everything you manage in the dashboard: services and deployments, environment variables, logs and metrics, domains and DNS, databases, files, WordPress tools, organizations, orders and renewals. The [CLI](/cli) is built on it.

Browse every endpoint in the **API reference** section of the sidebar.

## Base URL

```
https://orbitlab.dev/api/v1
```

Requests and responses use JSON unless an endpoint says otherwise (logs are `text/plain`, invoices are PDF, uploads use `multipart/form-data`).

## Authentication

Authenticate with an API token in the `Authorization` header:

```bash theme={null}
curl https://orbitlab.dev/api/v1/user \
  -H "Authorization: Bearer $ORBITLAB_TOKEN"
```

### Create a token

1. Open **Dashboard → Settings → API tokens**.
2. Click **Create token**, give it a name, and choose:
   * **Scope**: all your organizations, or a single one.
   * **Expiration**: 30, 90 or 365 days, or none.
3. Copy the token. It starts with `olab_` and is only shown once.

`orbitlab login` creates a token for the CLI the same way, after you approve it in the browser. Tokens created by the CLI expire after 90 days.

A token acts with your permissions: it can do what your role allows in each organization. OrbitLab only stores a hash of the token. Revoke tokens you no longer use from the same page, or with `DELETE /v1/tokens/{id}`. Tokens stop working immediately when revoked, when they expire, or when you leave the organization they're scoped to.

<Warning>
  Treat tokens like passwords: store them in your CI's secret store, never in your repository.
</Warning>

### Dashboard-only actions

For security, some actions require signing in to the dashboard and can't be done with a token: creating tokens, deleting your account, unlinking sign-in methods and installing the GitHub App.

## Organizations

Resources belong to organizations. Requests act on your first organization unless you choose another with the `X-OrbitLab-Org` header (organization id or slug):

```bash theme={null}
curl https://orbitlab.dev/api/v1/services \
  -H "Authorization: Bearer $ORBITLAB_TOKEN" \
  -H "X-OrbitLab-Org: acme"
```

Tokens scoped to one organization always act on it; selecting another organization returns `403`. List your organizations with `GET /v1/organizations`.

Some endpoints require the **owner** or **admin** role, for example reading environment variables and database credentials, editing DNS, or managing members. The API reference lists the role for each endpoint.

## Conventions

* Ids are UUIDs, except plan ids (`app-1`, `starter`…) and DNS record ids.
* Amounts are integers in cents, with a `currency`.
* Dates are ISO 8601 strings in UTC.
* Collections are returned whole under a named key, for example `{ "services": [...] }`.

## Errors

Errors return an HTTP status and a JSON body with an `error` message:

```json theme={null}
{ "error": "Service not found" }
```

| Status | Meaning                                                                               |
| ------ | ------------------------------------------------------------------------------------- |
| `400`  | Invalid request. Validation errors may return `error` as an object of field messages. |
| `401`  | Missing, invalid or expired token.                                                    |
| `403`  | Your role or token doesn't allow this action in the organization.                     |
| `404`  | The resource doesn't exist in the selected organization.                              |
| `409`  | Conflict, for example a domain already attached elsewhere.                            |
| `429`  | Too many requests. Wait for the number of seconds in the `Retry-After` header.        |
| `502`  | The hosting platform couldn't complete the operation; retry later.                    |

## Idempotent checkout

`POST /v1/checkout` creates an order and starts a payment. Send a unique `Idempotency-Key` header so a retried request returns the same order instead of creating another one.

## Examples

Deploy a service and follow it:

```bash theme={null}
SERVICE=5f0c3a0e-2b9a-4c8e-9a51-1d2f3e4a5b6c

curl -X POST https://orbitlab.dev/api/v1/services/$SERVICE/deployments \
  -H "Authorization: Bearer $ORBITLAB_TOKEN"

curl https://orbitlab.dev/api/v1/services/$SERVICE/deployments \
  -H "Authorization: Bearer $ORBITLAB_TOKEN"
```

Set environment variables:

```bash theme={null}
curl -X PATCH https://orbitlab.dev/api/v1/services/$SERVICE/env \
  -H "Authorization: Bearer $ORBITLAB_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"env": {"NODE_ENV": "production"}}'
```

Add a DNS record:

```bash theme={null}
curl -X POST https://orbitlab.dev/api/v1/domains/$DOMAIN_ID/records \
  -H "Authorization: Bearer $ORBITLAB_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"subdomain": "www", "type": "CNAME", "value": "web.orbitlab.sh", "ttl": 3600}'
```

Order an app plan paid with Mobile Money:

```bash theme={null}
curl -X POST https://orbitlab.dev/api/v1/checkout \
  -H "Authorization: Bearer $ORBITLAB_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"items": [{"type": "application", "planId": "app-1", "label": "api"}], "paymentMethod": "mobile_money", "mobileMoneyPhone": "+243812345678", "mobileMoneyNetwork": "VODACOM_MPESA_COD"}'
```

A payment request is sent to the phone. Poll `GET /v1/orders/{orderId}` until the order is `paid`. Card payments are currently unavailable; free orders need no phone number.

## Device login for your own tools

Tools that can't store a token ahead of time can use the same device login as the CLI:

1. `POST /v1/auth/device` with `{"clientName": "my-tool"}` returns `deviceCode`, `userCode` and `verificationUriComplete`.
2. Show the user the code and the link. They approve the request in the dashboard.
3. Poll `POST /v1/auth/device/token` with `{"deviceCode": "…"}` every `interval` seconds. While waiting, it responds `400` with `"error": "authorization_pending"`; on `"slow_down"`, add 5 seconds to the interval. Once approved, it returns the `token` exactly once.
