Wwire
API Reference

Reference

Every route Wire exposes.

Flow (prompt-to-payment pages), Relay (any API → MCP tools), and the account/payout endpoints underneath both. Generated directly from the route handlers in app/api/ — every request/response shape below reflects what the code actually does, not an aspirational spec.

https://usewiree.vercel.app/

Session auth

An httpOnly cookie (wire_session) set by /api/auth/login or /api/auth/signup. Required for anything scoped to an account.

Public

No auth — either genuinely public reference data, or intentionally open (Flow creation itself needs no account).

Signed webhook

Verified via an HMAC signature header from the sender (Paystack, Twilio) — not something you call directly.

Cron secret

Guarded by an Authorization: Bearer $CRON_SECRET header Vercel sends automatically on schedule.

Flow

The prompt-to-payment-page pipeline. Call it with no auth at all for an anonymous, unowned page, or with your developer API key (see Auth below) to create pages under your own account — e.g. from your own backend, not through Wire's UI.

POST/api/flowPublic or dev key

Turns one plain-English request into a live Flow page — single price, multiple named tiers, or a recurring subscription, decided automatically from the wording. Pass "Authorization: Bearer <your dev key>" to create it under your own account instead of anonymously; omit it and the page is unowned until someone logged-in claims it by viewing its dashboard.

Body

FieldTypeDescription
promptstringrequiredWhat's being sold, in plain English — price (or per-tier prices, or a recurring frequency) included.
sellerIdstringoptionalThe wire_seller_id browser cookie value, so the page can be claimed later by whoever logs in from this browser. Not needed when authenticating with a dev key — ownership is already resolved from that.

Response

{
  "slug": "a1b2c3d4",
  "checkoutUrl": "/checkout/a1b2c3d4",
  "dashboardUrl": "/dashboard/a1b2c3d4",
  "record": { "apiKey": "flow_...", "...": "see FlowRecord" }
}

Status

200 Created401 A dev key was provided but doesn't match any account422 Missing required info — response is { error: "<clarifying question>" }502 Agent or Paystack call failed
GET/api/flow/mineSession

Every Flow page the logged-in user owns. Also sweeps in and claims any unowned page created from this same browser first.

Response

{
  "email": "you@example.com",
  "flows": [ /* FlowRecord[] */ ]
}

Status

200 OK401 Not logged in
GET/api/flow/{slug}Session + ownership, or that Flow's own key

Polled every 3s by the dashboard. With a browser session, claims an unowned page for the current viewer on first load and 403s if it's already owned by someone else. With "Authorization: Bearer <the Flow's own apiKey>" (returned when it was created, not your developer key) it skips ownership entirely — this is the status-check path for a third-party app.

Response

// FlowRecord, plus subscriberCount if the Flow is recurring
{ "...": "see FlowRecord", "subscriberCount": 4 }

Status

200 OK401 Not logged in, and no valid Flow key given403 Owned by a different account404 No Flow for that slug
POST/api/flow/{slug}/purchasePublic

Tiered Flows only. Creates a one-off invoice for the chosen tier's price — there's no single fixed checkout link when a page has tiers.

Body

FieldTypeDescription
tierIdstringrequiredOne of the tier ids from the Flow's tiers array.

Response

{ "checkoutUrl": "https://checkout.paystack.com/..." }

Status

200 OK400 Not a tiered Flow, or missing tierId404 Flow or tier not found409 That tier is sold out502 Paystack call failed
GET/api/flow/{slug}/qrPublic

A standalone PNG QR code pointing at the Flow's checkout page — used to hand WhatsApp a public image URL, but works for anything that needs the raw image.

Response

// image/png bytes, not JSON

Status

200 OK — image/png404 No Flow for that slug

Payouts

Lets a seller route their share of every sale straight to their own bank account via a Paystack subaccount, instead of it pooling in the platform wallet.

GET/api/banksPublic

The full bank list for the payout-setup dropdown.

Response

{ "banks": [ { "name": "GTBank", "code": "058" }, ... ] }

Status

