---
title: REST API
description: The HTTP surface — authentication, the REST endpoints, and where tRPC takes over.
order: 10
---

# REST API

Izri's HTTP surface is deliberately small. REST covers the things that must be plain HTTP — health checks, CI triggers, inbound webhooks, file serving — and everything else goes through tRPC.

For programmatic use, prefer the [CLI](/docs/install/cli) or the [MCP server](/docs/install/mcp). They wrap this surface and stay in step with it.

## Authentication

```
Authorization: Bearer izri_xxxxxxxxxxxx
```

The API checks the `izri_` prefix first and only then validates the token. Without the prefix the request falls through to cookie-session handling and returns an opaque `401`. See [API tokens](/docs/configure/api-tokens).

Browser sessions use a cookie set by the auth flow; token auth takes precedence when both are present.

## Endpoints

### `GET /health`

Liveness. No authentication.

```bash
curl https://api.izri.ai/health
```

### `GET /api/test-runs/:runId/status`

Current status of a test run.

```bash
curl -H "Authorization: Bearer $IZRI_API_TOKEN" \
     https://api.izri.ai/api/test-runs/01HK.../status
```

Returns one of `PENDING`, `RUNNING`, `PASSED`, `FAILED`, `ERROR`, `CANCELLED`. See [verdicts and exit codes](/docs/reference/verdicts-and-exit-codes).

For polling, prefer `izri run --watch` — it already implements sane intervals and a timeout.

### `POST /api/ci/trigger/:projectId`

Trigger a run from a CI system that isn't GitHub Actions.

```bash
curl -X POST \
     -H "Authorization: Bearer $IZRI_API_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{"branch":"feat/x","commitSha":"abc123"}' \
     https://api.izri.ai/api/ci/trigger/01HK...
```

Requires `tests:run`. Returns the run identifier immediately; the run is asynchronous.

### `GET /files/*`

Serves stored artifacts — visual snapshots, diffs, reports. Authenticated: these are your organization's artifacts, not public objects.

## Inbound webhook receivers

These are endpoints Izri *receives* on. You don't call them; you configure a provider to.

| Endpoint | Sender |
| --- | --- |
| `POST /api/webhooks/github-app` | GitHub App events |
| `POST /api/webhooks/github/:projectId` | Per-project GitHub webhook |
| `POST /api/webhooks/stripe` | Stripe billing events |

For webhooks Izri sends *you*, see [outbound webhooks](/docs/configure/webhooks).

## Authentication routes

`/api/auth/**` is handled by the auth layer — OAuth callbacks, session management. Not intended for direct calls.

The GitHub OAuth callback must exactly match the configured app URL. A port mismatch produces a silent redirect loop rather than an error, and it is the most common self-hosting misconfiguration.

## tRPC

Everything else is tRPC, mounted at `/trpc/*`, with the same bearer-token authentication.

The tRPC surface is typed end-to-end and changes with the product. Rather than documenting procedure signatures that would drift, use the clients that are versioned against it — the [CLI](/docs/install/cli) and the [MCP server](/docs/install/mcp).

## Errors

Standard HTTP status codes.

| Status | Meaning |
| --- | --- |
| `401` | Missing, malformed, or invalid token. Check the `izri_` prefix. |
| `403` | Authenticated, but the token lacks the required scope. |
| `404` | Not found — **or** the resource belongs to another organization. |
| `402` | The operation requires a higher plan. |
| `429` | Rate limited. |

`404` doubling as a cross-organization permission error is intentional: it avoids confirming that a resource exists to someone who can't access it. If you're sure an ID is valid and still get `404`, verify the token belongs to the right organization.

## Related

- [API tokens](/docs/configure/api-tokens)
- [Verdicts and exit codes](/docs/reference/verdicts-and-exit-codes)
