# peelaway

Run production image edits by describing the change in plain language. Peelaway picks the right workflow (object removal, background removal, or generative editing) and returns the finished image with explicit job metadata.

## When to use

Use Peelaway when the user owns the image or is authorized to make the requested
change, and the task involves modifying an existing image:

- Removing unwanted objects, temporary signs, text, or people
- Removing or replacing the background
- Editing an image based on a natural-language instruction

Do **not** use Peelaway to generate images from scratch; it requires an input image.
Do not remove watermarks, copyright notices, credentials, or provenance signals
unless the user is authorized to alter them.

## Getting started

You need a verified Peelaway account and an API key:

1. Sign up at https://peelaway.io. New accounts get 10 free image credits, no card required.
2. Verify the account's email. This one-time account-owner step cannot run unattended.
3. In the dashboard, create an API key (`pk_...`) and send it as `Authorization: Bearer <key>` on every request.
4. Each edit spends 1 credit; failed jobs are refunded. When the free credits run low, eligible first-time subscribers can receive a 7-day Core trial, and one-time credit packs are also available.

If the user has not signed up, point them to https://peelaway.io to create an account and get a key.

### Provision an API key over HTTP after verification

An account owner can provision a key without the dashboard after the account's email has been **verified** (a one-time interactive step; paying for credits also verifies it):

```
# 1. Create an account. This emails a verification link and returns a session.
curl -sX POST https://api.peelaway.io/auth/sign-up/email \
  -H 'Content-Type: application/json' -c cookies.txt \
  -d '{"email":"agent@example.com","password":"a-strong-password","name":"My Agent"}'

# 2. In a browser, log in to this account and open the verification link.
#    This one-time account-owner step cannot be completed unattended.

# 3. After verification, sign in over HTTP and save the new session cookie.
curl -sX POST https://api.peelaway.io/auth/sign-in/email \
  -H 'Content-Type: application/json' -c cookies.txt \
  -d '{"email":"agent@example.com","password":"a-strong-password"}'

# 4. Mint an API key, sending the verified session cookie back.
curl -sX POST https://api.peelaway.io/api/keys \
  -H 'Content-Type: application/json' -b cookies.txt \
  -d '{"name":"my-agent"}'
# -> { "key": "pk_...", "id": "...", "prefix": "pk_...", "name": "my-agent" }
```

Sign-up and sign-in work before verification, but `POST /api/keys` and edits return `403 code:"email_unverified"` until the email is verified. The `key` (`pk_...`) is returned **once** — store it and send it as `Authorization: Bearer pk_...`. New accounts start with 10 free credits. List keys with `GET https://api.peelaway.io/api/keys`; revoke with `DELETE https://api.peelaway.io/api/keys/{id}`.

**Note:** creating a key and running an edit both require a verified email (click the link sent at sign-up — you must be signed in to that account to complete it); `POST /api/keys`, `POST /api/process`, and MCP `edit_image` return `403` `code: "email_unverified"` until then. Sign-up and sign-in don't require it.

## How to use

The REST API has one submit endpoint plus optional status and result endpoints. The preferred workflow is submit with a webhook; polling and fetching remain available when a callback is not practical.

### 1. Submit a job

`POST https://api.peelaway.io/api/process` with a JSON body:

```json
{
  "image": "<base64-encoded image bytes>",
  "prompt": "remove the temporary sign in the bottom right",
  "format": "jpeg",
  "webhook_url": "https://your.app/hooks/peelaway"
}
```

`webhook_url` is optional. If set, it must be a public `https:` URL; Peelaway POSTs a signed callback there when the job settles (see Webhooks below). For a batch, pass `{ "images": [ { "image": ..., "prompt": ..., "webhook_url"?: ... }, ... ] }` (up to 50) — each item may carry its own `webhook_url`.

Headers:

- `Authorization: Bearer <api_key>` (required)
- `Content-Type: application/json`
- `Idempotency-Key: <uuid>` (optional but recommended — lets you retry the same request without double-charging)

Response:

```json
{ "job_id": "8f4a17000e17...", "credits_remaining": 24 }
```

### 2. Poll for status

`GET https://api.peelaway.io/api/process/status?job_id=<job_id>`

Response: `{ "status": "pending" | "done" | "error" }`. Poll every 2-5 seconds until status is no longer `pending`. Once terminal, the response also carries the metadata block (`width`, `height`, `format`, `credits_used`, `credits_remaining`, `processing_time_ms`).

