API

Anyflo API

Anyflo API is the secure entry point for external requests to the Anyflo system. It authenticates clients, enforces permissions, and forwards requests to downstream services.

Request flow

A principal is a unique entity, such as a person or service, that the system can authenticate and authorize.

  1. The client sends a request with an Authorization: Bearer anyflo_sk_<secret> header for customer access, or a Cf-Access-Jwt-Assertion header for admin access.
  2. The gateway routes the credentials to the appropriate verifier and resolves the principal into the request context: a customerId and scopes, or an admin identity.
  3. After authorization and ownership checks, downstream services receive the resolved identity over private service bindings. They trust the gateway and do not re-authenticate the request.
flowchart TD Customer["Customer client"] -->|Bearer API key| Gateway["Anyflo API"] Admin["Admin client"] -->|Cf-Access-Jwt-Assertion| Gateway Gateway -->|Customer credentials| Coordinator["Coordinator: verify API key"] Gateway -->|Admin credentials| AdminVerifier["Admin credential verifier"] Coordinator -->|Customer ID and scopes| Principal["Resolved principal"] AdminVerifier -->|Admin identity| Principal Principal --> Checks["Authorization and ownership checks"] Checks -->|Identity over private service bindings| Services["Downstream services"]

OpenAPI documentation

Use the API documentation to explore the current specification:

  • GET /v1/docs — Swagger UI for the OpenAPI specification.
  • GET /v1/openapi.json — the OpenAPI JSON definition for documentation tools, code generation, machine-readable discovery, and AI-agent integration.

Content negotiation

The API supports CBOR and JSON. CBOR is the default and recommended format.

FormatRequest Content-TypeResponse Accept
CBOR
(default, recommended)
application/cborapplication/cbor
or omit
JSONapplication/jsonapplication/json

Set Content-Type to match your request body.
To receive JSON responses, set Accept: application/json.
If you omit Accept or set it to application/cbor, responses use CBOR.

BigInt values in JSON

JSON has no native BigInt type, so BigInt values are serialized as decimal strings:

{
  "amount": "1000000000000000000"
}

Send BigInt fields as numeric strings in JSON request bodies. CBOR supports BigInt natively.

Authentication

Customers authenticate with opaque API keys in the form anyflo_sk_<secret>:

Authorization: Bearer anyflo_sk_<secret>

The gateway hashes the key with BLAKE3-256 and verifies it through the Coordinator on every request, resolving the customer ID and the key’s scopes. Keys have individual scopes and can be revoked. Rotate a key by adding a replacement and revoking the old key.

Unknown, invalid, or revoked credentials return HTTP 401. A route-scope table enforces authorization and rejects access unless the required scopes are present. Ownership checks at the gateway prevent access to another customer’s resources.

Creating an order

  • senderId must be a valid UUID belonging to the authenticated customer.
  • recipientId is optional. When provided, it must be a valid UUID belonging to a registered user. When omitted, the order has no associated recipient ID, allowing transfers to unregistered users.

Rate limiting

API requests are rate-limited per actor using Cloudflare’s Rate Limiting binding. Limits count requests over a configured time window and are eventually consistent. Requests over the limit return HTTP 429.

TierRate limitCounted by
Public100 requests per secondClient fingerprint
(IP address and user agent)
Standard customer10,000 requests per 60 secondsCustomer ID
(customerId)

The public rate is expressed as a per-second equivalent; the current gateway configuration enforces it over a 10-second window.

  • Authenticated customers — requests are counted by customerId and use the customer’s configured tier. The default tier is standard; unrecognized tier values fall back to it.
  • Unauthenticated requests — requests use the public tier and are counted by a client fingerprint based on IP address and user agent.
  • Failed authentication — requests also count against the public tier, so invalid keys cannot bypass rate limiting.
  • Admin requests — these are not currently rate-limited.

Rate-limit binding errors allow requests to continue. The deployment’s gateway configuration defines the request counts and time windows for each tier.

Local API examples

These examples require a gateway running locally on port 8792. Set ANYFLO_API_KEY to a valid API key for your local environment. Each example explicitly requests a JSON response.

Register a user

Use a key with the UsersCreate scope:

curl -X POST http://localhost:8792/v1/customer/register-user \
  -H "Authorization: Bearer ${ANYFLO_API_KEY}" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"externalUserId": "local-user"}'

Retrieve signed deposit instructions

Replace <order-id> with an accepted order’s ID:

curl "http://localhost:8792/v1/orders/<order-id>?instructions=true" \
  -H "Authorization: Bearer ${ANYFLO_API_KEY}" \
  -H "Accept: application/json"

Errors

Anyflo Pay returns standard HTTP status codes. The body of an error response includes a code, message, and optional field identifier.

{
  "error": {
    "code": "quote_expired",
    "message": "The selected quote has expired. Request a new quote and retry.",
    "field": null
  }
}

WebSocket API

Solvers

Solvers connect to the Solver Hub’s /connect endpoint over WebSockets to receive order broadcasts and notifications. The connection is authenticated with a solver JWT.

Customer notifications

The customer app backend connects to the Gateway’s /v1/notification/ws-connect endpoint using a customer API key to receive order status updates.

This is a unidirectional channel: all messages are sent from the Anyflo server to the customer app backend server.

Instructions

  • Customer app backend must initiate the WebSocket connection to get order status updates.
  • The customer app should then forward the updates to user interface apps.
    • Web apps MUST not create a WebSocket connection to the Anyflo server — this would expose the customer API key.

Notification messages

The Notification Hub sends binary messages encoded using CBOR. Decode each message to read its type and payload.

The current message type is OrderStatusChanged.

FieldDescription
typeOrderStatusChanged
payload.orderIdUUID of the order
payload.statusUpdated order status
payload.userIdUUID of the notified customer’s user participating in the order as sender or recipient
payload.timestampTime the notification was generated, as a Unix timestamp in milliseconds
payload.metadataOptional object containing additional information

Subscriptions are scoped to the authenticated customer. A connection receives order status updates for that customer’s users, including orders where a user is the recipient.


Webhooks Coming soon

Subscribe to order lifecycle events without polling.

Webhooks will deliver signed JSON payloads to a URL you register on the dashboard. Each event will include the complete current order object and the event type.

Planned event types

  • order.quoted — a winning quote was selected.
  • order.awaiting_deposit — sender funds expected at deposit address.
  • order.settling — solver has fronted the destination payout.
  • order.completed — destination payout confirmed.
  • order.failed — order entered terminal failure state.

Signatures will use HMAC-SHA256 over the raw request body with your webhook secret. A timestamp header will provide replay protection.