# Use Leap from your agent Source: https://www.tryleap.ai/docs/agents Connect Claude Code, Cursor or any MCP client, or point your coding agent at these docs. ## Connect over MCP Leap's MCP server lets an agent search models, read their schemas, quote, generate and check runs. You sign in once in the browser; there's no key to paste. ```bash Claude Code theme={null} claude mcp add --transport http leap https://app.tryleap.ai/api/mcp ``` ```json Cursor (.cursor/mcp.json) theme={null} { "mcpServers": { "leap": { "url": "https://app.tryleap.ai/api/mcp" } } } ``` In Claude.ai or ChatGPT, add a custom connector with the URL `https://app.tryleap.ai/api/mcp`. The tools: `search_models`, `get_model`, `quote`, `generate`, `get_generation`, `cancel_generation`, `get_account` and `list_workspaces`. ## Build Leap into your app with a coding agent Give your agent this page's address, or paste this prompt: ```text theme={null} Add Leap media generation to this app. Docs: https://docs.tryleap.ai (start with /quickstart and /generations). - Call https://api.tryleap.ai from the server only, with the key from the LEAP_API_KEY env var in the x-api-key header. - Find the model with GET /v1/models and build the input from its input_schema (GET /v1/models/{creator}/{name}). - Start runs with POST /v1/generations and an idempotency-key header. Use prefer: wait=60 for images; poll GET /v1/generations/ every 3 s for video until status is succeeded, failed or canceled. - Download outputs you keep: their URLs expire after 24 hours. ``` Every page here has a copy button for pasting into an LLM. # Authentication Source: https://www.tryleap.ai/docs/authentication API keys, scopes and where to send them. Create keys at [app.tryleap.ai/go/api](https://app.tryleap.ai/go/api). A key belongs to a workspace and spends that workspace's balance. Send the key in the `x-api-key` header on every request: ```bash theme={null} curl https://api.tryleap.ai/v1/credits -H "x-api-key: $LEAP_API_KEY" ``` Keys start with `leap_`. Keep them on your server, never in a browser or a mobile app. ## Scopes | Scope | Lets the key | | - | - | | `generations:read` | list models, read quotes, read generations and the balance | | `generations:write` | start, cancel and batch generations, and upload files | ## No key needed The public catalog answers without a key, so you can browse models before you sign up: ```bash theme={null} curl https://api.tryleap.ai/v1/public/models ``` # Errors Source: https://www.tryleap.ai/docs/errors One error shape, stable codes and a request ID on every answer. Every error has the same shape: ```json theme={null} { "error": { "type": "invalid_request_error", "code": "invalid_parameter", "message": "Limit must be between 1 and 100.", "param": "limit", "request_id": "req_..." } } ``` Branch on `type` and `code`, never on `message`. Every response carries an `x-request-id` header; include it when you contact support. | Status | `type` | What to do | | - | - | - | | 400 | `invalid_request_error` | Fix the input. `param` names the field. | | 401 | `authentication_error` | Send a valid key in `x-api-key`. | | 402 | `billing_error` (`insufficient_credit`) | The balance doesn’t cover the hold. Add credits, or quote first. | | 403 | `permission_error` | The key lacks the scope. | | 409 | `conflict_error` | The idempotency key was used with a different body. | | 429 | `rate_limit_error` | Wait for `Retry-After` seconds, then retry with the same idempotency key. | | 5xx | `api_error` | Retry with backoff and the same idempotency key. | A run that fails (the model refused the prompt, or the provider errored) is not an HTTP error: the generation comes back with `status: "failed"` and an `error` object, and you are not charged. # Files and uploads Source: https://www.tryleap.ai/docs/files Send photos, video and audio as inputs. Models that edit or animate take files as input. Most inputs accept a public `https://` URL directly. To send a file you hold, upload it first and pass the URL you get back. ## Small files Send the raw bytes to `POST /v1/files`: ```bash theme={null} curl https://api.tryleap.ai/v1/files \ -H "x-api-key: $LEAP_API_KEY" \ -H "content-type: image/jpeg" \ --data-binary @portrait.jpg ``` ## Large video and audio Ask for an upload link, `PUT` the file to it, then complete the upload: ```bash theme={null} curl https://api.tryleap.ai/v1/uploads -H "x-api-key: $LEAP_API_KEY" \ -H "content-type: application/json" -d '{"content_type": "video/mp4", "bytes": 48213992}' # PUT the file to the returned url, then: curl -X POST https://api.tryleap.ai/v1/uploads/$UPLOAD_ID/complete -H "x-api-key: $LEAP_API_KEY" ``` ## Keep an output Output links expire after 24 hours. `POST /v1/generations/$GENERATION_ID/outputs/0/file` turns an output into a file of your workspace, so you can pass it to the next run. # Generations Source: https://www.tryleap.ai/docs/generations Start a run, then wait for it, poll it or cancel it. A generation is a job. Its `status` goes `queued`, then `running`, then one of `succeeded`, `failed` or `canceled`. Only a succeeded generation is charged. ## Start one ```bash theme={null} curl https://api.tryleap.ai/v1/generations \ -H "x-api-key: $LEAP_API_KEY" \ -H "content-type: application/json" \ -H "idempotency-key: 7f1c2a9e-order-1234" \ -d '{"model": "google/veo-3.1", "input": {"prompt": "A heron lands on a still lake at dawn"}}' ``` Send an `idempotency-key` you generate (a UUID works) so a retried request never starts a second run. ## Wait for the result Add `prefer: wait=N` (up to 60 seconds) to hold the request open until the run finishes. Images usually finish inside the wait. If the run is still going when the wait ends, you get it back as `queued` or `running`, and you poll. ## Poll ```bash theme={null} curl https://api.tryleap.ai/v1/generations/$GENERATION_ID -H "x-api-key: $LEAP_API_KEY" ``` ```ts TypeScript theme={null} async function waitForGeneration(id: string) { for (;;) { const response = await fetch(`https://api.tryleap.ai/v1/generations/${id}`, { headers: { "x-api-key": process.env.LEAP_API_KEY! }, }); const generation = await response.json(); if (["succeeded", "failed", "canceled"].includes(generation.status)) return generation; await new Promise((resolve) => setTimeout(resolve, 3000)); } } ``` ```python Python theme={null} import os, time, requests def wait_for_generation(generation_id): while True: generation = requests.get( f"https://api.tryleap.ai/v1/generations/{generation_id}", headers={"x-api-key": os.environ["LEAP_API_KEY"]}, ).json() if generation["status"] in ("succeeded", "failed", "canceled"): return generation time.sleep(3) ``` Poll every few seconds. Video often takes one to five minutes. Webhooks that tell your server when a run finishes are coming soon. Until then, poll or use `prefer: wait`. ## List and cancel ```bash theme={null} # Your recent runs, newest first. Filter by model or status. curl "https://api.tryleap.ai/v1/generations?status=running,queued&limit=20" -H "x-api-key: $LEAP_API_KEY" # Stop a run that hasn't finished. Its hold is released. curl -X POST https://api.tryleap.ai/v1/generations/$GENERATION_ID/cancel -H "x-api-key: $LEAP_API_KEY" ``` Lists return `{ "object": "list", "data": [...], "has_more": true, "next_cursor": "..." }`. Pass `cursor=` for the next page. ## Batches `POST /v1/batches` queues up to 50 runs in one request: `{"requests": [{"model": "...", "input": {...}}, ...]}`. # Leap API Source: https://www.tryleap.ai/docs/index One API and one balance for the best image, video and audio models. Leap runs Veo, Kling, Seedance, FLUX, GPT Image, ElevenLabs and more behind one REST API. You pay from one balance, see the price before each run, and failed runs are never charged. Make a key and get your first result in a minute. List every model and read the inputs each one takes. Wait for a result, poll for it, or cancel a run. Connect Claude Code, Cursor or any MCP client. ## How it works 1. Pick a model from `GET /v1/models`. Each model has an `input_schema` (JSON Schema) that lists what it takes. 2. Send `POST /v1/generations` with the model and its input. 3. Read the result: wait for it in the same request with `prefer: wait=60`, or poll `GET /v1/generations/:id` until the status is final. Every request goes to `https://api.tryleap.ai` with your key in the `x-api-key` header. # Models and schemas Source: https://www.tryleap.ai/docs/models List every model, read its inputs, and price a run before you start it. ## List models ```bash theme={null} curl https://api.tryleap.ai/v1/models -H "x-api-key: $LEAP_API_KEY" ``` ```json theme={null} { "object": "list", "data": [ { "id": "black-forest-labs/flux-2-pro", "object": "model", "name": "FLUX.2 [pro]", "modality": "image", "tasks": ["text-to-image"], "status": "stable", "pricing": { "unit": "image", "usd": "0.033" } } ] } ``` A model ID is `creator/name`. Presets (ready-made recipes such as `leap/restore-photo@1`) are listed with the models and run the same way. Without a key, use `GET /v1/public/models`. It returns the same catalog. ## Read a model's input schema ```bash theme={null} curl https://api.tryleap.ai/v1/models/black-forest-labs/flux-2-pro \ -H "x-api-key: $LEAP_API_KEY" ``` The answer includes `input_schema`, a JSON Schema (2020-12) of the `input` object the model takes: ```json theme={null} { "id": "black-forest-labs/flux-2-pro", "input_schema": { "type": "object", "required": ["prompt"], "properties": { "prompt": { "type": "string" }, "aspect_ratio": { "type": "string", "default": "1:1" }, "n": { "type": "integer", "default": 1 }, "seed": { "type": "integer" } } } } ``` Validate your input against it, or hand it to an LLM as a tool schema. Fields you leave out take their defaults. ## Price a run first `POST /v1/quotes` takes the same body as a generation and returns what it would cost, without running it: ```bash theme={null} curl https://api.tryleap.ai/v1/quotes \ -H "x-api-key: $LEAP_API_KEY" \ -H "content-type: application/json" \ -d '{"model": "google/veo-3.1", "input": {"prompt": "A heron lands on a still lake at dawn"}}' ``` ```json theme={null} { "object": "quote", "cost_usd": "3.20", "hold_usd": "3.20", "input": { "prompt": "...", "duration": 8 } } ``` `hold_usd` is held from your balance while the run works. You are charged `cost_usd` only if it succeeds. # Quickstart Source: https://www.tryleap.ai/docs/quickstart Your first image in one request. Open [app.tryleap.ai/go/api](https://app.tryleap.ai/go/api) and create a key. New accounts start with free credit, and no card is needed. ```bash theme={null} export LEAP_API_KEY="leap_..." ``` `prefer: wait=60` holds the request open until the result is ready, for up to 60 seconds. ```bash curl theme={null} curl https://api.tryleap.ai/v1/generations \ -H "x-api-key: $LEAP_API_KEY" \ -H "content-type: application/json" \ -H "prefer: wait=60" \ -d '{ "model": "black-forest-labs/flux-2-pro", "input": { "prompt": "A silk scarf in the wind on a ferry deck", "aspect_ratio": "4:5" } }' ``` ```ts TypeScript theme={null} const response = await fetch("https://api.tryleap.ai/v1/generations", { method: "POST", headers: { "x-api-key": process.env.LEAP_API_KEY!, "content-type": "application/json", prefer: "wait=60", }, body: JSON.stringify({ model: "black-forest-labs/flux-2-pro", input: { prompt: "A silk scarf in the wind on a ferry deck", aspect_ratio: "4:5" }, }), }); const generation = await response.json(); console.log(generation.status, generation.output[0]?.url); ``` ```python Python theme={null} import os import requests response = requests.post( "https://api.tryleap.ai/v1/generations", headers={"x-api-key": os.environ["LEAP_API_KEY"], "prefer": "wait=60"}, json={ "model": "black-forest-labs/flux-2-pro", "input": {"prompt": "A silk scarf in the wind on a ferry deck", "aspect_ratio": "4:5"}, }, ) generation = response.json() print(generation["status"], generation["output"][0]["url"]) ``` ```json theme={null} { "id": "gen_8lz2...", "object": "generation", "model": "black-forest-labs/flux-2-pro", "status": "succeeded", "output": [{ "type": "image", "url": "https://...", "content_type": "image/jpeg" }], "usage": { "cost_usd": "0.033" } } ``` Output links expire after 24 hours. Download what you keep. Reading the generation again signs fresh links. Video takes longer than 60 seconds. If the status is still `queued` or `running` when the wait ends, poll it. See [Generations](/docs/generations).