---
name: hedra
description: Use when building integrations with multimodal AI models for
  image/video/audio generation, vision-language reasoning, or chat completions.
  Reach for this skill when working with asynchronous inference jobs, managing
  API credentials, handling webhooks, or optimizing costs through the prepaid
  USD wallet.
metadata:
  mintlify-proj: hedra
  version: "1.0"
---

# Hedra API v3 Skill

## Product summary

Hedra is a managed inference platform providing access to frontier multimodal models through a REST API. Agents use it to submit asynchronous jobs for image, video, and audio generation; run vision-language reasoning through OpenAI-compatible chat endpoints; and manage inference workflows with webhooks and job polling. The platform uses a prepaid USD API wallet (separate from Studio credits) and exposes models through `https://api.hedra.com/v3`. Key files: API keys stored in `HEDRA_API_KEY` environment variable as `<key_id>:<secret>`. SDKs available for Python (`hedra-sdk`), TypeScript (`@hedra/sdk`), and CLI (`@hedra/cli`). Primary docs: https://www.hedra.com/docs

## When to use

- **Submitting media generation jobs**: When a user requests image, video, or audio generation from text or reference inputs
- **Vision-language inference**: When analyzing images or reasoning over visual content using models like GLM-5.3 or Kimi-K3
- **Asynchronous workflows**: When building systems that submit jobs and retrieve results later (jobs return `202` with `job_id`)
- **Webhook integration**: When you need to avoid polling and receive completion notifications at a callback URL
- **Cost estimation**: Before submitting expensive jobs, estimate the charge with `POST /v3/models/{model}/estimate`
- **Chaining generations**: When using outputs from one model as inputs to another (reuse `asset_id` from completed jobs)
- **Error recovery**: When handling rate limits, insufficient balance, or retryable failures with bounded retry logic

## Quick reference

### Authentication

| Method | Format | Use case |
|--------|--------|----------|
| Direct HTTP | `Authorization: Key <key_id>:<secret>` | cURL, raw HTTP requests |
| Python SDK | Pass `api_key` parameter | `from hedra import Hedra` |
| TypeScript SDK | Pass `apiKey` parameter | `new HedraClient({ apiKey })` |
| OpenAI-compatible | Pass as `api_key`, base URL `https://api.hedra.com/v3` | Use existing OpenAI/Anthropic clients |

### API scopes (least-privilege)

- `chat:write` — Language model calls
- `jobs:read`, `jobs:write` — Submit and poll jobs
- `files:write` — Upload media files
- `webhooks:manage` — Configure webhook endpoints
- `usage:read` — Inspect billing and usage
- `keys:manage` — Manage API keys

### Job lifecycle

| State | Meaning | Next action |
|-------|---------|-------------|
| `IN_QUEUE` | Waiting to run | Poll or wait for webhook |
| `IN_PROGRESS` | Running | Poll or wait for webhook |
| `COMPLETED` | Finished successfully | Inspect `outputs[]`, download URLs |
| `FAILED` | Job failed | Read `error` envelope, inspect logs |

### Common endpoints

| Endpoint | Purpose |
|----------|---------|
| `POST /v3/models/{model}` | Submit a job (returns `202` with `job_id`) |
| `GET /v3/jobs/{job_id}` | Poll job status and retrieve outputs |
| `GET /v3/jobs/{job_id}/status` | Quick status check (lighter than full job fetch) |
| `POST /v3/models/{model}/estimate` | Estimate cost before submitting |
| `POST /v3/files` | Upload media for use as model input |
| `POST /v3/chat/completions` | Synchronous chat/vision inference (OpenAI format) |
| `PUT /v3/webhooks/default` | Set account-wide webhook endpoint |
| `GET /v3/balance` | Check API wallet balance |
| `GET /v3/usage` | Inspect usage and charges |

### Model selection

| Task | Starting model | Check |
|------|-----------------|-------|
| Image generation | `gpt-image-2` | Aspect ratio, resolution, quality, output format |
| Video generation | `veo-3` | Duration, start frame, resolution, audio support |
| Audio/speech | `elevenlabs-v3` | Available voices, text length, language |
| Vision reasoning | `glm-5.3` | Max images per request (up to 8), context length |
| Chat/reasoning | `glm-5.3`, `kimi-k3`, `deepseek-v4-pro-0813` | Context, output tokens, reasoning effort |

## Decision guidance

### When to use polling vs webhooks

| Scenario | Approach | Reason |
|----------|----------|--------|
| Low-volume, interactive requests | Polling with `GET /v3/jobs/{job_id}/status` | Simple, no infrastructure needed |
| High-volume batch processing | Webhooks with `PUT /v3/webhooks/default` | Reduces API calls, scales better |
| Real-time user-facing requests | Polling with short timeout | User expects immediate feedback |
| Background/async processing | Webhooks | Decouple submission from result handling |

### When to use chat vs model jobs

| Use case | Endpoint | Why |
|----------|----------|-----|
| Text reasoning, image understanding | `POST /v3/chat/completions` | Synchronous, returns immediately, OpenAI-compatible |
| Image/video/audio generation | `POST /v3/models/{model}` | Asynchronous, returns `job_id`, requires polling/webhooks |
| Chaining outputs | Model jobs with `asset_id` | Generated outputs can be reused as inputs |

### When to estimate vs submit directly

| Condition | Action |
|-----------|--------|
| First time with a model | Always estimate first |
| Production workload | Estimate on representative inputs before switching models |
| Cost-sensitive application | Estimate before each submission |
| Rapid prototyping | Skip estimation, handle `402 INSUFFICIENT_BALANCE` |

## Workflow

