# Machine API

Use your administrator-provided HTTPS origin with `/api/public/v1`.
These routes register caller-owned entities and admit configured work.
Browser and managed-pairing APIs have separate authentication and are outside this reference.

See the [generated API reference](https://docs.amonsul.io/developers/api-reference/) for payload
fields, response shapes and the downloadable OpenAPI specification.

## Machine authentication and scope

Send `Authorization: Bearer <api-key>`. The authenticated key supplies the
tenant, lane, and managed integration association. A body field or browser lane
switch cannot change that context. A key must have each route's required scope.
Production and test key classifications must agree with their stored lane.

| Method and path below `/api/public/v1`   | Scope           | Purpose                                                       |
| ---------------------------------------- | --------------- | ------------------------------------------------------------- |
| `GET /entity-types/:entityType/statuses` | `read_entities` | Exact entity type's permitted status catalog                  |
| `GET /association/entity-counts`         | `read_entities` | Counts for the authenticated association in its lane          |
| `POST /entities`                         | `enqueue`       | Register an external entity under the lane binding            |
| `POST /entities/batch`                   | `enqueue`       | Register up to 500 entities in one call                       |
| `GET /entities/:identifier`              | `read_entities` | Entity status/tracks, policy context, and available sequences |
| `GET /entities/:identifier/history`      | `read_entities` | Paginated execution history                                   |
| `POST /enqueue`                          | `enqueue`       | Admit a sequence for a registered entity                      |

Send `POST /entities/batch` a body of `{ "entities": [ … ] }` holding 1-500
registration bodies. The answer is 200 with `observed_at` and one
`{ status, body }` per row, in order. A row is 201, 409 or 422 on its own;
anything unexpected rolls back the whole batch with 500. The batch counts as
one request against the rate limit.

`GET /health` sits at the service root, outside that route group. A health probe
does not establish that a specific policy, tenant, or external destination works.

## Register an entity

First read the entity type's statuses and tracks with
`GET /entity-types/:entityType/statuses` and confirm the entity type has the
expected published binding in the key's lane. Registration requires `external_id`
and `entity_type`:

```json
{
  "external_id": "INV-001",
  "entity_type": "invoice",
  "description": "Invoice awaiting review",
  "metadata": { "sourceRecordId": "INV-001" }
}
```

Optional `initial_status_code` or composite `initial_status_codes` select valid
initial context; they are validated against the bound policy. Optional
`registration_context` records caller-supplied registration evidence. It does
not confer permissions or change authenticated provenance.

A successful registration returns HTTP 201 with `entity_id`, external identity,
status, and policy information; composite registration also exposes tracks.
An existing registration returns 409. Missing or invalid policy/status context
returns a validation error rather than inventing a workflow.

## Read offered work

Use the returned UUID as `:identifier`, or an external identifier with the
`entity_type` query parameter. The entity response describes available sequences,
including `sequence_id`, `sequence_code`, input contract, matrix/version context,
role, `available`, and `blocked_reason`.

Choose the offered concrete `sequence_id`. A sequence code is a compatibility
selector and may be ambiguous across composite tracks. A blocked sequence needs
its prerequisite resolved; its displayed name is not an execution credential.

History uses `/history`, with `entity_type` where needed and `limit` / `offset`
(defaults 50 / 0). Its response includes `history` and `pagination`. There is
no `/entities/:id/logs` endpoint in this route registration.

## Start a sequence

```json
{
  "external_id": "INV-001",
  "entity_type": "invoice",
  "sequence_id": "00000000-0000-4000-8000-000000000001",
  "starting_parameters": { "invoice_number": "INV-001" }
}
```

Replace the UUID and parameters with those offered by the entity response.
Supply `entity_id` or `external_id`, and `sequence_id` or `sequence_code`.
`starting_parameters` contains the sequence-start input object. The entity's
pinned policy supplies the matrix; enqueue does not take `action_matrix_code`.
Optional `executed_by` is an audit label; the authenticated key remains recorded.

HTTP 202 means admission was accepted. The response contains `success`,
`message`, entity identity, concrete sequence identity, `tenant_id`, and `run_id`.
It does not mean the sequence or its external effects have completed.

| Status | Enqueue interpretation                                              |
| ------ | ------------------------------------------------------------------- |
| 400    | Missing identifier/selector or invalid UUID                         |
| 403    | Scope or admission refused                                          |
| 404    | Entity or permitted sequence not found in the authenticated context |
| 409    | Conflicting execution ownership or context                          |
| 422    | Sequence input or policy validation failed                          |
| 429    | Rate limit exceeded                                                 |
| 500    | Unexpected admission error; inspect evidence before repeating       |

Errors use a string `error` and may contain `details`, validation fields, or a
lane rejection `code`. Framework authentication and validation errors may have
their own shape. Do not assume every error is `{ error: { code, message } }`.

Enqueue and entity routes configure per-key limits of 300, 1000, or 5000 requests
per minute for standard, premium, or enterprise keys, with an IP fallback when
key context is absent. The catalog, status and count routes fall under the
platform's blanket limit of 1,000 requests per minute per client IP.

Continue with the [integration guide](https://docs.amonsul.io/developers/integration/). Examples were checked against
request schemas; they were not sent to a live API during this documentation review.
