---
title: "Get Log Drain"
method: GET
path: "/log-drains/{drain_id}"
tags: ["Log drains"]
---

# Get Log Drain

`GET /log-drains/{drain_id}`

## Request

- Base URL: `https://api.hedra.com/v3`
- URL: `https://api.hedra.com/v3/log-drains/{drain_id}`
- Auth: one of:
  - API key in header `Authorization`
  - HTTP bearer

## Path parameters

- `drain_id` string, required: The drain's id (`drain_<uuid>`).

## Response `200`

Successful Response

- LogDrainConfig
  - `id` string, required: The drain's id (`drain_<uuid>`).
  - `name` string, required: Human-readable label.
  - `url` string, required: The destination endpoint.
  - `format` 'ndjson' | 'otlp', required: Wire encoding for one log drain endpoint's HTTP posts.
  - `header_names` string[]: Names of the configured extra headers. Values are write-only and never echoed back.
  - `enabled` boolean, required: Whether the drain receives batches.
  - `batch_size` integer, required: Maximum log lines per post.
  - `consecutive_failures` integer, required: Failed batches since the last success; the drain auto-disables when it crosses the failure threshold.
  - `last_success_at` string, date-time, nullable: ISO-8601 instant of the last delivered batch.
  - `last_failure_at` string, date-time, nullable: ISO-8601 instant of the last failed batch.
  - `last_failure_status` integer, nullable: HTTP status of the last failed batch; null when it never got a response.
  - `last_error` ErrorEnvelope
    - `code` 'UNKNOWN' | 'INVALID_ARGUMENT' | 'NOT_FOUND' | 'GONE' | 'ALREADY_EXISTS' | 'ALREADY_IN_PROGRESS' | 'UNAUTHORIZED' | 'PERMISSION_DENIED' | 'INSUFFICIENT_BALANCE' | 'MODERATION_FAILED' | 'FAILED_PRECONDITION' | 'CANCELLED' | 'DEADLINE_EXCEEDED' | 'RESOURCE_EXHAUSTED' | 'UNAVAILABLE' | 'INTERNAL', required: Universal error code space. Modeled after gRPC status codes. Every exception in the system carries an ErrorCode. SDK clients map 3rd-party errors to these codes at the lowest level. Retry logic, HTTP status mapping, and OTEL metrics all key off this enum. NOTE: The semantic meaning of these error codes is roughly mapped from the semantic of the gRPC status codes: see https://grpc.io/docs/guides/status-codes/ for details.
    - `message` string, required: Human-readable summary of the error. Fixed per condition — match on `code`, not on this text.
    - `retryable` boolean: Whether retrying the same request can succeed. Describes the condition, not a promise — pair with `retry_after` when present.
    - `retry_after` integer, nullable: Seconds to wait before retrying; set when the error is retryable. Mirrors the `Retry-After` response header.
    - `param` string, nullable: The primary offending input field, when the error is about one specific field.
    - `details` FieldError[], nullable: Every field-level problem, when the error is a validation failure — all of them at once, not just the first.
      - `field` string, required: Dotted path to the offending input (e.g. `input.resolution`).
      - `message` string, required: What is wrong with this field's value.
      - `reason` string, nullable: Machine-readable hint for which constraint failed ("required", "enum", "type", …).
      - `allowed` string[], nullable: Accepted values for an enum, or accepted field names on the first unknown-field violation. Omitted on subsequent unknown fields.
    - `replaced_by` string, nullable: The id of a successor model, set when the requested model has been retired (code `GONE`) and replaced; null otherwise. Lets a client programmatically migrate off a retired model.
    - `billing` BillingError: Why a request was refused for funds, and what would clear it. The envelope's structured detail for `INSUFFICIENT_BALANCE`, the way `details` is its structured detail for a validation failure. Every amount is in `currency`, and `balance` is the same number `GET /balance` returns — so a client can decide whether to top up, wait, or fail over without a second round trip to work out which balance was short.
      - `balance` number, required: Spendable balance on the account this request bills, at the moment it was refused. The same value `GET /balance` returns.
      - `required` number, nullable: What this request needed. Null when the refusal is a funding precondition rather than a priced one — an upload is not priced, and some models cannot be quoted until their inputs are measured (`POST /models/{model}/estimate` says so explicitly).
      - `currency` string: ISO-4217 code the amounts above are denominated in.
      - `funding_url` string, required: Where a human can add funds to the account this request bills. The API itself cannot add them.
      - `reason` string, nullable: Why the automatic top-up did not fund the balance, when known. `card_declined`: the card that pays for automatic top-ups was declined, and the payment method must be updated on the billing page before a top-up can succeed. Clients MUST tolerate unrecognized values: new reasons may be added at any time.
      - `affordable_output_tokens` integer, nullable: On a chat request's refusal, the largest output bound in tokens, `max_tokens` or `max_output_tokens` on `POST /responses`, whose hold the balance covers for this request's prompt. A chat request (`POST /chat/completions`, `POST /responses`, `POST /anthropic/v1/messages`) holds its worst-case price, `required`, until it completes. The balance covers the hold of the same request with this bound until the balance changes. 0 when the balance does not cover the prompt with the model's smallest output bound. Null on every other refusal.
    - `type` 'invalid_request_error' | 'authentication_error' | 'permission_error' | 'rate_limit_error' | 'server_error', required: The OpenAI error type for an error's HTTP status, published so an OpenAI SDK's `APIStatusError.type` carries a value.
  - `disabled_reason` string, nullable: Why the drain is off (`consecutive_failures` for auto-disable, `disabled_by_user`); null while enabled.
  - `created_at` string, date-time, required: ISO-8601 instant the drain was created.
  - `updated_at` string, date-time, required: ISO-8601 instant the config last changed.
  - `updated_by_key_id` string, nullable: The API key that last changed the config.

## Other responses

- `400`: Invalid or failed-validation request.
- `401`: Authentication failed: missing, malformed, or invalid credentials.
- `403`: Insufficient scope or plan.
- `404`: Resource not found.
- `429`: Rate limit exceeded.
- `500`: Internal error.

## Changes

- **2026-10-16** `06692d16e78a`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/hedra-labs/apis/hedra-api/changes/log-drains/:drain_id/get.md)

---

[API](https://skmtc.dev/hedra-labs/apis/hedra-api.md) - [All operations](https://skmtc.dev/hedra-labs/apis/hedra-api/llms.txt) - [OpenAPI document](https://skmtc.dev/hedra-labs/apis/hedra-api/revisions/6ef35a11cefe?raw)
