# Public API

> Sign up, create products and run tasks on Orkosi from any program or AI agent. API keys, the machine-readable API document, limits and the MCP server.

Source: https://support.orkosi.com/docs/public-api

Everything you can do in the Orkosi hub, a program can do over HTTPS. The public API lives under `/api/v1/public`, speaks JSON, and is described by one OpenAPI 3.1 document you can import into any client, SDK generator or AI assistant:

```text
https://orkosi.com/api/v1/public/openapi.json
```

If you are wiring up ChatGPT, Claude or another assistant, read [Build with an AI agent](https://support.orkosi.com/docs/ai-agents) first. It uses the same API through a signup call and an MCP server.

## Authentication
Every call except signup, health and the document itself carries a tenant API key. Keys start with `ak_` and are sent either way:

```http
Authorization: Bearer ak_0123456789abcdef...
X-API-Key: ak_0123456789abcdef...
```

A key belongs to one workspace and carries scopes. The scopes decide what it may do; the role of the person who created it decides what it may change (archiving a product needs the owner). You get a key in one of two ways:

- **Sign up by API.** `POST /signup` creates the account, the workspace and the first key in one call. See [Sign up](#signup).
- **Settings → API keys** in the hub, for an existing account. Pick the scopes you need; the raw key is shown once.

Scopes follow the `resource:action` form: `products:read`, `products:write`, `tasks:read`, `tasks:write`, `agents:read`, `billing:read` and others listed at `GET /api/settings/api-keys/scopes` when signed in. A `:write` scope includes `:read`.

## Sign up
```http
POST /api/v1/public/signup
Content-Type: application/json

{
  "name": "Acme",
  "email": "founder@acme.com",
  "terms_accepted": true,
  "agent": { "client": "claude" }
}
```

```json
{
  "data": {
    "api_key": "ak_...",
    "key_prefix": "ak_0123456",
    "scopes": ["products:read", "products:write", "tasks:read", "tasks:write", "agents:read", "billing:read"],
    "account": {
      "user_id": 42,
      "email": "founder@acme.com",
      "tenant_id": "…",
      "tenant_slug": "acme",
      "plan": "free",
      "email_verification": "sent",
      "password": "set one from the \"forgot password\" link"
    },
    "credits": { "granted": 100 },
    "next": { "docs": "…", "openapi": "…", "mcp": "…", "set_password": "…", "dashboard": "…" }
  }
}
```

What happens: the person's account is created on the free plan with its signup credits, a verification email goes out, and the key in the answer is ready to use. `password` is optional. Without one the person sets theirs from the "forgot password" link, so an agent never has to invent or store a password. `terms_accepted` must be `true`: the person agrees to the [terms](https://support.orkosi.com/terms) and the [privacy policy](https://support.orkosi.com/privacy).

Limits: signup is rate limited per IP address and per email, one account per email (`409 EMAIL_TAKEN`), and the free plan holds one product. `GET /me` answers the workspace, plan, scopes and credit balance of any key.

## Products
A product is an app, a site or a SaaS Orkosi builds and hosts. Creating one gives it a URL at once; tasks make it real.

| Method and path         | What it does                                                             | Scope            |
| ----------------------- | ------------------------------------------------------------------------ | ---------------- |
| `GET /products`         | List products (`?status=active`, `paused` or `archived`)                 | `products:read`  |
| `POST /products`        | Create a product: `name`, optional `slug`, `description`, `product_type` | `products:write` |
| `GET /products/{id}`    | One product: state, lifecycle, URL                                       | `products:read`  |
| `PATCH /products/{id}`  | Rename, describe, pause, resume or archive                               | `products:write` |
| `DELETE /products/{id}` | Archive (hosting is torn down within a day, nothing is deleted)          | `products:write` |

```http
POST /api/v1/public/products
Authorization: Bearer ak_...

{ "name": "Acme CRM", "description": "A CRM for small agencies", "product_type": "saas" }
```

The answer is `{ "data": { "id", "slug", "name", "status", "lifecycle", "url", … } }`. On the free plan a second product answers `402 PLAN_PRODUCT_LIMIT` with the plan to upgrade to. Product types: `saas` (default), `informational`, `shopify`, `blog`.

## Tasks
A task is a work order on a product: "add a login page", "connect Stripe", "write the pricing page". Orkosi plans it, builds it, tests it and deploys it; it is charged in credits when it runs.

| Method and path      | What it does                                                    | Scope         |
| -------------------- | --------------------------------------------------------------- | ------------- |
| `GET /tasks`         | List tasks (`?product_id=`, `?status=`)                         | `tasks:read`  |
| `POST /tasks`        | Create a task: `title`, `description`, `product_id`, `priority` | `tasks:write` |
| `GET /tasks/{id}`    | One task: status and resolution                                 | `tasks:read`  |
| `PATCH /tasks/{id}`  | Update a task                                                   | `tasks:write` |
| `DELETE /tasks/{id}` | Cancel a task                                                   | `tasks:write` |

`product_id` is the numeric id of the product row the hub shows, not the product's uuid. `GET /costs` answers the spend summary of the workspace (`billing:read`).

## Responses and errors
- A single item answers `{ "data": { … } }`. A list answers `{ "data": [ … ], "meta": { "total", "limit", "offset" } }` and takes `?limit=` (1 to 200) and `?offset=`.
- An error answers `{ "error": "<message>", "code": "<STABLE_CODE>" }` with the matching HTTP status: `400 VALIDATION_ERROR`, `401 API_KEY_REQUIRED`, `403 INSUFFICIENT_SCOPE`, `404 NOT_FOUND`, `402 PLAN_PRODUCT_LIMIT`, `429 RATE_LIMIT_EXCEEDED`.
- Every keyed call carries `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`. The allowance per minute follows the plan; a `429` carries `Retry-After`.

## The MCP server
The same API is available as a [Model Context Protocol](https://modelcontextprotocol.io) server, so an assistant that speaks MCP gets `orkosi_whoami`, `orkosi_list_products`, `orkosi_create_product`, `orkosi_create_task` and friends as tools:

- **Remote:** `https://orkosi.com/api/v1/public/mcp` (Streamable HTTP, stateless JSON responses; `initialize`, `tools/list` and `tools/call`). Authorization: OAuth 2.1 with dynamic client registration and PKCE (a call without a key answers `401` with `WWW-Authenticate: Bearer resource_metadata="https://orkosi.com/.well-known/oauth-protected-resource"`; the server metadata is at `/.well-known/oauth-authorization-server`), or an API key as `Authorization: Bearer ak_…`. Approving the sign-in creates a key with the agent scopes, listed in **Settings → API keys**.
- **Local (stdio):** a stdio server exists for teams that run the Orkosi code (`ORKOSI_API_KEY` in its environment, no dependencies beyond Node 18). From a laptop, the remote server above is the one to use.

Every tool call is a call to this API with your key, so scopes, plan limits, rate limits and credits apply exactly as above. [Build with an AI agent](https://support.orkosi.com/docs/ai-agents) has the configuration for ChatGPT, Claude and Cursor.
