Paperstall

built to integrate

Paperstall API

Versioned JSON API under /api/v1. The full OpenAPI 3.1 spec, generated from the same zod schemas the server validates with, is at /api/v1/openapi.json. Every response includes receipts: the PayPal, Gemini and Channel3 calls it made, with PayPal debug IDs.

AI

  • POST/api/v1/ai/read

    Read a photo of paper

    Image → structured Read (intent, items with 0–1000 boxes, currency, questions, warnings) plus an acceptable-use check. Rate-limited per IP.

  • POST/api/v1/market

    Market check for branded items (Channel3)

  • POST/api/v1/ai/concierge

    Buyer concierge: request → cart proposal from this stall's items only

  • POST/api/v1/ai/penny

    Penny, the seller's clerk

    Gemini function calling over PayPal tools. Mutating tools return proposals only; they execute through the routes above after the seller approves.

Stalls

  • POST/api/v1/stalls/sign

    Sign a stall so it can take payments

    The server assigns the stall ID and returns an owner token once; refunds and shipping need it.

  • POST/api/v1/stalls/check

    Check a stall link's signature and expiry

Checkout

  • POST/api/v1/orders

    Create a PayPal order from a signed stall and a cart

    Prices are recomputed on the server from the signed stall; client totals are ignored. The stall's payee receives the money.

  • POST/api/v1/orders/capture

    Capture an approved order and get the signed receipt code

Verify

  • POST/api/v1/verify

    Verify a payment with PayPal before recording it

    Checks order + capture status, payee, amount, currency, stall and replay. Send a scanned receipt `code` or a typed `orderId`.

Invoicing

  • POST/api/v1/invoices

    Create, send and QR a PayPal invoice

Subscriptions

  • POST/api/v1/plans

    Create a Catalog Product + active Billing Plan

  • POST/api/v1/subscriptions

    Create a subscription for approval, or read its status

Errors and limits

Errors are { error: { code, message, debugId? } }. AI and payment routes are rate-limited per IP (best-effort on serverless) and accept same-origin browser requests only. Money is always integer minor units; the server recomputes every amount from a signed stall.