# info.description
Purchase-flow API for LLM agents: create a customer account, upload photos, compose a photo gallery with server-side auto-layout, render a visual preview, place an order and receive a Stripe payment link for the customer. The agent never handles card data.

Typical flow: POST /accounts → POST /photos (multipart or source_url) → GET /products → POST /compositions → POST /compositions/{id}/preview (show the image to the customer) → POST /orders → PUT /orders/{id}/shipping-address → POST /orders/{id}/checkout → send payment_url to the customer → poll GET /orders/{id} until status == 'paid'.

# paths./api/agent/v1/accounts.post.description
Create a customer account and receive an agent token.

Returns 409 with code EMAIL_EXISTS when the e-mail is already registered;
a 6-digit login code is then e-mailed to the customer — exchange it via
POST /accounts/verify.

# paths./api/agent/v1/accounts.post.parameters[].description
Optional unique key making this POST safe to retry: the same key with the same body replays the original response for 24h instead of repeating the side effect. Recommended for /orders and /checkout.

# paths./api/agent/v1/accounts/verify.post.description
Exchange the e-mailed 6-digit code for an agent token (existing account).

# paths./api/agent/v1/accounts/verify.post.parameters[].description
Optional unique key making this POST safe to retry: the same key with the same body replays the original response for 24h instead of repeating the side effect. Recommended for /orders and /checkout.

# paths./api/agent/v1/compositions.post.description
Create a composition from a product variant.

The server clones the variant's layout and automatically assigns the
customer's photos to frames (optimal match by resolution and aspect
ratio), computing center crops. Check `frames[].quality_warnings` and
`missing_photos_count` in the response, then request a visual preview
via POST /compositions/{id}/preview before ordering.

The response `edit_url` deep-links the customer into the framky.com
configurator to fine-tune the gallery; it carries a login token, so share
it only with the account's own customer.

# paths./api/agent/v1/compositions.post.parameters[].description
Optional unique key making this POST safe to retry: the same key with the same body replays the original response for 24h instead of repeating the side effect. Recommended for /orders and /checkout.

# paths./api/agent/v1/compositions/{composition_id}.get.description
Composition status (GET) and photo swaps (PATCH).

PATCH body: {"swaps": [{"frame_id": "...", "photo_id": "..."}]} — replaces
the photo in a frame and recomputes the crop. Compositions attached to an
order already in payment/production return 409 ORDER_LOCKED.

# paths./api/agent/v1/compositions/{composition_id}.patch.description
Composition status (GET) and photo swaps (PATCH).

PATCH body: {"swaps": [{"frame_id": "...", "photo_id": "..."}]} — replaces
the photo in a frame and recomputes the crop. Compositions attached to an
order already in payment/production return 409 ORDER_LOCKED.

# paths./api/agent/v1/compositions/{composition_id}/preview.get.description
Visual preview of a composition (rendered JPEG with frames, photos,
crops and shadows).

POST queues rendering (or returns the finished image immediately);
GET polls the state: `ready` (preview_url set), `pending` (retry after a
few seconds), `stale` (composition changed — POST again), `error`.
Always show the preview to the customer before placing an order.

# paths./api/agent/v1/compositions/{composition_id}/preview.post.description
Visual preview of a composition (rendered JPEG with frames, photos,
crops and shadows).

POST queues rendering (or returns the finished image immediately);
GET polls the state: `ready` (preview_url set), `pending` (retry after a
few seconds), `stale` (composition changed — POST again), `error`.
Always show the preview to the customer before placing an order.

# paths./api/agent/v1/compositions/{composition_id}/preview.post.parameters[].description
Optional unique key making this POST safe to retry: the same key with the same body replays the original response for 24h instead of repeating the side effect. Recommended for /orders and /checkout.

# paths./api/agent/v1/me.get.description
Sanity-check the token and return the account it belongs to.

# paths./api/agent/v1/orders.post.description
Create an order from a composition.

Agent orders are always fresh (never merged into the customer's web
shopping cart). Flow: POST /orders → PUT /orders/{id}/shipping-address →
POST /orders/{id}/checkout → give payment_url to the customer.

# paths./api/agent/v1/orders.post.parameters[].description
Optional unique key making this POST safe to retry: the same key with the same body replays the original response for 24h instead of repeating the side effect. Recommended for /orders and /checkout.

# paths./api/agent/v1/orders/{order_id}.get.description
Order status. Poll after checkout until `status` == "paid".

# paths./api/agent/v1/orders/{order_id}/checkout.post.description
Create the Stripe payment link for the order.

Returns payment_url — send it to the customer; the agent never handles
card details. The link expires after 24 h; calling checkout again returns
the same open session (or a fresh one if the price changed).

# paths./api/agent/v1/orders/{order_id}/checkout.post.parameters[].description
Optional unique key making this POST safe to retry: the same key with the same body replays the original response for 24h instead of repeating the side effect. Recommended for /orders and /checkout.

# paths./api/agent/v1/orders/{order_id}/items.post.description
Add another composition to an existing (unpaid) order.

# paths./api/agent/v1/orders/{order_id}/items.post.parameters[].description
Optional unique key making this POST safe to retry: the same key with the same body replays the original response for 24h instead of repeating the side effect. Recommended for /orders and /checkout.

# paths./api/agent/v1/orders/{order_id}/shipping-address.put.description
Set the delivery address (and optional company billing details with EU
VAT number, validated against VIES). Moves the order to awaiting_payment
and recalculates the price including shipping.

# paths./api/agent/v1/photos.get.description
Upload a customer photo (multipart `file` or JSON `{source_url}`)
and list uploaded photos.

Photos are deduplicated by filename: re-uploading the same filename
overwrites the previous file. Thumbnails, face detection and quality
analysis run asynchronously — poll GET /photos/{id} until
`faces_detected` is not null for the full quality report.

# paths./api/agent/v1/photos.post.description
Upload a customer photo (multipart `file` or JSON `{source_url}`)
and list uploaded photos.

Photos are deduplicated by filename: re-uploading the same filename
overwrites the previous file. Thumbnails, face detection and quality
analysis run asynchronously — poll GET /photos/{id} until
`faces_detected` is not null for the full quality report.

# paths./api/agent/v1/photos.post.parameters[].description
Optional unique key making this POST safe to retry: the same key with the same body replays the original response for 24h instead of repeating the side effect. Recommended for /orders and /checkout.

# paths./api/agent/v1/photos/{photo_id}.get.description
Status of a single photo (thumbnails, face detection, quality warnings).

# paths./api/agent/v1/products.get.description
Catalog of orderable gallery variants (flattened, one entry per variant).

Prices are in the account's currency and may be cached for up to 3 hours;
the checkout always recomputes the authoritative price server-side.
Filter with ?frame_count= and ?max_wall_width_cm= to narrow the list.

# paths./api/agent/v1/products/{variant_id}.get.description
Variant detail with photo slots (aspect ratio and minimum photo
resolution per frame) — use it to pick which photos fit which product.

# components.securitySchemes.AgentToken.description
Agent token from POST /accounts or POST /accounts/verify. Send as: Authorization: Bearer agk_…