# Native API

> The gRPC service and HTTP/JSON routes, bearer-key auth, and receipt handles.

One listener (default `:8080`) serves three surfaces from the same router:
SQS (covered in [SQS compatibility](/docs/sqs-compatibility)), gRPC, and an
HTTP/JSON mirror of the same calls. Native surfaces authenticate with
bearer API keys; the SQS surface authenticates with SigV4. The two
credential sets are separate and never derived from each other.

## Authentication

Every gRPC and HTTP/JSON request carries a bearer key:

```
Authorization: Bearer <key>
```

Keys are 32 bytes in base64 and each is scoped to a namespace; see
[configuration](/docs/configuration) for how they are provisioned. A key
scoped to a different namespace is indistinguishable from one that was
never configured.

## gRPC

The service is `okuri.api.v1.QueueService`:

| rpc | purpose |
| --- | --- |
| `SendMessage` | append a message, with optional delay and dedup id |
| `ReceiveMessage` | lease up to a batch of messages, with optional long poll |
| `AckMessage` | complete a delivery |
| `NackMessage` | return a message early, with optional backoff |
| `ChangeMessageVisibility` | extend or shorten an outstanding lease |
| `RedriveQueue` | move dead letters back to the parent queue |
| `PurgeQueue` | drop everything sent before now |
| `GetQueueStats` | queue depth and related counters |

The proto files live in the
[`okuri-proto` crate](https://github.com/okuri-oss/okuri/tree/main/crates/okuri-proto).

## HTTP/JSON

The same calls as plain HTTP:

| route | purpose |
| --- | --- |
| `POST /v1/queues/{queue}/messages` | send |
| `POST /v1/queues/{queue}/messages:receive` | receive |
| `POST /v1/messages:ack` | ack |
| `POST /v1/messages:nack` | nack |
| `POST /v1/messages:extend` | change visibility |
| `POST /v1/queues/{queue}:redrive` | redrive the queue's dead letters |
| `POST /v1/queues/{queue}:purge` | purge |
| `GET /v1/queues/{queue}/stats` | stats |

## Receipt handles

A receive hands back one receipt handle per message. The handle is opaque,
signed with the fleet-wide `receipt_handle_key`, and bound to the node's
namespace. Because every node carries the same key, a handle issued by
whichever node served the receive is honored by whichever node the load
balancer sends the ack to, so sticky routing is not required.

Handles are what ack, nack, and visibility changes take. Do not parse or
store them beyond the lease's lifetime.

## Queue management

The native API deliberately defines no queue-creation RPC today: create
queues through the SQS surface's `CreateQueue`, or through the Rust
library when embedding okuri. `okuri queue` admin CLI commands are planned
for 0.1.0.

Queue names everywhere are non-empty, at most 64 bytes, `[a-z0-9_-]` only,
and the `-dlq` suffix is reserved for each queue's dead-letter companion.
