# Figgshield — complete documentation > Figgshield is an MCP server and CLI tool for generating AI video and images. Add it to > Claude (as a connector) or the Claude Code CLI and generate video with Kling and images > with Nano Banana 2 by prompting; credits are metered and billed via an annual > subscription. A REST API at https://api.figgshield.ai is the non-MCP option, > authenticated with `Authorization: Bearer figg_...` API keys. Every page of the human > documentation has a Markdown twin at the same URL with `.md` appended. # Figgshield overview > What Figgshield is — an MCP server and CLI tool for generating video with Kling and images with Nano Banana 2 inside Claude — plus a five-minute quickstart to add it and generate. Figgshield is an **MCP server and CLI tool**. You add it to **Claude** (as a connector) or the **Claude Code CLI**, then generate **video with Kling** and **images with Nano Banana 2** by asking in plain language. Figgshield runs the job, meters the credits, and hands back a file. The web app is only for account management — signing in, choosing a plan, and managing API keys. There are two models and one credit balance: | Model | Kind | Credits | Options | | --- | --- | --- | --- | | **Kling** | video | 35 (5s) · 70 (5s + audio or 10s) | durations 5/10s, 720p/1080p, optional audio | | **Nano Banana 2** | image | 8 | 1K / 2K / 4K | ## Ways to use it | Surface | How | Auth | | --- | --- | --- | | **Claude** (Desktop / web) | Add Figgshield as a connector under Settings → Connectors | Browser sign-in (OAuth) | | **Claude Code CLI** | `claude mcp add --transport http figgshield https://api.figgshield.ai/mcp` | `claude mcp login` (OAuth) or an API key header | | **REST API** (non-MCP) | `POST https://api.figgshield.ai/api/generations/create/` | `Authorization: Bearer figg_...` API key | Everything shares one account, one plan and one credit balance. Every page of this documentation has a Markdown twin at the same URL with `.md` appended (this page: [`/documentation/index.md`](https://figgshield.ai/documentation/index.md)). There is also an [llms.txt](https://figgshield.ai/llms.txt) index, the [complete docs in one file](https://figgshield.ai/llms-full.txt), and a machine-readable [OpenAPI 3.1 specification](https://figgshield.ai/openapi.json). ## Five-minute quickstart: add to Claude and generate You need a Figgshield account with an active subscription — any plan works. Sign in at the app with Google, Apple or GitHub and pick a plan; then connect Claude. ### 1. Add the connector In **Claude Desktop or claude.ai**, open **Settings → Connectors → Add custom connector** and paste the MCP endpoint: ```text https://api.figgshield.ai/mcp ``` Claude opens a browser sign-in. Approve the two scopes (`figgshield:read`, `figgshield:write`) and the connector is ready. See [MCP server & tools](https://figgshield.ai/documentation/mcp.md) for the full walkthrough, the config JSON and every tool. ### 2. Ask for a generation Prompt Claude in plain language: ```text Generate a 5-second video of a quiet harbour at dawn, mist lifting off the water. ``` Claude calls Figgshield's `generate_video` tool, which runs Kling, spends 35 credits, and returns a generation id plus an `output_url` once the clip is ready. For an image, just ask for one — Claude calls `generate_image`, which runs Nano Banana 2 for 8 credits. ### 3. Get the file Video jobs take tens of seconds; Claude polls `get_generation` for you and hands back the download link. Images usually return in one step. Ask Claude to _"show my recent generations"_ and it calls `list_library`; ask _"how many credits do I have left"_ and it calls `get_usage`. That is the whole loop: connect once, then ask. No keys to paste, nothing to poll by hand. ### Prefer the CLI or a script? - [Claude Code CLI](https://figgshield.ai/documentation/cli.md) — `claude mcp add` then `claude mcp login`, or a personal API key header. - [Generations (REST)](https://figgshield.ai/documentation/generations.md) — the non-MCP path: create a key, `POST` a job, poll it, download the output. ## Where to go next - [MCP server & tools](https://figgshield.ai/documentation/mcp.md) — add the connector, the five tools, example prompts, config JSON. - [Claude Code CLI](https://figgshield.ai/documentation/cli.md) — loopback sign-in and the API-key alternative. - [Authentication](https://figgshield.ai/documentation/authentication.md) — SSO sign-in, OAuth for the connector, personal API keys. - [Models](https://figgshield.ai/documentation/models.md) — Kling and Nano Banana 2, parameters and credit costs. - [Generations (REST)](https://figgshield.ai/documentation/generations.md) — the full REST job lifecycle for non-MCP clients. - [Usage & credits](https://figgshield.ai/documentation/usage.md) — usage summary and the credit ledger. - [Billing & top-ups](https://figgshield.ai/documentation/billing.md) — the four plans, annual billing, and top-ups. - [Errors](https://figgshield.ai/documentation/errors.md) — every machine code, its HTTP status, and what to do about it. --- # MCP server & tools > Add Figgshield as an MCP connector in Claude or the Claude Code CLI, the five tools (generate_image, generate_video, get_generation, list_library, get_usage), example prompts, config JSON and OAuth discovery. Figgshield is a remote **MCP server** — a single Streamable HTTP endpoint that Claude and the Claude Code CLI call to generate video and images. It implements the MCP spec `2025-11-25` (with `2025-06-18` compatibility). | Item | Value | | --- | --- | | MCP endpoint | `https://api.figgshield.ai/mcp` | | Transport | Streamable HTTP (`POST` / `GET` / `DELETE`) | | Auth | OAuth 2.1 (browser sign-in) **or** `Authorization: Bearer figg_...` API key | | Models | Kling (video), Nano Banana 2 (image) | ## Add Figgshield to Claude ### Claude Desktop or claude.ai 1. Open **Settings → Connectors**. 2. Choose **Add custom connector**. 3. Paste the endpoint `https://api.figgshield.ai/mcp` and save. 4. Claude opens a browser sign-in. Sign in with Google, Apple or GitHub and approve the scopes `figgshield:read` and `figgshield:write`. The connector is registered automatically (Dynamic Client Registration), so there is nothing to configure by hand. Tokens refresh on their own; you will not be asked to sign in again unless you revoke access. ### Claude Code CLI ```bash claude mcp add --transport http figgshield https://api.figgshield.ai/mcp claude mcp login figgshield ``` `claude mcp login` runs a browser sign-in (loopback PKCE) and stores the token. Full details, and the API-key alternative, are in [Claude Code CLI](https://figgshield.ai/documentation/cli.md). ### Config JSON Clients that read an MCP config file (for example `claude_desktop_config.json`) can declare Figgshield directly: ```json { "mcpServers": { "figgshield": { "type": "http", "url": "https://api.figgshield.ai/mcp" } } } ``` On first use the client runs the OAuth flow above. To use an API key instead of the browser flow, add a header: ```json { "mcpServers": { "figgshield": { "type": "http", "url": "https://api.figgshield.ai/mcp", "headers": { "Authorization": "Bearer figg_your_api_key_here" } } } } ``` ## Tools Figgshield exposes five tools. The two generate tools spend credits (with auto top-up if enabled) and state the model they used; the other three are read-only. ### `generate_image` Runs **Nano Banana 2**. Burns **8 credits**. | Param | Type | Notes | | --- | --- | --- | | `prompt` | string | What to generate. Required. | | `resolution` | string | Optional. `"1K"`, `"2K"` or `"4K"` (default `"1K"`). | Returns `{ generation_uuid, model: "Nano Banana 2", status, output_url?, credits_charged }`. ### `generate_video` Runs **Kling**. Burns **35 credits** for a 5-second clip; **70** for 10 seconds or with audio. | Param | Type | Notes | | --- | --- | --- | | `prompt` | string | What to generate. Required. | | `duration` | integer | Optional. `5` or `10` seconds (default `5`). | | `resolution` | string | Optional. `"720p"` or `"1080p"` (default `"720p"`). | | `audio` | boolean | Optional. Default `false`; `true` doubles the credit cost. | Returns `{ generation_uuid, model: "Kling", status, output_url?, credits_charged }`. ### `get_generation` Polls a job to completion. Read-only. | Param | Type | Notes | | --- | --- | --- | | `generation_uuid` | string | The id returned by a generate tool. Required. | Returns `{ status, output_url?, error? }`. `status` is `queued`, `running`, `succeeded` or `failed`. ### `list_library` Recent generations, newest first. Read-only. | Param | Type | Notes | | --- | --- | --- | | `limit` | integer | Optional. How many to return. | | `kind` | string | Optional. `"video"` or `"image"` to filter. | Returns `[{ uuid, model, kind, prompt, status, output_url, created_at }]`. ### `get_usage` Current plan and credit balance. Read-only. Returns `{ plan, credits: { balance, granted_this_period, used_this_period }, jobs }`. ## Example prompts Once connected, ask Claude in plain language — it picks the tool and the model: ```text Generate a 5-second video of a quiet harbour at dawn, mist lifting off the water. Make a 10-second clip with audio of rain on a city street at night. Create a 2K image of a paper boat on a still pond, top-down. Show my last five generations. How many credits do I have left this month? ``` ## Credit checks and errors Each generate tool runs a **pre-flight credit check**. If your balance cannot cover the job it surfaces as a tool error: `insufficient_credits` (top up or enable auto top-up) or `subscription_required` (no active plan). With [auto top-up](https://figgshield.ai/documentation/billing.md) enabled, the top-up is attempted first. Failed generations are refunded automatically. ## OAuth discovery Figgshield is an OAuth 2.1 resource server with a co-hosted authorization server; PKCE (S256) is required and Google/Apple/GitHub are the upstream identity providers. An unauthenticated `/mcp` request returns `401` with a `WWW-Authenticate: Bearer resource_metadata="..."` header pointing at the protected-resource metadata. Clients discover the rest from these documents: | Document | URL | | --- | --- | | Protected resource metadata (RFC 9728) | `https://api.figgshield.ai/.well-known/oauth-protected-resource` | | Authorization server metadata (RFC 8414) | `https://api.figgshield.ai/.well-known/oauth-authorization-server` | | OpenID configuration | `https://api.figgshield.ai/.well-known/openid-configuration` | | JWKS | `https://api.figgshield.ai/jwks.json` | Claude performs this discovery for you. See [Authentication](https://figgshield.ai/documentation/authentication.md) for the token flow and the API-key alternative. --- # Claude Code CLI > Use Figgshield from the Claude Code CLI: claude mcp add plus claude mcp login (loopback PKCE), or the personal API-key header alternative, then generate by prompting. The Claude Code CLI talks to Figgshield over the same [MCP endpoint](https://figgshield.ai/documentation/mcp.md) as the Claude connector. You add the server once, sign in, then ask Claude Code to generate — it calls Figgshield's tools for you. ## Add the server ```bash claude mcp add --transport http figgshield https://api.figgshield.ai/mcp ``` This registers a server named `figgshield` on the HTTP transport. Confirm it is listed: ```bash claude mcp list ``` ## Sign in (browser OAuth) ```bash claude mcp login figgshield ``` `claude mcp login` runs an **authorization-code + PKCE** flow over a loopback redirect: it opens your browser, you sign in with Google, Apple or GitHub and approve the `figgshield:read` and `figgshield:write` scopes, and the CLI stores the token. Tokens refresh automatically, so this is a one-time step. To sign out: ```bash claude mcp logout figgshield ``` ## API-key alternative Instead of the browser flow you can authenticate with a **personal API key**. Create one in the app under **Account → API keys** (it looks like `figg_` followed by 40 hex characters, shown once) and pass it as an `Authorization` header when adding the server: ```bash claude mcp add --transport http figgshield https://api.figgshield.ai/mcp \ --header "Authorization: Bearer figg_your_api_key_here" ``` With the header set there is no `claude mcp login` step — every request carries the key. Keys can be named, rotated and revoked independently in the account screen; see [Authentication](https://figgshield.ai/documentation/authentication.md). ## Generate Once the server is added and authenticated, prompt Claude Code as usual: ```text Generate a 5-second video of a quiet harbour at dawn. Create a 4K image of a paper boat on a still pond. List my recent Figgshield generations. ``` Claude Code calls `generate_video` (Kling) or `generate_image` (Nano Banana 2), polls `get_generation` for longer jobs, and gives you the `output_url` to download. The [MCP tools reference](https://figgshield.ai/documentation/mcp.md) lists every tool and its parameters. ## Skills A Claude skill that uses Figgshield inherits the host's authentication — if Claude Code is signed in to the `figgshield` server (via OAuth or an API-key header), the skill can call the tools without any extra setup. ## Troubleshooting | Symptom | Fix | | --- | --- | | `401` / repeated sign-in prompts | Run `claude mcp login figgshield` again, or check the API-key header is a current, unrevoked key. | | `subscription_required` tool error | The account has no active plan — subscribe in the app, then retry. | | `insufficient_credits` tool error | Top up or enable [auto top-up](https://figgshield.ai/documentation/billing.md); the next monthly grant also refills the balance. | | Server not found | Re-check the transport and URL: `claude mcp add --transport http figgshield https://api.figgshield.ai/mcp`. | --- # Authentication > How Figgshield authenticates: SSO sign-in (Google, Apple, GitHub), OAuth 2.1 for the MCP connector and CLI, and personal API keys (Authorization: Bearer figg_...) for the CLI and REST. Figgshield has three ways in, for three purposes: | Purpose | Mechanism | | --- | --- | | Sign in to the web app | **SSO** — Google, Apple or GitHub | | Connect Claude or the Claude Code CLI | **OAuth 2.1** (browser sign-in, PKCE) | | CLI header or the REST API | **Personal API key** (`Authorization: Bearer figg_...`) | There is no email/password sign-in and no email one-time-code step — sign-in is SSO only. ## Signing in (SSO) The web app authenticates with one of three identity providers: **Google, Apple and GitHub**. Sign-in creates or links your account by email and sets an HttpOnly session cookie named `token`; the app uses that cookie for account, plan and key management. There is nothing to configure — pick a provider on the sign-in screen. `GET /authentication/social/config/` reports which providers are available, so the app can hide any that are not configured: ```bash curl https://api.figgshield.ai/authentication/social/config/ ``` ```json { "google": true, "apple": true, "github": true } ``` The current user is read with `GET /authentication/me/` (session cookie), and `POST /authentication/logout/` clears the cookie. ## OAuth for the connector and CLI Adding Figgshield to **Claude** (as a connector) or the **Claude Code CLI** uses OAuth 2.1, not a session cookie. Figgshield is the authorization server; Google, Apple and GitHub are the upstream identity providers it federates to. You never paste a token — the client runs the flow: 1. The client requests `https://api.figgshield.ai/mcp` unauthenticated and receives `401` with a `WWW-Authenticate` header pointing at the protected-resource metadata. 2. It discovers the authorization server, then opens a browser for you to sign in (SSO) and approve the scopes `figgshield:read` and `figgshield:write`. 3. It exchanges an authorization code (PKCE, S256) for a JWT access token and refreshes it automatically. Discovery documents: | Document | URL | | --- | --- | | Protected resource metadata (RFC 9728) | `https://api.figgshield.ai/.well-known/oauth-protected-resource` | | Authorization server metadata (RFC 8414) | `https://api.figgshield.ai/.well-known/oauth-authorization-server` | | JWKS | `https://api.figgshield.ai/jwks.json` | See [MCP server & tools](https://figgshield.ai/documentation/mcp.md) and [Claude Code CLI](https://figgshield.ai/documentation/cli.md) for the client-side steps. Claude registers itself automatically (Dynamic Client Registration), so private connectors need no manual client setup. ## Personal API keys An API key authenticates the **Claude Code CLI** (as a header) and the **REST API** without a browser flow. A key acts with the same permissions as the account that owns it. Create keys in the app under **Account → API keys**. A key looks like `figg_` followed by 40 hex characters: ```text figg_1f2e3d4c5b6a79880716253443526170817263f4 ``` The full secret is shown **once**, at creation — Figgshield stores only a SHA-256 hash and the first 12 characters as a display `prefix`. If you lose a key, revoke it and create a new one. An account can hold at most **20 active keys**. Send the key on every request with the `Authorization: Bearer` header (or `X-API-Key`): ```bash curl https://api.figgshield.ai/api/models/ \ -H "Authorization: Bearer $FIGGSHIELD_API_KEY" ``` For the Claude Code CLI, pass it when you add the server: ```bash claude mcp add --transport http figgshield https://api.figgshield.ai/mcp \ --header "Authorization: Bearer figg_your_api_key_here" ``` A revoked or unknown key returns `401` with the machine code `invalid_api_key`: ```json { "error": "invalid_api_key", "detail": "This API key is invalid or has been revoked." } ``` ### Managing keys over the REST API Key management also works over the API, so keys can rotate keys. Each call accepts a session cookie or an API key. ```bash # Create curl https://api.figgshield.ai/api/keys/create/ -X POST \ -H "Authorization: Bearer $FIGGSHIELD_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "ci-pipeline" }' # List curl https://api.figgshield.ai/api/keys/ \ -H "Authorization: Bearer $FIGGSHIELD_API_KEY" # Revoke curl https://api.figgshield.ai/api/keys//revoke/ -X POST \ -H "Authorization: Bearer $FIGGSHIELD_API_KEY" ``` Create returns `201` and is the only response that ever contains the full `key`. List returns the standard envelope with `uuid`, `name`, `prefix`, `last_used_at`, `revoked` and `created_at` — never the secret. Revoke returns `200 {"revoked": true}`, is idempotent, and frees the key from the 20-key cap. ## Session cookies (browser) The web app authenticates with the HttpOnly `token` cookie set at SSO sign-in and cleared by `POST /authentication/logout/`. Browser clients send it automatically with `credentials: "include"`. The cookie is for the account screens; programmatic clients should use OAuth (for MCP) or an API key (for the CLI header and REST). --- # Models > The two live models — Kling for video and Nano Banana 2 for images — with their parameters, live status semantics and per-generation credit costs. Figgshield runs two models: **Kling** for video and **Nano Banana 2** for images. Both are reachable the same way — through Claude, the Claude Code CLI, or the REST API — and draw on the same credit balance. In Claude you rarely name a model; you ask for a video or an image and Figgshield routes to the right one. ## List models `GET /api/models/` — public, no authentication required. ```bash curl https://api.figgshield.ai/api/models/ ``` Returns the standard list envelope. Each item: ```json { "uuid": "3c2b1a09-8f7e-4d6c-5b4a-392817065e4d", "slug": "kling-video", "name": "Kling", "provider": "fal", "kind": "video", "description": "Cinematic motion in 5 or 10-second clips, with optional audio.", "credits_base": 35, "status": "online", "sort_order": 10, "params_schema": { "durations": [5, 10], "resolutions": ["720p", "1080p"], "audio": true, "aspect_ratios": ["16:9", "9:16"] } } ``` ## Fields | Field | Type | Meaning | | --- | --- | --- | | `slug` | string | Stable identifier — `kling-video` or `nano-banana-2`. Pass as `model` when [creating a generation](https://figgshield.ai/documentation/generations.md) over REST. | | `name` | string | Display name (`Kling`, `Nano Banana 2`). | | `provider` | string | Hosting provider (`fal` for Kling, `google` for Nano Banana 2). Informational. | | `kind` | string | `video` or `image` — determines which params apply. | | `description` | string | One-line description. | | `credits_base` | integer | Base credits per generation (35 for Kling, 8 for Nano Banana 2). Duration and audio can multiply it — see below. | | `status` | string | `online`, `degraded` or `offline` from live health checks. | | `sort_order` | integer | Suggested display order. | | `params_schema` | object | The values this model accepts. | ## The two models ### Kling — video | | | | --- | --- | | Slug | `kling-video` | | Durations | 5 or 10 seconds | | Resolutions | 720p, 1080p | | Audio | Optional, default off (doubles the credit cost) | | Base cost | 35 credits | ### Nano Banana 2 — image | | | | --- | --- | | Slug | `nano-banana-2` | | Resolutions | 1K, 2K, 4K | | Base cost | 8 credits | ## Credit costs Costs are fixed per generation; `credits_base` is the authoritative base. For Kling, a **10-second** clip and **audio** each double the cost: | Generation | Kind | Credits | | --- | --- | --- | | Nano Banana 2 image (1K / 2K / 4K) | image | 8 | | Kling — 5-second clip (720p / 1080p) | video | 35 | | Kling — 5-second clip with audio | video | 70 | | Kling — 10-second clip | video | 70 | The same credits work across both models; there are no per-model plans or multipliers beyond duration and audio. What a credit costs in money depends on your plan — see [Billing & top-ups](https://figgshield.ai/documentation/billing.md). ## Status semantics | Status | Meaning | What to do | | --- | --- | --- | | `online` | Healthy; generations run normally. | Use freely. | | `degraded` | The provider is up but slow or intermittently failing (failures are auto-refunded). | Expect longer waits; retry if needed. | | `offline` | The provider is down. Creating a generation returns `503 model_unavailable`. | Retry later. | --- # Generations (REST) > The non-MCP path: create Kling video and Nano Banana 2 image jobs over REST, poll them to completion, list and delete them, and how credits are charged and refunded. This is the **REST API** for generations — the non-MCP way to drive Figgshield from your own tools and scripts. In Claude or the Claude Code CLI you would use the [MCP tools](https://figgshield.ai/documentation/mcp.md) (`generate_video`, `generate_image`) instead; both paths run the same models against the same credit balance. A generation is one video or image job. The lifecycle is asynchronous: you create a job, it moves through `queued → running`, and it ends as `succeeded` (with an `output_url`) or `failed` (credits refunded automatically). ## The generation object ```json { "uuid": "0b8f6a2e-4c1d-4f7a-9b2e-6d3c8a1f5e90", "model": "kling-video", "model_name": "Kling", "kind": "video", "prompt": "A slow dolly shot across a quiet harbour at dawn", "params": { "duration": 5, "resolution": "720p", "audio": false, "aspect_ratio": "16:9" }, "status": "succeeded", "output_url": "https://cdn.figgshield.ai/outputs/0b8f6a2e.mp4", "thumbnail_url": "https://cdn.figgshield.ai/thumbs/0b8f6a2e.jpg", "credits_charged": 35, "error_message": null, "created_at": "2026-07-06T09:00:00Z", "completed_at": "2026-07-06T09:00:48Z", "duration_ms": 48000, "is_watermarked": false } ``` `status` is one of `queued`, `running`, `succeeded`, `failed`. `output_url` and `thumbnail_url` are `null` until the job succeeds; `error_message` is set only on failure. `is_watermarked` is always `false` — outputs are never watermarked. ## Create a generation `POST /api/generations/create/` ```bash # Kling video (35 credits) curl https://api.figgshield.ai/api/generations/create/ \ -X POST \ -H "Authorization: Bearer $FIGGSHIELD_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "kling-video", "prompt": "A slow dolly shot across a quiet harbour at dawn", "params": { "duration": 5, "resolution": "720p", "audio": false } }' ``` ```bash # Nano Banana 2 image (8 credits) curl https://api.figgshield.ai/api/generations/create/ \ -X POST \ -H "Authorization: Bearer $FIGGSHIELD_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "nano-banana-2", "prompt": "A paper boat on a still pond, top-down", "params": { "resolution": "2K" } }' ``` Returns `201` with the new generation (`status: "queued"`). ### Request body | Field | Type | Notes | | --- | --- | --- | | `model` | string | `kling-video` or `nano-banana-2` (from [`GET /api/models/`](https://figgshield.ai/documentation/models.md)). | | `prompt` | string | What to generate. | | `params` | object | Optional settings; allowed keys depend on the model — see below. | ### Params by model | Param | Applies to | Example | Notes | | --- | --- | --- | --- | | `duration` | Kling | `5` | 5 or 10 seconds. 10 doubles the cost. | | `resolution` | Kling | `"720p"` | `720p` or `1080p`. | | `audio` | Kling | `false` | Default off; `true` doubles the cost. | | `resolution` | Nano Banana 2 | `"2K"` | `1K`, `2K` or `4K`. | | `aspect_ratio` | both | `"16:9"` | Optional. | Omitted params fall back to defaults. A value outside the model's schema returns `400 validation_error`. ### Credits: pre-flight check, charge, refund - The credit cost is checked **before** dispatch. If your balance cannot cover it, the request fails with `402 insufficient_credits` and nothing is charged. Kling is 35 credits (70 for 10 seconds or with audio); Nano Banana 2 is 8. - With [automatic top-ups](https://figgshield.ai/documentation/billing.md) enabled, the top-up runs first and the pre-flight check happens after it. - On success the cost is recorded as `credits_charged` and appears in the [ledger](https://figgshield.ai/documentation/usage.md) as a `burn`. - If the job **fails**, the charged credits are refunded automatically (ledger entry `refund`). You only pay for output. ### Error responses | Status | Code | Meaning | | --- | --- | --- | | `400` | `validation_error` | Unknown model slug, bad prompt, or params outside the model's schema. | | `402` | `insufficient_credits` | Balance cannot cover the cost (after any automatic top-up attempt). | | `402` | `subscription_required` | The account has no active subscription. | | `409` | `parallel_limit_reached` | As many jobs already in flight as your plan allows — wait for one to finish. | | `503` | `model_unavailable` | The model is offline or its provider is not responding. Retry later. | See [Errors](https://figgshield.ai/documentation/errors.md) for the full envelope and handling advice. ## Poll a generation `GET /api/generations/{uuid}/` — **the polling endpoint.** Reading it refreshes the job's provider status; the backend throttles provider polls to at most one per 2 seconds per job, so poll at a **2-second interval or slower**. ```bash while true; do BODY=$(curl -s "https://api.figgshield.ai/api/generations/$GENERATION_UUID/" \ -H "Authorization: Bearer $FIGGSHIELD_API_KEY") STATUS=$(echo "$BODY" | jq -r .status) [ "$STATUS" = "succeeded" ] && { echo "$BODY" | jq -r .output_url; break; } [ "$STATUS" = "failed" ] && { echo "$BODY" | jq -r .error_message >&2; exit 1; } sleep 2 done ``` Kling clips typically take tens of seconds; Nano Banana 2 images usually finish in seconds. ## List generations `GET /api/generations/` — your own generations, newest first (`-created_at`), in the standard list envelope. Page through with `?page=N`. ```bash curl "https://api.figgshield.ai/api/generations/?page=1" \ -H "Authorization: Bearer $FIGGSHIELD_API_KEY" ``` ## Delete a generation `DELETE /api/generations/{uuid}/` — soft delete; the generation disappears from your list. Deleting does not refund credits (only failure does). ```bash curl https://api.figgshield.ai/api/generations/$GENERATION_UUID/ \ -X DELETE \ -H "Authorization: Bearer $FIGGSHIELD_API_KEY" ``` Returns `204 No Content`. --- # Usage & credits > The usage summary endpoint — plan, balance, in-flight jobs, 30-day history — and the credit ledger with its entry types. Also backs the get_usage MCP tool. Two read-only endpoints answer "where do my credits stand" and "where did they go": a current-period summary and an append-only ledger. The summary is also what the [`get_usage`](https://figgshield.ai/documentation/mcp.md) MCP tool returns, so asking Claude _"how many credits do I have left"_ reads the same data. ## Usage summary `GET /api/usage/summary/` ```bash curl https://api.figgshield.ai/api/usage/summary/ \ -H "Authorization: Bearer $FIGGSHIELD_API_KEY" ``` ```json { "plan": { "slug": "pro", "name": "Pro", "monthly_credits": 1100, "parallel_limit": 5, "price_monthly_cents": 2900 }, "credits": { "balance": 812, "used_this_period": 288, "granted_this_period": 1100, "rollover": 0, "period_start": "2026-07-01T00:00:00Z", "period_end": "2026-08-01T00:00:00Z" }, "jobs": { "in_flight": 1, "parallel_limit": 5 }, "history": [ { "date": "2026-07-01", "credits_used": 78, "generations": 4 } ], "by_model": [ { "model": "Kling", "credits": 210, "count": 6 }, { "model": "Nano Banana 2", "credits": 64, "count": 8 } ] } ``` | Field | Meaning | | --- | --- | | `plan` | Your current plan. `null` if the account has no active subscription (in that state the balance is 0 and creating generations returns `402 subscription_required`). | | `credits.balance` | Spendable credits right now, including rollover and top-ups. | | `credits.used_this_period` / `granted_this_period` | Burn and grant totals for the current monthly credit period. | | `credits.rollover` | Credits carried over from earlier periods. | | `credits.period_start` / `period_end` | Bounds of the current monthly credit period. | | `jobs` | In-flight generations versus your plan's parallel limit — useful for avoiding `409 parallel_limit_reached`. | | `history` | Last 30 days of `credits_used` and `generations` per day. | | `by_model` | Credit and generation totals per model (Kling, Nano Banana 2) for the current period. | A cheap pre-flight pattern: read `credits.balance` and `jobs.in_flight` before submitting a batch, then submit up to `parallel_limit - in_flight` jobs whose combined cost fits the balance. ## Credit ledger `GET /api/ledger/` — every credit movement on your account, newest first, read-only, in the standard list envelope (`?page=N` to page). ```bash curl "https://api.figgshield.ai/api/ledger/?page=1" \ -H "Authorization: Bearer $FIGGSHIELD_API_KEY" ``` Each entry: ```json { "uuid": "9a8b7c6d-5e4f-4a3b-2c1d-0e9f8a7b6c5d", "entry_type": "burn", "amount": -35, "balance_after": 812, "description": "Kling generation 0b8f6a2e", "created_at": "2026-07-06T09:00:00Z" } ``` ### Entry types | `entry_type` | Direction | When it happens | | --- | --- | --- | | `grant` | + | Monthly plan credits land at the start of a credit period. | | `burn` | − | A generation is charged. | | `refund` | + | A failed generation returns its charge automatically. | | `rollover` | + | Unused credits carried into a new period. | | `expiry` | − | Rolled-over credits age out, or the subscription lapses. | | `topup` | + | A manual or automatic [top-up](https://figgshield.ai/documentation/billing.md) is credited. | `amount` is signed; `balance_after` is the running balance, so the ledger reconciles exactly against `credits.balance` in the summary. --- # Billing & top-ups > The three plans (Starter, Pro, Studio), annual-only billing, checkout and portal, manual top-ups from $50, automatic top-ups, and the credit conversion formula. Figgshield has three paid plans, billed **annually only**. Prices are displayed per month; the charge is always twelve times the monthly sticker, once a year. Credits are granted monthly regardless. There is no free tier. ## Plans `GET /api/billing/plans/` — public, no authentication. ```bash curl https://api.figgshield.ai/api/billing/plans/ ``` ```json [ { "slug": "pro", "name": "Pro", "price_monthly_cents": 2900, "price_yearly_cents": 34800, "monthly_credits": 1100, "parallel_limit": 5, "features": ["1,100 credits a month", "5 generations in parallel"], "highlight": true } ] ``` The three plans: | Plan | Sticker | Charged annually | Credits / month | Parallel jobs | ≈ images or clips | | --- | --- | --- | --- | --- | --- | | Starter | $12/month | $144/year | 400 | 3 | 50 images / 11 clips | | Pro (highlighted) | $29/month | $348/year | 1,100 | 5 | 137 images / 31 clips | | Studio | $75/month | $900/year | 3,000 | 8 | 375 images / 85 clips | `price_monthly_cents` is the display sticker; `price_yearly_cents = 12 × sticker` is the only amount ever charged. `highlight` marks the plan to present as the default (Pro). Capacity figures assume 8-credit Nano Banana 2 images and 35-credit Kling clips. ## Billing status `GET /api/billing/status/` ```bash curl https://api.figgshield.ai/api/billing/status/ \ -H "Authorization: Bearer $FIGGSHIELD_API_KEY" ``` ```json { "plan": { "slug": "pro", "name": "Pro", "parallel_limit": 5 }, "status": "active", "interval": "yearly", "current_period_end": "2027-07-01T00:00:00Z", "cancel_at_period_end": false, "processor": "stripe", "has_payment_method": true } ``` `interval` is always `"yearly"`. `plan` is `null` while the account has no active subscription — in that state generation creation returns `402 subscription_required`. `has_payment_method` tells you whether automatic top-ups can be enabled. ## Checkout `POST /api/billing/checkout/` with `{"plan": ""}` — returns a Stripe Checkout URL to complete in a browser. Billing is annual; an `interval` field, if sent, is ignored. ```bash curl https://api.figgshield.ai/api/billing/checkout/ \ -X POST \ -H "Authorization: Bearer $FIGGSHIELD_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "plan": "pro" }' ``` ```json { "checkout_url": "https://checkout.stripe.com/c/pay/cs_..." } ``` `POST /api/billing/portal/` returns a `portal_url` to the Stripe billing portal for managing the payment method, invoices and cancellation. ## Top-ups Top-ups buy extra credits between grants, at your plan's rate. The conversion formula: ```text credits = floor(amount_cents × plan.monthly_credits ÷ plan.price_monthly_cents) ``` For example, a $50 top-up on Pro: `floor(5000 × 1100 ÷ 2900)` = **1,896 credits**. The minimum top-up is **5000 cents ($50)** — below that the request fails with `400 validation_error`. Top-ups require an active subscription. ### Manual top-up `POST /api/billing/topup/` with `{"amount_cents": }` — returns a Stripe Checkout URL (one-off payment). The credits land as a ledger entry of type `topup` once payment completes. ```bash curl https://api.figgshield.ai/api/billing/topup/ \ -X POST \ -H "Authorization: Bearer $FIGGSHIELD_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "amount_cents": 5000 }' ``` ### Automatic top-ups `GET /api/billing/topup/settings/` / `PATCH` the same URL: ```bash curl https://api.figgshield.ai/api/billing/topup/settings/ \ -X PATCH \ -H "Authorization: Bearer $FIGGSHIELD_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "auto_topup_enabled": true, "auto_topup_amount_cents": 5000, "auto_topup_threshold_credits": 50 }' ``` | Field | Meaning | | --- | --- | | `auto_topup_enabled` | Enabling requires an active subscription and a payment method on file (`has_payment_method`). | | `auto_topup_amount_cents` | Amount charged per automatic top-up; minimum 5000 ($50). | | `auto_topup_threshold_credits` | Balance level that triggers a top-up; must be ≥ 0. | | `preview_credits` | Read-only: how many credits the configured amount buys at your current plan rate. | When enabled, an automatic top-up fires in two situations, server-side and atomically: 1. **On generation create**, if your balance cannot cover the job's cost: the saved payment method is charged off-session, credits are granted, and the generation proceeds. If the payment fails, the request returns `402 insufficient_credits`. 2. **After any burn** that leaves the balance below `auto_topup_threshold_credits`. At most **one automatic top-up per hour** fires, as a guard against loops. ## Webhooks `POST /api/billing/webhooks/stripe/` (signature-verified) receives payment events from Stripe and fast-acknowledges with `200`. It is called by Stripe, not by API clients — you never need to call it. Affiliate commission payouts run through Stripe Connect off the same `invoice.paid` events. --- # Errors > The error envelope and every machine code with its HTTP status, what it means, and what your client should do about it. Every error is JSON with the same two-field envelope: a stable machine code for your code to branch on, and a human sentence for logs and messages. ```json { "error": "insufficient_credits", "detail": "This generation costs 35 credits but your balance is 12." } ``` `error` values are stable identifiers — match on them, not on `detail`, which can change wording at any time. ```bash curl -s https://api.figgshield.ai/api/generations/create/ \ -X POST \ -H "Authorization: Bearer $FIGGSHIELD_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "kling-video", "prompt": "..." }' | jq -r .error ``` ## Machine codes | Code | HTTP | Meaning | What to do | | --- | --- | --- | --- | | `validation_error` | 400 | The request body is malformed or a value is out of range — bad params for the model, a top-up under $50, a key name over 64 characters. | Fix the request. `detail` names the offending field. Do not retry unchanged. | | `invalid_api_key` | 401 | The API key is unknown or revoked, or the `Authorization`/`X-API-Key` header is malformed. | Check the key was copied in full (`figg_` + 40 hex). If revoked, create a new key in Account → API keys. Do not retry with the same key. | | `insufficient_credits` | 402 | Your balance cannot cover the generation's cost — including the case where an automatic top-up was attempted and its payment failed. | [Top up](https://figgshield.ai/documentation/billing.md), enable auto top-ups, or wait for the next monthly grant. | | `subscription_required` | 402 | The account has no active subscription — required for generations and top-ups. | Subscribe via `POST /api/billing/checkout/` or in the app, then retry. | | `admin_required` | 403 | A non-staff account called a staff-only endpoint such as [`GET /api/admin/metrics/`](https://figgshield.ai/documentation/admin.md). | Not retryable — the endpoint requires a staff account. | | `not_found` | 404 | No such resource, or it belongs to another account — objects are owner-scoped, so someone else's generation UUID also returns this. | Check the UUID and the account the key belongs to. | | `parallel_limit_reached` | 409 | As many generations already in flight as your plan allows. | Poll until one finishes, then retry. `jobs` in the [usage summary](https://figgshield.ai/documentation/usage.md) shows in-flight versus limit. | | `rate_limited` | 429 | Too many requests. | Back off exponentially and retry. Polling generation detail more often than every 2 seconds serves no purpose anyway. | | `model_unavailable` | 503 | The requested model (Kling or Nano Banana 2) is offline or its provider is not responding. | Check [`GET /api/models/`](https://figgshield.ai/documentation/models.md) for `status`; retry later. Nothing was charged. | Over MCP, the same conditions surface as **tool errors** — for example a `generate_video` call returns an `insufficient_credits` or `subscription_required` error rather than an HTTP status. ## Handling guidance - **4xx except 409/429** — a client-side problem; retrying the identical request will fail identically. Fix the request, the key, the balance or the subscription first. - **409 and 429** — transient by design; retry after a delay (poll for a free slot on 409, exponential backoff on 429). - **503 `model_unavailable`** — transient on the provider side; no charge was made. Retry later. - **Failed generations are not errors at request time.** A job that is accepted (`201`) but later ends `failed` reports its reason in `error_message` on the generation object, and its credits are refunded automatically. --- # Admin metrics > Staff-only platform metrics: GET /api/admin/metrics/, its full response shape, and the 403 admin_required returned to non-staff accounts. Figgshield exposes one staff-only endpoint for platform metrics. It backs the internal admin dashboard (run locally, not part of the public app) and is not part of the normal customer API surface — ordinary accounts never reach it. Staff accounts are created **out-of-band**, through the Django admin or shell; there is no signup or upgrade path to staff. Every ordinary account carries `is_staff: false` in its [user object](https://figgshield.ai/documentation/authentication.md); staff accounts carry `is_staff: true`. ## Platform metrics `GET /api/admin/metrics/` — requires a staff account. Authenticate with a staff session cookie or an API key belonging to a staff account. ```bash curl https://api.figgshield.ai/api/admin/metrics/ \ -H "Authorization: Bearer $FIGGSHIELD_API_KEY" ``` A non-staff caller — even a perfectly valid, authenticated one — receives `403` with the machine code `admin_required`: ```json { "error": "admin_required", "detail": "This endpoint requires a staff account." } ``` The response aggregates users, subscriptions, revenue, provider costs and margins, plus 30-day daily and per-model breakdowns. All monetary amounts are integer cents. ```json { "generated_at": "2026-07-06T09:00:00Z", "users": { "total": 4120, "new_30d": 318, "onboarding": { "profile": 44, "plan": 61, "complete": 4015 } }, "subscriptions": { "active_total": 2870, "cancel_at_period_end": 63, "by_plan": [ { "slug": "starter", "name": "Starter", "count": 980, "yearly_cents": 14400 }, { "slug": "pro", "name": "Pro", "count": 1080, "yearly_cents": 34800 }, { "slug": "studio", "name": "Studio", "count": 170, "yearly_cents": 90000 } ] }, "revenue": { "run_rate_yearly_cents": 89078400, "effective_monthly_cents": 7423200, "topups_30d_cents": 512000 }, "costs": { "provider_30d_cents": 2140000, "per_active_user_monthly_cents": 745 }, "margins": { "monthly_revenue_cents": 7423200, "monthly_cost_cents": 2140000, "gross_margin_pct": 71.2 }, "daily": [ { "date": "2026-07-01", "signups": 11, "new_subscriptions": 7, "credits_used": 24310, "provider_cost_cents": 71200 } ], "by_model": [ { "model": "Kling", "generations": 1820, "credits": 63700, "provider_cost_cents": 637000 }, { "model": "Nano Banana 2", "generations": 5140, "credits": 41120, "provider_cost_cents": 174760 } ] } ``` ## Response fields | Group | Fields | | --- | --- | | `generated_at` | When these figures were computed. | | `users` | `total`, `new_30d`, and an `onboarding` funnel counting accounts at each step (`profile`, `plan`, `complete`). | | `subscriptions` | `active_total`, `cancel_at_period_end`, and `by_plan` — per-plan active counts with each plan's `yearly_cents` (12 × the monthly sticker). | | `revenue` | `run_rate_yearly_cents`, `effective_monthly_cents` (the run-rate ÷ 12), and `topups_30d_cents`. | | `costs` | `provider_30d_cents` and `per_active_user_monthly_cents`. | | `margins` | `monthly_revenue_cents`, `monthly_cost_cents`, and `gross_margin_pct` — `null` when monthly revenue is 0. | | `daily` | The last 30 days, one entry per day: `signups`, `new_subscriptions`, `credits_used`, `provider_cost_cents`. | | `by_model` | The last 30 days per model (Kling, Nano Banana 2): `generations`, `credits`, `provider_cost_cents`. | Provider cost is the best available estimate: the actual per-call cost where the provider reports it, otherwise a per-model admin-set estimate multiplied by the number of calls. The [`GET /api/models/`](https://figgshield.ai/documentation/models.md) public schema never exposes these internal cost figures.