PFlux DOCS
GitHub Integration enquiries Start integrating
REFERENCE/API REFERENCE

API reference

Eleven integration endpoints, all POST with a JSON body, plus a GET liveness probe. Nothing is authenticated in v1: the capability in the body is what authorizes the call.

BASE URLyour deployment
TRANSPORTHTTPS · JSON
METHODPOST
AUTHNone in v1

Authentication

There is no API authentication in v1. Payments are secured by the customer’s signature and by the contract, not by knowing who is calling. There are no API keys, no bearer tokens and no accounts.

What protects each call instead is the capability it carries. Payment intents, setup tokens, subscription capabilities and cancel tokens are HMAC-signed by the deployment and verified on every request; a token minted for another deployment fails here even if a key were shared. The rate limits below protect the service itself.

TREAT CAPABILITIES AS SECRETS

A p2s2 subscription capability authorizes charges against a customer’s wallet. Keep it server-side. Use /v1/subscriptions/revoke/session when something has to reach a browser.

Capabilities never appear in a path or query string, which is what a server, a proxy and an access log actually record. The hosted checkout does carry one in the URL fragment — browsers do not send a fragment in the request or in the Referer header, so it stays on the client. That protects it from your infrastructure, not from everything running in the page.

Conventions

  • The eleven integration endpoints are all POST with a JSON body — including the reads, so a capability travels in the body rather than in a path or query string a server would log. GET /health is the one exception: a liveness probe that takes no input.
  • Unknown fields are rejected, not ignored. A field the API does not recognise means the caller expects something it is not honouring.
  • Amounts are decimal strings ("100.00"); base units appear alongside them as integer strings.
  • Errors return { "error": CODE }, usually with an action telling your system what to do. See Errors.
  • CORS is open and credentials are never allowed: there is no cookie or header authority for another origin to borrow.
  • Request bodies are capped at 16 KB.

Payments

POST/v1/payments

Mint a one-time payment intent.

BODY FIELDTYPEREQUIREDNOTES
recipientstringYesAddress that receives the payment.
amountstringYesDecimal USDC.

Returns intent, reference, amount, expires_at, and a pay object with chain_id, splitter, token, recipient, amount_units and reference.

POST/v1/payments/resolve

Authoritative terms for a checkout to display.

BODY FIELDTYPEREQUIREDNOTES
intentstringYesThe signed intent.

Returns the recipient, amount, base units, token, splitter, chain id, reference and expiry. Rejects a payment the contract has already settled.

POST/v1/payments/verify

Server-side proof that a payment landed.

BODY FIELDTYPEREQUIREDNOTES
intentstringYesThe signed intent.
tx_hashstringYes0x + 64 lowercase hex.

Returns HTTP 200 either way. A proven payment returns valid: true with tx_hash, reference, amount, block_number and block_hash. Anything else returns { valid: false, code } — including PAYMENT_CONFIRMING, which is not a 409 on this endpoint. Branch on valid. Only transport failures use status codes: 400 for a malformed body, 429 for rate limiting, 500 for an unexpected fault.

Subscriptions

POST/v1/subscriptions

Create the technical terms of a subscription.

BODY FIELDTYPEREQUIREDNOTES
recipientstringYesAddress that receives each renewal.
amountstringYesDecimal USDC per period.
periodintegerYesSeconds between charges.
endintegerNoUnix seconds; 0 means no end.

Returns setup_token, expires_at, chain_id, contract, amount and salt.

POST/v1/subscriptions/resolve

Terms plus the EIP-712 scaffold for a custom checkout.

BODY FIELDTYPEREQUIREDNOTES
setup_tokenstringYesFrom /v1/subscriptions.

Returns the full terms, max_gas_reimbursement, fee_bps, network_fee, typed_data, and a best-effort network_fee_estimate which may be null.

POST/v1/subscriptions/finalize

Exchange the customer’s signature for a capability.

BODY FIELDTYPEREQUIREDNOTES
setup_tokenstringYes
payerstringYesThe signing wallet.
signaturestringYesEIP-712 signature.

Returns subscription (the p2s2 capability), subscription_id, amount, period and end.

POST/v1/subscriptions/status

Current state, read from the chain.

BODY FIELDTYPEREQUIREDNOTES
subscriptionstringYesThe capability.

Returns the state fields documented in Recurring payments, including the echoed terms.

POST/v1/subscriptions/revoke/session

Mint a short-lived cancel token safe for a browser.

BODY FIELDTYPEREQUIREDNOTES
subscriptionstringYesThe capability.

Returns cancel_token, expires_at (15 minutes by default), subscription_id and payer.

POST/v1/subscriptions/revoke/prepare

Unsigned calldata that cancels one subscription.

BODY FIELDTYPEREQUIREDNOTES
subscriptionstringYesA capability or a cancel token.

Returns chain_id, payer, to, data, subscription_id and a human-readable description. Only the payer’s wallet can send it.

POST/v1/allowances/revoke/prepare

Unsigned calldata that removes the token allowance entirely.

Returns chain_id, to, data and description. Stops every P2Flux subscription paid in this token from that wallet.

Charges

POST/v1/charges

Attempt one recurring charge. Idempotent per billing period.

BODY FIELDTYPEREQUIREDNOTES
subscriptionstringYesThe capability. No amount or recipient — both come from the signed permission.

Returns status, ok, already_paid, action, subscription_id, period_index, period_start, period_end, next_period_at, and — when a transaction was sent — tx_hash and amount.

Service

GET/health

Liveness only. Returns { "ok": true } and never grows a body.

/metrics and /ready exist but are bound to a loopback-only listener and are not reachable from outside the host. They are operational, not part of the integration surface.

Rate limits

Per minute, per client IP unless noted. These are a ceiling on abuse, not a merchant quota — there are no accounts, and many merchant sites share one outbound address. Defaults shown; an operator can change them.

SCOPEDEFAULT
Global600
/v1/payments120
/v1/subscriptions120
Checkout calls (resolve, finalize)180
/v1/subscriptions/status and /v1/payments/verify300
/v1/subscriptions/revoke/session60
/v1/charges per IP300
/v1/charges per subscription6
Simultaneous charges in flight20

Exceeding one returns RATE_LIMITED or CONCURRENCY_LIMIT with HTTP 429, a retry_after field and a matching Retry-After header. Nothing was charged.

NO IDEMPOTENCY KEYS

There is no idempotency header, because the two write paths do not need one: a payment is settled once by the contract’s replay guard, and a charge is allowed once per billing period.

Something more than a standard integration?
Marketplace flows, platform billing and custom settlement logic.
Discuss an integration