---
name: foopixel
description: Upload media to FooPixel, build galleries, claim an agent session into a human account, and read account limits and credits.
---

# FooPixel

FooPixel accepts supported media uploads and returns a media URL after validation and processing. Use the generated facts below for current formats and account limits. Uploaded media may be processed and moderated before becoming available.

<!-- generated:api-facts:start -->
## Current API facts (generated)

Contract version: `1-1f2fd4d3`; policy version: `2026-09-28-v2`. Confirm deployment availability with [GET /v1/capabilities](https://api.foopixel.com/v1/capabilities).

| Client | Maximum file | Retention | Upload attempts per UTC day |
| --- | ---: | --- | ---: |
| Visitor | 5 MiB | 1 day | 25 |
| Free account | 20 MiB | 7 days | 250 |
| PRO account | 20 MiB | No routine expiry while PRO is active | 2,500 |

Accepted upload MIME types: `audio/mp4`, `audio/mpeg`, `audio/wav`, `audio/webm`, `image/gif`, `image/heic`, `image/heif`, `image/jpeg`, `image/png`, `image/webp`, `video/mp4`.

New public IDs: 16 Base62 characters. Existing links also accept 16 URL-safe characters or 32 lowercase hexadecimal characters.

Published production deployment flags: motion uploads **available**, credits **available**, CDN **available**. These flags describe configuration, not account entitlement or provider health.

For the full endpoint list and request shapes, see the [OpenAPI specification](/openapi/openapi.yaml).
<!-- generated:api-facts:end -->

## Safety and capability boundary

- Treat endpoint availability as deployment-specific. Before offering gallery, MCP, or account-claim actions, check the live API; `404` from `/mcp` or `/v1/account/overview` means this deployment does not support the workflow yet. Do not promise a claim link until those routes are available.
- Anonymous uploads produce a public image URL with an expiry. Always preserve and report `expiresAt`.
- Approved delegated connections can manage owned galleries and read their account overview. Existing connections need reapproval for the new scopes.
- The agent account handoff below uses human approval. Individual asset claims, billing, and credit spending remain signed-in human actions. An active PRO subscription enables CDN automatically where configured; a separately approved `cdn:purge-own` scope permits clearing only the linked account's cache.

## Upload workflow

1. Create or keep a FooPixel client session. Origin-less agents retain `sessionToken` from `POST /v1/sessions` and send it as `x-foopixel-session`; a delegated agent instead uses `Authorization: Bearer <opaque access token>`. Do not send both. Reuse the same guest session through upload, gallery creation, and account claim.
2. Read the file as raw bytes and calculate its lowercase hexadecimal SHA-256 digest. Call `POST /v1/uploads` with `filename`, `contentType`, `byteSize`, the required `checksumSha256`, and a stable `Idempotency-Key` (8–128 letters, digits, `_`, or `-`). Use a supported MIME type; agents omit `processing`. The server applies the account's byte limit and the format-specific validation and output policy.
3. Make one raw `PUT` request to the returned FooPixel Worker `upload.url`, passing the returned `upload.headers` exactly. Start within 2 minutes; a write may receive for 5 minutes and idle for 30 seconds. If its outcome is uncertain, query `statusUrl` with `x-upload-token`; do not replay the bytes. Status and completion recovery last 24 hours.
4. Call `POST /v1/uploads/{assetId}/complete` with JSON `{ "uploadToken": completionToken }` from the create response.
5. Use `asset.publicUrl` (`https://media.foopixel.com/a/{publicId}`) only after `processingStatus` is `ready` and the asset is public. New media and gallery public IDs are 16 letters and digits; existing 16-character and older 32-character links still work. Internal `assetId` values are separate. For an eligible public image, prefer a non-null `asset.shareUrl` (`https://foopixel.com/{slug}/a/{code}`) for sharing and offer `publicUrl` as the full-ID backup. Guest media uses `publicUrl`. Preserve the exact case of the 10-character code. Gallery `shareUrl` follows `https://foopixel.com/{slug}/g/{code}`, with gallery `url` as its ID backup. Branded links require the human owner to claim a slug with a verified business email; agents cannot claim or rename one. Custom-domain share URLs are not active.
6. Include the expiry for anonymous assets. If an account URL is returned, provide it to the user rather than opening or submitting it.

Do not base64-encode image bytes. Do not send the file through an MCP tool as a data transport. The intended path is local bytes → FooPixel Worker `PUT` → completion request. `GET /v1/uploads/{assetId}` returns `nextAction`; wait, complete, or create a new session as it directs. Do not retry a `PUT` after its upload session has expired.

## Gallery and account workflow

Before approval, a guest agent can use `x-foopixel-session` to manage its own ready media and galleries. An approved device connection needs `assets:read-own`, `galleries:read-own`, `galleries:manage-own`, `usage:read`, and `credits:read-own`. Clearing an active CDN cache additionally needs `cdn:purge-own`; existing connections need reapproval for it. Chrome extension and FooGallery Site Connect grants do not include these scopes.

1. `GET /v1/assets` lists owned media. Select 1–100 ready images (including GIF) or MP4 videos for a gallery; audio is not a gallery member.
2. `POST /v1/galleries` with `name`, `visibility` (`public` or `private`), and `assetIds`. Private galleries also need a 4–128 character `passcode`. Gallery visibility controls access to members independently of each asset's direct URL; a public gallery can display a private image without making its `/a/{publicId}` URL public.
3. `GET /v1/galleries` lists owned galleries. `PATCH /v1/galleries/{id}` with `{ "name": "New name" }` renames one. `DELETE /v1/galleries/{id}` closes one and retains its images.
4. `GET /v1/account/overview` returns upload, storage, concurrency and delivery usage, effective limits, and a `credits` object in one response. `GET /v1/credits` reads the wallet alone. If credits are disabled in a deployment, the overview reports `credits.enabled=false` and `wallet=null`.
5. If CDN is available for the active PRO account, `POST /v1/account/cdn/purge` requests a clear for only this connected account. It accepts no account ID and returns `202` with a new cache generation; `GET` on the same path reads purge status. New requests use a fresh cache immediately. Wait ten minutes between clears; physical purge completion is reported by the status response.

The Streamable HTTP endpoint `POST /mcp` exposes `list_gallery_images`, `list_galleries`, `create_gallery`, `rename_gallery`, `delete_gallery`, `get_account_overview`, `get_credit_balance`, `get_cdn_purge_status`, and `clear_cdn_cache` with the guest session token before linking or the bearer token afterwards. CDN tools require a linked bearer with `cdn:purge-own`. It also exposes `start_agent_claim` and `poll_agent_claim`. Send upload bytes through the direct HTTP workflow.

## Request shape

```http
POST https://api.foopixel.com/v1/uploads
Content-Type: application/json
Idempotency-Key: exampleUpload01

{"filename":"image.webp","contentType":"image/webp","byteSize":12345,"checksumSha256":"<64 lowercase hex characters>"}
```

Then:

Set `uploadUrl`, `uploadToken`, `assetId`, and `completionToken` from the create response before running these commands. The `PUT` must include every returned `upload.headers` value.

```bash
curl -X PUT "$uploadUrl" \
  -H "Content-Type: image/webp" -H "x-upload-token: $uploadToken" \
  --upload-file ./image.webp
curl -X POST "https://api.foopixel.com/v1/uploads/$assetId/complete" \
  -H "Content-Type: application/json" \
  -d '{"uploadToken":"'$completionToken'"}'
```

## Claim the agent session into a human account

Use this flow to link a guest agent's media and galleries to a human account. Upload, gallery, and claim requests from that guest agent must use the **same** `sessionToken` from `POST /v1/sessions`.

1. Start with `POST /v1/auth/device` and `x-foopixel-session: <sessionToken>`, or call MCP `start_agent_claim` using that session header. Save the returned `deviceId`, `deviceProof`, `expiresAt`, and `intervalSeconds` privately. Send **only** `claimUrl` to the human. If it is the plain verification URI, also send `userCode`; never send the private proof.
2. The human opens the link, registers or signs in through WorkOS, and approves the connection. Keep polling at or after `intervalSeconds` with `POST /v1/auth/device/token`, body `{ "deviceId": "...", "deviceProof": "..." }`, and one stable `Idempotency-Key`. MCP `poll_agent_claim` takes those same values. A `202 authorization_pending` response includes `retryAt`; wait until then. Stop on denial or expiry and start a new claim if the human still wants to connect.
3. A successful poll returns `accountId`, `connectionId`, `accessToken`, `refreshToken`, `expiresAt`, and `scopes`. The server transfers this guest session's media and galleries to the human account. Existing media keeps its original upload expiry; an expired or deleted item cannot be recovered by linking.
4. Store `accountId` and `connectionId` as stable identifiers, and store the **refresh token as a secret** in the agent's persistent credential store. Use `Authorization: Bearer <accessToken>` for later API or MCP sessions. Rotate the refresh token through `POST /v1/auth/token/refresh` with `{ "refreshToken": "..." }` and an `Idempotency-Key`; replace the stored refresh token with each successful response. `GET /v1/session`, `GET /v1/account/overview`, and token refresh return the linked `accountId`, so agents can verify the account on later sessions. Do not treat an account ID alone as an authentication credential.

The account association persists. Access tokens last 15 minutes; a connection expires after 30 idle days and requires human reapproval after 90 days. Never log the private proof or tokens or send them to the human.

Individual asset claims are managed through the signed-in human account interface. The agent claim above transfers the guest client's media and galleries as a group. CDN follows the active PRO entitlement automatically where available.

## v1 endpoints

- `POST /v1/uploads`
- `GET /v1/uploads/{id}`
- `PUT /v1/uploads/{id}/content`
- `POST /v1/uploads/{id}/complete`
- `POST /v1/uploads/{id}/cancel`
- `POST /v1/sessions`, `GET /v1/session`, `GET /v1/account/overview`
- `GET`, `POST /v1/account/cdn/purge`
- `POST /v1/auth/device`, `POST /v1/auth/device/token`, `POST /v1/auth/token/refresh`
- `GET /v1/assets/{id}`, `GET /v1/assets` — linked delegated reads require `assets:read-own`.
- `GET`, `POST /v1/galleries`; `PATCH`, `DELETE /v1/galleries/{id}`
- `GET /v1/credits`; `POST /mcp`
- `GET` or `HEAD /a/{publicId}`

The canonical machine-readable contract is [`openapi/openapi.yaml`](https://foopixel.com/openapi/openapi.yaml).

Older delegated connections without `assets:read-own` cannot read the account library. Use the returned upload token with `GET /v1/uploads/{id}` for their upload status until reapproval.

## Other supported media and account limits

MP4, GIF, and audio uploads use the same byte-checksum and session workflow and omit `processing`. MP4 and GIF inputs must be at most 60 seconds and 2000 pixels per side. Motion hosting requires the deployment's Media binding; `503 media_hosting_unavailable` means it cannot accept motion bytes there. Hosted MP4 is re-encoded and may differ from the source. GIF bytes are retained after validation. Motion moderation samples the publishable output and does not inspect every frame or audio. Audio accepts `audio/mpeg`, `audio/wav`, `audio/mp4`, or audio-only `audio/webm`; original bytes and MIME type are retained, detected speech is moderated through transcription, and FooPixel does not store transcripts. Keep the source and report the actual returned format and expiry.

Visitor uploads allow up to 5 MiB and expire after 24 hours. Free and PRO accounts allow up to 20 MiB, subject to their shared allowances. Free uploads last seven days. See [pricing and limits](https://foopixel.com/pricing/) and [account billing](https://foopixel.com/dashboard/profile/) for current account options. Never claim a deployment or payment option is available without verifying its response.