### 1. Set up credentials and funding
- Create API key at https://www.hedra.com/develop/api-keys with required scopes
- Fund the prepaid USD wallet at https://www.hedra.com/develop/billing (separate from Studio credits)
- Store key as `HEDRA_API_KEY=<key_id>:<secret>` in environment (server-side only)

### 2. Inspect the model
- Fetch `GET /v3/models/{model}` to read input schema, limits, and pricing
- For media models, fetch `GET /v3/models/{model}/openapi.json` for detailed input/output contracts
- Check `required` fields, enums, file size limits, and duration limits

### 3. Estimate the cost (optional but recommended)
- Send the exact input payload to `POST /v3/models/{model}/estimate`
- Compare prices across models or quality levels before committing
- Estimate does not create a job

### 4. Upload media if needed
- Use `POST /v3/files` to upload images, video, or audio
- Returns `url` (upload handle), `content_type`, and `expires_at` (typically 1 hour)
- Pass the returned `url` in the model's media input field

### 5. Submit the job
- POST to `/v3/models/{model}` with model-specific input object
- Optionally pass `webhook` URL for this job, or rely on account default
- Response: `202` with `job_id` (e.g., `job_5f3a…`)
- Store the `job_id` for tracking and recovery

### 6. Wait for completion
- **Polling**: Call `GET /v3/jobs/{job_id}/status` every 5–10 seconds until `COMPLETED` or `FAILED`
- **Webhooks**: Register endpoint with `PUT /v3/webhooks/default`, verify ed25519 signature on delivery, deduplicate on `X-Hedra-Webhook-Id`
- **Streaming**: Use `GET /v3/jobs/{job_id}/stream` for SSE updates

### 7. Retrieve and download outputs
- Fetch `GET /v3/jobs/{job_id}` to get full job details
- Check each output's `status` (should be `COMPLETED`)
- Download from `outputs[].url` without forwarding API credentials
- Signed URLs expire; download immediately or store the `asset_id` for reuse

### 8. Reuse outputs (optional)
- For chaining jobs, use `{"source":"asset","asset_id":"asset_..."}` in the next model's input
- Do not derive `asset_id` from `job_id`; read it from the completed output

### 9. Handle errors and retry
- Check HTTP status and error `code` (e.g., `INSUFFICIENT_BALANCE`, `RESOURCE_EXHAUSTED`)
- Use `idempotency_key` when retrying the same logical job
- Respect `Retry-After` header for rate limits
- Do not retry invalid inputs indefinitely

## Common gotchas

- **Confusing API wallet with Studio credits**: v3 uses a separate prepaid USD wallet. Studio subscription credits do not fund API requests.
- **Embedding long-lived keys in browser code**: Store keys server-side only. Use `POST /v3/tokens` to mint ephemeral tokens for browser access.
- **Resubmitting on timeout**: A local timeout does not cancel the job. Store the `job_id` and resume polling; do not submit a fresh job.
- **Not verifying webhook signatures**: Always verify ed25519 signature on webhook deliveries before processing. Use `GET /v3/webhooks/public-key` to fetch the public key.
- **Deriving asset_id from job_id**: Asset IDs are server-issued and separate from job IDs. Read them from completed outputs, not constructed.
- **Ignoring output status**: A completed job can contain outputs with status `FAILED` or `EXPIRED`. Check each output's status before using it.
- **Polling too aggressively**: Use webhooks or SSE streams for sustained workloads. Aggressive polling triggers rate limits (`429`).
- **Not handling 402 INSUFFICIENT_BALANCE**: This error has two causes: insufficient balance (not retryable, add funds) or in-flight requests holding the balance (retryable after `Retry-After`).
- **Passing external URLs as media inputs**: Only Hedra upload handles (from `POST /v3/files`) work as media inputs. External URLs are not equivalent.
- **Assuming model-specific input schemas are interchangeable**: Each model has its own input contract. Payloads for `gpt-image-2` do not work for `veo-3`.
- **Not checking model availability**: Models change; inspect the live catalog before hardcoding model IDs. Use `GET /v3/models` to list current models.
- **Forgetting to set HEDRA_API_KEY**: SDKs read this environment variable. If a legacy v2 integration uses it, use a separate terminal or command-scoped assignment for v3.

## Verification checklist

Before submitting work:

- [ ] API key created with required scopes (`chat:write` for chat, `jobs:write` for media jobs)
- [ ] API wallet funded and balance checked with `GET /v3/balance`
- [ ] Model ID confirmed in live catalog (`GET /v3/models`)
- [ ] Input payload validated against model's schema (`GET /v3/models/{model}/openapi.json`)
- [ ] Cost estimated with `POST /v3/models/{model}/estimate` (for production workloads)
- [ ] Media files uploaded with `POST /v3/files` if needed; URLs stored before expiry
- [ ] Webhook endpoint configured and tested with `POST /v3/webhooks/default/test` (if using webhooks)
- [ ] Idempotency key generated for retryable submissions
- [ ] Job ID stored for tracking and recovery
- [ ] Error handling in place for `402`, `429`, `5xx` responses
- [ ] Webhook signature verification implemented (if using webhooks)
- [ ] Output status checked before downloading or reusing

## Resources

- **Comprehensive navigation**: https://www.hedra.com/docs/llms.txt
- **Model catalog and pricing**: https://www.hedra.com/develop/models
- **API reference**: https://www.hedra.com/docs/pages/developer/v3/reference/chat
- **Quickstart (vision reasoning)**: https://www.hedra.com/docs/pages/developer/v3/quickstart
- **Model jobs (async generation)**: https://www.hedra.com/docs/pages/developer/v3/model-jobs
- **Webhooks and callbacks**: https://www.hedra.com/docs/pages/developer/v3/webhooks

---

> For additional documentation and navigation, see: https://www.hedra.com/docs/llms.txt