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

# Run an asynchronous model job

> Create a Hedra v3 API key, fund your API wallet, and submit, wait for, and download an inference result with Python, TypeScript, or cURL.

Run an image model and save its output. The same job lifecycle applies to
video and audio models; each model defines its own inputs.

## Create a key and fund your wallet

1. Create a key in the [developer console](https://www.hedra.com/develop/api-keys).
2. Add funds to your [API wallet](https://www.hedra.com/develop/billing).
3. Set the credential in a terminal dedicated to v3. If your current shell runs
   a legacy integration using `HEDRA_API_KEY`, open a separate terminal first:

```bash theme={null}
export HEDRA_API_KEY="<key_id>:<secret>"
```

The v3 API uses a **prepaid USD wallet**, separate from Studio credits. An
unfunded wallet cannot pay for a generation. See
[Authentication](https://www.hedra.com/docs/pages/developer/v3/authentication.md) and
[Pricing and billing](https://www.hedra.com/docs/pages/developer/v3/billing.md).

## Check the cost

This example uses `gpt-image-2`. You can estimate the charge before submitting;
an estimate does not create a job.

```bash theme={null}
curl --fail-with-body -X POST https://api.hedra.com/v3/models/gpt-image-2/estimate \
  -H "Authorization: Key $HEDRA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"input":{"prompt":"An industrial inspection camera on a workbench","aspect_ratio":"1:1","resolution":"1K","quality":"medium","output_format":"png"}}'
```

## Submit, wait, and download

Choose a language. Each example prints a job ID, waits for a terminal state,
and downloads the first completed output to `output.png` in your current directory.
Running it submits a billable job and replaces that local file if it exists.
A local timeout stops waiting; it does **not** cancel the job.

**Python**

Install the [Python SDK](https://github.com/hedra-labs/hedra-python) and HTTP client:

```bash theme={null}
python -m pip install hedra-sdk httpx
```

Save as `quickstart.py` and run `python quickstart.py`:

```python theme={null}
import os
import time
from pathlib import Path

import httpx
from hedra import Hedra

client = Hedra(api_key=os.environ["HEDRA_API_KEY"], timeout=30.0)
ack = client.jobs.submit(
    model="gpt-image-2",
    input={"prompt": "An industrial inspection camera on a workbench",
           "aspect_ratio": "1:1", "resolution": "1K",
           "quality": "medium", "output_format": "png"},
)
print(f"Job: {ack.job_id}", flush=True)
deadline = time.monotonic() + 600
while True:
    if time.monotonic() >= deadline:
        raise TimeoutError(f"Still running: {ack.job_id}. Resume polling; do not resubmit.")
    status = client.jobs.get_status(job_id=ack.job_id)
    if status.status in ("COMPLETED", "FAILED"):
        break
    time.sleep(5)

result = client.jobs.get(job_id=ack.job_id)
if result.status == "FAILED":
    raise RuntimeError(str(result.error))
outputs = result.outputs or []
if not outputs or outputs[0].status != "COMPLETED" or not outputs[0].url:
    raise RuntimeError("No downloadable output; inspect the job's output status and error.")
# Download without forwarding the API credential to the storage host.
with httpx.stream("GET", str(outputs[0].url), timeout=60.0, follow_redirects=True) as response:
    response.raise_for_status()
    with Path("output.png").open("wb") as output:
        for chunk in response.iter_bytes():
            output.write(chunk)
print("Saved output.png")
```

**TypeScript**

Use Node.js 20 or later. Install the [TypeScript SDK](https://github.com/hedra-labs/hedra-node):

```bash theme={null}
npm install @hedra/sdk
npm install --save-dev tsx typescript @types/node
```

Save as `quickstart.mts` and run `npx tsx quickstart.mts`:

```typescript theme={null}
import { HedraClient } from "@hedra/sdk";
import { writeFile } from "node:fs/promises";

const key = process.env.HEDRA_API_KEY;
if (!key) throw new Error("Set HEDRA_API_KEY first");
const client = new HedraClient({ apiKey: key });
const ack = await client.jobs.submit("gpt-image-2", {
  input: { prompt: "An industrial inspection camera on a workbench",
    aspect_ratio: "1:1", resolution: "1K", quality: "medium", output_format: "png" },
}, { timeoutInSeconds: 30 });
console.log(`Job: ${ack.job_id}`);
const deadline = Date.now() + 600_000;
while (true) {
  if (Date.now() >= deadline) {
    throw new Error(`Still running: ${ack.job_id}. Resume polling; do not resubmit.`);
  }
  const status = await client.jobs.getStatus(ack.job_id, {}, { timeoutInSeconds: 30 });
  if (status.status === "COMPLETED" || status.status === "FAILED") break;
  await new Promise(resolve => setTimeout(resolve, 5000));
}
const result = await client.jobs.get(ack.job_id, {}, { timeoutInSeconds: 30 });
if (result.status === "FAILED") throw new Error(JSON.stringify(result.error));
const output = result.outputs?.[0];
if (!output || output.status !== "COMPLETED" || !output.url) {
  throw new Error("No downloadable output; inspect the job's output status and error.");
}
// Download without forwarding the API credential to the storage host.
const download = await fetch(output.url, { signal: AbortSignal.timeout(60_000) });
if (!download.ok) throw new Error(`Download failed: ${download.status}`);
await writeFile("output.png", Buffer.from(await download.arrayBuffer()));
console.log("Saved output.png");
```

**cURL**

Requires Bash, cURL with `--fail-with-body` support, and `jq`.
Save as `quickstart.sh` and run `bash quickstart.sh`:

```bash theme={null}
#!/usr/bin/env bash
set -euo pipefail
: "${HEDRA_API_KEY:?Set HEDRA_API_KEY first}"
API="https://api.hedra.com/v3"
ACK=$(curl --fail-with-body --silent --show-error --max-time 30 \
  -X POST "$API/models/gpt-image-2" \
  -H "Authorization: Key $HEDRA_API_KEY" -H "Content-Type: application/json" \
  -d '{"input":{"prompt":"An industrial inspection camera on a workbench","aspect_ratio":"1:1","resolution":"1K","quality":"medium","output_format":"png"}}')
JOB_ID=$(printf '%s' "$ACK" | jq -er '.job_id')
echo "Job: $JOB_ID"
DEADLINE=$((SECONDS + 600))
while true; do
  if (( SECONDS >= DEADLINE )); then
    echo "Still running: $JOB_ID. Resume polling; do not resubmit." >&2
    exit 1
  fi
  STATUS=$(curl --fail-with-body --silent --show-error --max-time 30 \
    "$API/jobs/$JOB_ID/status" -H "Authorization: Key $HEDRA_API_KEY" | jq -er '.status')
  case "$STATUS" in
    COMPLETED) break ;;
    FAILED) echo "Job failed: $JOB_ID. Inspect GET /v3/jobs/$JOB_ID." >&2; exit 1 ;;
    IN_QUEUE|IN_PROGRESS) sleep 5 ;;
    *) echo "Unexpected status: $STATUS" >&2; exit 1 ;;
  esac
done
RESULT=$(curl --fail-with-body --silent --show-error --max-time 30 \
  "$API/jobs/$JOB_ID" -H "Authorization: Key $HEDRA_API_KEY")
URL=$(printf '%s' "$RESULT" | jq -er '.outputs[0] | select(.status == "COMPLETED") | .url // empty')
# Download without forwarding the API credential to the storage host.
curl --fail --location --silent --show-error --max-time 120 "$URL" -o output.png
echo "Saved output.png"
```

Expected result: a printed `job_...` ID, followed by `Saved output.png`.
If a job fails or times out, use that ID to inspect it before submitting again.
See [Errors and retries](https://www.hedra.com/docs/pages/developer/v3/errors-and-retries.md).

## Next steps

> **[Choose a model](https://www.hedra.com/docs/pages/developer/v3/model-catalog.md)**
>
> Compare modalities and inspect model-specific schemas.

> **[Send media inputs](https://www.hedra.com/docs/pages/developer/v3/files.md)**
>
> Upload files and reuse generated assets.

> **[Receive webhooks](https://www.hedra.com/docs/pages/developer/v3/webhooks.md)**
>
> Handle completion without polling.

> **[Call language models](https://www.hedra.com/docs/pages/developer/v3/chat-completions.md)**
>
> Use the OpenAI or Anthropic SDK with supported v3 routes.

## Use Hedra from an AI client

To use Hedra from Claude, Cursor, Codex or ChatGPT, add the Hedra MCP server,
`https://mcp.hedra.com`, to the client instead of calling the API. The client
signs you in with your Hedra account, and you need no API key:

> **[Add to Claude](https://claude.ai/customize/connectors?modal=add-custom-connector\&connectorName=Hedra\&connectorUrl=https%3A%2F%2Fmcp.hedra.com)**
>
> Opens Claude's connector dialog with Hedra filled in.

> **[Add to Cursor](cursor://anysphere.cursor-deeplink/mcp/install?name=hedra\&config=eyJ1cmwiOiJodHRwczovL21jcC5oZWRyYS5jb20ifQ%3D%3D)**
>
> Installs the Hedra MCP server in Cursor.

> **[Codex, ChatGPT, Claude Code](https://www.hedra.com/docs/pages/developer/v3/mcp.md)**
>
> Setup steps for every client.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.