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

# Endpoints and errors

> Every ingest path, every status code the receiver returns, the rate limits and the size caps — the page to open when a request is being rejected.

Reference for the ingest surface. If a request is being rejected and you want to
know why, start with [status codes](#status-codes).

## Base endpoint

| Deployment                               | Base endpoint                    |
| :--------------------------------------- | :------------------------------- |
| **aiAxonIQ Cloud**                       | `https://app.aiaxoniq.com/otlp`  |
| **Self-hosted** behind the bundled nginx | `https://app.<your-domain>/otlp` |

Both forms carry the `/otlp` prefix because nginx serves OTLP under it and
strips it before forwarding, so the receiver still sees `/v1/logs`. Dropping the
prefix is the most common setup mistake: the request reaches the dashboard
instead of the receiver and comes back as an HTML 404 rather than an ingest
error.

<Info>
  **Get Started** in the dashboard shows the exact base endpoint for your
  deployment next to a license key you create there, with copy buttons, and
  then watches for your first records. Where these pages write
  `$OIQ_ENDPOINT`, that page has the real value.
</Info>

## Paths

Over HTTP:

| Method | Path                 | Purpose                                                      |
| :----- | :------------------- | :----------------------------------------------------------- |
| `POST` | `/v1/logs`           | OTLP logs                                                    |
| `POST` | `/v1/metrics`        | OTLP metrics                                                 |
| `POST` | `/v1/traces`         | OTLP traces                                                  |
| `POST` | `/api/v1/prom/write` | Prometheus remote-write                                      |
| `GET`  | `/health`            | Liveness — always 200 if the process is up                   |
| `GET`  | `/readyz`            | Readiness — 200 when the pipeline is reachable, 503 when not |
| `GET`  | `/metrics`           | The receiver's own Prometheus metrics                        |

Over gRPC, on port **4317**: the standard OTLP logs, metrics and trace services.

<Warning>
  **gRPC is not exposed on aiAxonIQ Cloud** — the hosted deployment serves OTLP
  over HTTP only, and port `4317` refuses connections. It is reachable only on a
  self-hosted deployment whose reverse proxy has been configured to carry gRPC.
  See [OTLP over gRPC](/send-data/otel/collector#otlp-over-grpc).
</Warning>

Where both are served, they accept **the same dashboard-issued key** and enforce
the same rate limits, quotas and per-signal entitlements — the only difference is
that gRPC metadata keys are lower-case, so the header is `x-license-key`.

<Warning>
  `/health` is a static check on the process only; it does not test
  dependencies. Use `/readyz` if you want a check that fails when the pipeline
  behind the receiver is unreachable. Wiring a load balancer to `/health`
  expecting it to drain an unhealthy receiver will not do what you want.
</Warning>

## Authentication

Send your license key one of two ways:

```http theme={null}
X-License-Key: oiq_4f3c2b1a9e8d7c6b5a4f3e2d1c0b9a8e
```

```http theme={null}
Authorization: Bearer oiq_4f3c2b1a9e8d7c6b5a4f3e2d1c0b9a8e
```

`X-License-Key` takes precedence if both are present. Header names are
case-insensitive; the key value is not.

<Note>
  **One reason to prefer the `X-License-Key` header.** Rate limiting buckets
  requests by that header's value, falling back to source IP when it is absent.
  Authenticating with `Authorization: Bearer` therefore shares a rate-limit
  bucket with everything else from the same address. If several services egress
  through one NAT gateway, they will collectively hit a limit that the per-key
  form would have kept separate.
</Note>

## Status codes

<AccordionGroup>
  <Accordion title="202 Accepted — success" icon="circle-check">
    The batch was published to the pipeline. This is success. It acknowledges
    receipt, not storage; data becomes queryable a few seconds later.
  </Accordion>

  <Accordion title="400 Bad Request — the payload did not decode" icon="circle-xmark">
    Causes: malformed protobuf, a body that does not match the declared content
    type, or a payload that decodes but violates the OTLP schema.

    Rejected payloads are copied to a dead-letter queue, so they are recoverable
    by an operator.
  </Accordion>

  <Accordion title="401 Unauthorized — the key was not accepted" icon="key">
    One of:

    * No key supplied — the message names both accepted headers.
    * Malformed key — not `oiq_`-prefixed, or shorter than 20 characters.
    * Invalid or revoked key.

    <Warning>
      **A 401 does not always mean your key is wrong.** If the receiver cannot
      reach the service that validates keys, validation fails closed and returns
      the same `401` as a genuinely invalid key. A sudden `401` across every
      service at once, with a key you have not changed, is far more likely to be
      a validation outage than a credential problem. Check `/readyz` before
      regenerating keys.
    </Warning>
  </Accordion>

  <Accordion title="403 Forbidden — valid key, disallowed request" icon="ban">
    The signal is not enabled for your account, or the source address is not
    permitted.
  </Accordion>

  <Accordion title="413 Payload Too Large" icon="weight-hanging">
    The body exceeded a size cap. See [limits](#limits-and-caps).
  </Accordion>

  <Accordion title="429 Too Many Requests" icon="gauge-high">
    A rate limit was hit. A `Retry-After` header gives the wait in seconds.
  </Accordion>

  <Accordion title="500 / 502 / 503 — retryable" icon="arrows-rotate">
    The receiver could not publish to the pipeline. OpenTelemetry SDKs and
    Prometheus remote-write both retry these with backoff.
  </Accordion>
</AccordionGroup>

## Rate limits

Three limits apply to authenticated HTTP ingest:

* **200 requests per second** per account, with a burst allowance of 400.
  Exceeding it returns `429` with `Retry-After: 1`.
* **10,000 requests per minute** per account. Exceeding it returns `429` with
  `Retry-After: 60`.
* A global per-key limit, which also returns `429`.

The per-second limit does not apply to Prometheus remote-write; the per-minute
limit does.

<Tip>
  These are limits on **requests**, not on records. Batching is therefore the
  correct response to hitting them — an SDK exporting 500 spans in one request
  uses one of your 200 per second, not 500. If you are being rate-limited, look
  at your exporter's batch settings before asking for a limit increase.
</Tip>

## Limits and caps

<Tabs>
  <Tab title="General ingest">
    * **50 MB** maximum request body.
  </Tab>

  <Tab title="Prometheus remote-write">
    Tighter caps than general ingest:

    * **8 MB** compressed body
    * **64 MB** decompressed
    * **10,000** timeseries per request
    * **100,000** total samples per request
    * **128** labels per series
    * **1,024 bytes** per label name or value

    Exceeding the decompressed cap returns `413`; exceeding the series, sample
    or label caps returns `400`.
  </Tab>
</Tabs>

## Encodings

OTLP/HTTP accepts:

* `application/json`
* `application/x-protobuf`
* `application/octet-stream` — treated as protobuf

Request bodies may be gzip, deflate or brotli compressed. An unsupported
`Content-Encoding` returns `415`; a body that fails to decompress returns `400`.

<Warning>
  Prometheus remote-write is the exception: it expects snappy-compressed
  protobuf and has HTTP-level decompression disabled, so gzip on top of it will
  fail. Leave Prometheus's compression settings alone and it will do the right
  thing.
</Warning>

## Next

<CardGroup cols={2}>
  <Card title="Send data with OpenTelemetry" icon="telescope" href="/send-data/otel/collector">
    Endpoints, headers and a first request.
  </Card>

  <Card title="Prometheus remote-write" icon="chart-line" href="/send-data/prometheus">
    Ship from an existing Prometheus server.
  </Card>
</CardGroup>
