Partner reference

rufly Commerce API for AI agents

This reference is for approved partner platforms whose assistants buy travel eSIMs on a shopper's behalf. It documents request shapes, rules and refusal codes. Version 2026-09-20.

Base URL: https://rufly.co/api/public/v1
Machine-readable contract: /api/public/v1/openapi.json

Authentication

Every call needs a partner key issued by rufly, sent as Authorization: Bearer rufly_live_.... Keys are shown once at issue and can be revoked instantly. There is no self-service signup, and no end-user account is required.

Keys carry one of two permissions. A browse-only key can search destinations, read live plans and check phone compatibility. A purchase-enabled key can additionally lock a price and open a payment page. A key used outside its permission is refused with FORBIDDEN.

Rate limits

Each key has its own per-minute allowance for browsing calls, 60 by default. Payment-page creation is limited to 20 requests per minute and order lookups to 30 requests per minute, per key. A refusal returns 429 RATE_LIMITED with a Retry-After header in seconds.

Conventions

JSON only. Timestamps are UTC ISO 8601. Countries are ISO 3166-1 alpha-2 and currencies ISO 4217, limited to EUR, USD, GBP and AUD. Money is returned both as integer minor units and as a formatted display string.

Send X-Request-Id to have your identifier echoed on the response and stored in our request log. Send Idempotency-Key when creating a quote so retries are safe; reusing that key with different details is refused rather than answered with the wrong price. Payment-page creation is idempotent on quote_id: one quote can only ever produce one order.

List endpoints paginate with an opaque cursor. A cursor we did not issue is refused with INVALID_REQUEST. The catalogue is live, so prices and availability may change between pages.

Endpoints

GET/destinations

Find a destination rufly sells.

Includes countries covered only by a regional plan; those carry covered_by naming the plan that covers them.

GET/plans

List sellable plans with live prices.

Filter by destination, duration_days and currency. Each plan carries its data allowance and its donation block.

GET/plans/{plan_id}

One plan in full.

Refused with PLAN_UNAVAILABLE if the plan is no longer sellable.

POST/device-check

Check whether a phone supports eSIM.

Answers supported or needs_confirming. Takes a device name only; no identifiers, no IMEI.

POST/quotes

Lock a price for 15 minutes.

Optional travel_date (today or later, within 400 days) and discount_code. Only a live quote may be read out to a shopper or turned into a payment page.

POST/checkouts

Turn a quote into a rufly-hosted payment page.

Takes the quote and the email the eSIM should go to. Returns a short-lived link. Repeat calls replay the same order, refresh an expired link, or report that the shopper has already paid.

GET/checkouts/{checkout_id}

Has the shopper paid?

Status is open, expired or paid. An expired link is replaced by calling POST /checkouts again with the same quote_id.

GET/orders/{order_id}

Order and eSIM delivery status.

Requires the buyer's email as a query parameter and returns that address masked, plus the data allowance and the donation the order funded.

GET/orders/{order_id}/installation

Installation steps that are safe to read aloud.

Generic guidance only. Also requires the buyer's email.

How a purchase works

An assistant finds a plan, locks a price, then receives a rufly-hosted payment link. The shopper approves and pays on that page. Card details are never sent to this API and never pass through the partner platform.

The total is recomputed from the live plan before any charge, so a quoted price cannot drift. A quote is valid for 15 minutes; after that, QUOTE_EXPIRED is returned and a fresh quote is needed.

The eSIM QR code and activation codes are never returned by this API. They are emailed to the buyer only, exactly as for a purchase made on the website.

The donation block

A fixed share of every rufly plan funds meals at animal shelters, wherever possible one local to the destination. Plans, quotes and orders all carry a donation block with the amount, the meals it funds, the shelter where known, and whether it is committed or still awaiting payment. Assistants are encouraged to mention it when presenting a price.

Refusal codes

Failures return { request_id, error: { code, message } } with an HTTP status. The message is written to be read aloud to a shopper. Codes are stable:

  • UNAUTHORIZED 401, FORBIDDEN 403 — key missing, revoked, or outside its permission.
  • INVALID_REQUEST 400, UNSUPPORTED_CURRENCY 400 — malformed input or a currency we cannot price right now.
  • DESTINATION_NOT_FOUND, PLAN_NOT_FOUND, QUOTE_NOT_FOUND, ORDER_NOT_FOUND 404.
  • PLAN_UNAVAILABLE, QUOTE_EXPIRED, QUOTE_ALREADY_USED, CHECKOUT_UNAVAILABLE 409.
  • RATE_LIMITED 429, INTERNAL_ERROR 500.

Not available in this version

Refunds, plan extensions, top-ups, multi-plan baskets, QR code retrieval, and any purchase the shopper has not explicitly approved. Refunds and support are handled by rufly directly.

Requesting access

Partner keys are issued by rufly on request. Reach us through rufly.co/contact.