### 3. Fetch the result

`GET https://api.peelaway.io/api/process/result?job_id=<job_id>`

Response:

```json
{
  "job_id": "...",
  "url": "https://.../signed-url-to-image",
  "format": "jpeg",
  "width": 4000,
  "height": 3000,
  "credits_used": 1,
  "credits_remaining": 24,
  "processing_time_ms": 8420
}
```

The `url` is a signed URL valid for 1 hour. Download the image bytes with a normal HTTP GET.

## Webhooks

Instead of polling, pass a `webhook_url` on submit and let Peelaway call you back. When the job settles (`done` or `error`), Peelaway sends one `POST` to that URL with a JSON body:

```json
{
  "job_id": "...",
  "status": "done",
  "width": 4000,
  "height": 3000,
  "format": "jpeg",
  "credits_used": 1,
  "credits_remaining": 24,
  "processing_time_ms": 8420,
  "result_url": "https://.../signed-url-to-image"
}
```

On `status: "error"` there is no `result_url`; instead a generic `"error": "Processing failed"` field is present (credits are auto-refunded). Delivery uses retry backoff (30s, 2m, 10m, 1h), so receivers must dedupe on `job_id`.

**Verifying the signature.** Every callback carries two headers:

- `X-Peelaway-Timestamp: <unix-ms>`
- `X-Peelaway-Signature: sha256=<hex>`

The signature is `HMAC-SHA256(secret, `${timestamp}.${rawRequestBody}`)`. Fetch your signing secret once from `GET https://api.peelaway.io/api/webhooks/secret` (authed; returns `{ "secret": "<hex>" }`), recompute the HMAC over `${timestamp}.${body}`, and compare. Reject stale timestamps to guard against replay.

## MCP

Peelaway is also an MCP server for tool-using agents, at `POST https://api.peelaway.io/mcp` (Streamable-HTTP JSON-RPC 2.0), authed by the same `Authorization: Bearer pk_...` key. It implements `initialize`, `tools/list`, and `tools/call`, exposing three tools:

- `edit_image` — args `{ image, prompt, negative_prompt?, format?, quality?, mask?, detect?, webhook_url? }`; returns a `job_id` (debits 1 credit, refunded on failure). `mask` (base64 PNG) skips auto-detection; `detect` overrides the removal vocabulary.
- `get_job_status` — args `{ job_id }`; returns the status (+ metadata block once terminal).
- `get_job_result` — args `{ job_id }`; returns the signed result URL (+ metadata block).

The manifest is at `GET https://api.peelaway.io/mcp.json`.

For a human connecting a configurable client, the API-key setup guide is at https://peelaway.io/connectors.

## Prompting guide

Peelaway routes prompts to workflows by parsing the verb in the prompt:

| Workflow | Trigger phrases | Example |
|---|---|---|
| Background removal | "remove the background", "transparent background" | "remove the background" |
| Object removal | "remove X", "erase X", "delete X", "clean up X" | "remove the power lines" |
| Generative editing | anything else | "change the sky to sunset" |

Use the right verb for the workflow you want. "Remove the person on the left" → object removal. "Replace the person with a tree" → generative editing.

## Errors

- `400` — invalid request (bad prompt, malformed image, etc.). Don't retry. A `code` of `batch_exceeds_plan_limit` means the batch is larger than your plan's concurrency limit — submit fewer images per call or upgrade.
- `402` — insufficient credits. The user needs to top up before retrying.
- `429` — throttled. `code: "rate_limited"` (too many submissions this minute; honor the `Retry-After` header) or `code: "too_many_in_flight"` (too many jobs still processing; let some finish, then retry). Both scale with plan — see Rate limits.
- `502` — upstream provider failure. Safe to retry with the same `Idempotency-Key`.

## Rate limits

Editing throughput scales with the account's plan. Credits are the hard monthly cap; these govern how fast you can submit and how many jobs can run at once (an image in a batch counts once toward each):

| Plan | Submissions / min | Concurrent jobs (also the max batch size) |
| --- | --- | --- |
| Free | 5 | 3 |
| Starter | 15 | 10 |
| Core | 40 | 25 |
| Pro | 120 | 50 |

Signup and MCP client registration are additionally rate-limited per IP (a `429` with `Retry-After`).

## Discovery

- `GET https://api.peelaway.io/llms.txt` — overview of the service
- `GET https://api.peelaway.io/openapi.json` — full machine-readable API spec