200 OK502 Paystack call failed
GET/api/payoutSession

The logged-in user's payout account, if they've set one up.

Response

{ "account": /* PayoutAccount */ null }

Status

200 OK401 Not logged in
POST/api/payoutSession

Creates a Paystack subaccount for this user (once) and saves it. Defaults to a 100% split — the seller keeps everything unless a platform fee is set explicitly.

Body

FieldTypeDescription
bankCodestringrequiredFrom the /api/banks list.
accountNumberstringrequiredThe seller's own bank account number.
bankNamestringoptionalDisplay label only — passed through from the client's bank list lookup.
splitPercentagenumberoptionalDefaults to 100.

Response

{ "account": /* PayoutAccount */ }

Status

200 OK400 Missing bankCode or accountNumber401 Not logged in502 Paystack rejected the account details

Relay & MCP

Turns a pasted curl command or OpenAPI spec into real MCP tools, plus the fixed Paystack-preset gateway every Flow page is built on.

POST/api/gatewayPublic

Parses a curl command or OpenAPI JSON spec into a gateway and registers it, ready to be pointed at by /api/gateway/{id}/mcp.

Body

FieldTypeDescription
inputstringrequiredA curl command, or an OpenAPI spec as JSON text.
authValuestringoptionalBearer token / API key / basic-auth credentials for the target API.
persistbooleanoptionaltrue keeps the gateway indefinitely (e.g. for /connect); otherwise it expires after 30 days.

Response

{
  "id": "gw_x1y2",
  "sourceLabel": "curl: api.example.com",
  "baseUrl": "https://api.example.com",
  "auth": { "type": "bearer" },
  "operations": [ /* GatewayOperation[] */ ]
}

Status

200 OK400 Missing input, or it couldn't be parsed
GET / POST / DELETE/api/gateway/{id}/mcpPublic

The live MCP server for a generated gateway — point any MCP-capable client at this URL. Stateless: re-compiled from the stored spec on every request.

Response

// Streamable HTTP MCP transport, not a plain JSON body

Status

200 OK404 No gateway for that id (may have expired)
GET/api/gateway/{id}/mcp.jsonPublic

A downloadable MCP client config file (mcpServers block) pointing at the gateway above.

Response

{ "mcpServers": { "wire-gateway-gw_x1y2": { "url": "...", "description": "..." } } }

Status

200 OK404 No gateway for that id
GET / POST / DELETE/api/mcpPublic

The fixed Paystack-preset MCP server — six tools (invoice, reserved account, sub-account split, refund, wallet balance, transaction search).

Response

// Streamable HTTP MCP transport

Status

200 OK
GET/api/mcp.jsonPublic

Downloadable MCP client config for the Paystack preset above.

Response

{ "mcpServers": { "wire-paystack": { "url": "...", "description": "..." } } }

Status

200 OK
POST/api/chatPublic

The Playground's live test chat — streams Server-Sent Events as the agent reasons, calls tools, and gets results back, against either the Paystack preset or a generated gateway.

Body

FieldTypeDescription
messagestringrequiredWhat to ask the agent to do.
gatewayIdstringoptionalUse a generated gateway's tools instead of the Paystack preset.

Response

// text/event-stream — events: reasoning, tool_call, tool_result, error, done
event: tool_call
data: {"tool":"get_wallet_balance","input":{}}

event: tool_result
data: {"tool":"get_wallet_balance","output":{...},"isError":false}

Status

200 OK — SSE stream400 Missing message404 gatewayId given but not found

Auth

The whole account system — email + password, hashed with scrypt, sessions stored in Redis behind a random-token cookie.

POST/api/auth/signupPublic

Creates an account and starts a session.

Body

FieldTypeDescription
emailstringrequiredMust contain “@”.
passwordstringrequiredAt least 8 characters.

Response

{ "email": "you@example.com" }

Status

200 OK400 Invalid email or short password409 Email already registered
POST/api/auth/loginPublic

Verifies credentials and starts a session.

Body

FieldTypeDescription
emailstringrequired
passwordstringrequired

Response

{ "email": "you@example.com" }

Status

200 OK400 Missing fields401 Invalid email or password
POST/api/auth/logoutSession

Ends the current session and clears the cookie.

Response

{ "loggedOut": true }

Status

200 OK
GET/api/auth/meSession

Who's currently logged in.

Response

{ "email": "you@example.com" }

Status

200 OK401 Not logged in
GET/api/auth/api-keySession

Your developer API key — creates one on first request, returns the same one on every call after that. This is what you put in your own backend's config; pass it as "Authorization: Bearer <key>" on POST /api/flow to create Flow pages under your account without a browser session. Distinct from a single Flow's own apiKey (returned when that Flow is created), which only ever authenticates GET requests for that one Flow's status.

Response

{ "apiKey": "dev_..." }

Status

200 OK401 Not logged in

Connect

Ties a seller's browser identity to a system they've connected (Airtable, Notion, etc.), so a confirmed sale can trigger an action there.

POST/api/sellerPublic

Saves the link between a sellerId (browser cookie) and a gateway they've connected.

Body

FieldTypeDescription
sellerIdstringrequired
gatewayIdstringrequired
sourceLabelstringoptionalDefaults to “Connected system.”

Response

// SellerRecord
{ "sellerId": "...", "gatewayId": "...", "sourceLabel": "...", "connectedAt": "..." }

Status

200 OK400 Missing sellerId or gatewayId
GET/api/seller?sellerId={id}Public

Looks up what a given sellerId has connected, if anything.

Response

// SellerRecord

Status

200 OK400 Missing sellerId404 Not connected

Internal & inbound webhooks

Not meant to be called directly — documented for completeness. Each is only reachable by the specific external sender its signature/secret is checked against.

POST/api/webhook/paystackinbound onlySigned (Paystack)

Paystack's charge.success notifications. Verifies x-paystack-signature (HMAC-SHA512 over the raw body, keyed with the secret key), records the sale, captures a reusable authorization for recurring billing, and fans out to any connected system.

Response

{ "received": true }

Status

200 Always — Paystack retries on non-2xx401 Invalid signature
POST/api/webhook/whatsappinbound onlySigned (Twilio)

Inbound WhatsApp messages via Twilio. Verifies X-Twilio-Signature, then runs the same Flow-creation agent a browser request would, replying over WhatsApp.

Response

// 200 with an empty body in every case Twilio should not retry

Status

200 Acknowledged401 Invalid signature
GET/api/cron/charge-subscriptionsinbound onlyCron secret

Fired daily by Vercel Cron (see vercel.json). Charges every recurring subscription whose next cycle is due, via Paystack's charge-authorization API.

Response

{ "charged": 3, "results": [ { "id": "...", "ok": true }, ... ] }

Status

200 OK — includes per-subscription failures, doesn't fail the whole request401 Missing/wrong CRON_SECRET

Data types

The shapes referenced above, as they’re actually stored — every optional field is genuinely optional depending on which kind of Flow it is.

FlowRecord

slug, title, priceNaira, ticketCap, ticketsSold, revenueNaira,
accountReference, accountNumber?, bankName?, checkoutUrl?,
createdAt, tiers?: FlowTier[], recurring?: { frequency },
userId?, sellerId?, lastConnectedAction?

accountNumber/bankName/checkoutUrl are only set for single-price Flows — tiered and recurring pages don't have one fixed payment target.

FlowTier

id, name, priceNaira, cap, sold

One entry per named tier on a multi-tier Flow.

PayoutAccount

subAccountCode, bankCode, bankName, accountNumber,
accountName?, splitPercentage, createdAt

One per user — created via POST /api/payout, referenced (not recreated) on every future sale.

SellerRecord

sellerId, gatewayId, sourceLabel, connectedAt

Links a browser/WhatsApp identity to a connected external system.

GatewayOperation

name, description, method, path, params: GatewayParam[]

One entry per endpoint a pasted API exposed. GatewayParam: name, location (path/query/header/body), type, required, description.