FFiber Offers
Documentation / Foundations

Resolver API reference

The resolver is a compact HTTP boundary for offer discovery, readiness, invoice creation, resolution records, receipts, reconciliation, and webhook operations.

Authentication

Public reads and payment-critical requests remain open: offer fetches, Fiber Address lookup, QR codes, readiness, invoice resolution, receipts, reconciliation, and diagnostics. When RESOLVER_API_KEY is configured, offer inventory, webhook configuration and history, registration, and operator writes require a bearer token, x-api-key, or a signed operator session established through POST /operator/session.

Authorization: Bearer change-me
# or
x-api-key: change-me
Why invoice requests stay publicA payer must be able to resolve a signed merchant offer without possessing merchant credentials. The offer signature and request validation protect the payment semantics; API credentials protect merchant and operator mutations.

Endpoint map

Method and pathPurposeAuth when configured
GET /healthResolver mode and authentication state.No
GET|POST|DELETE /operator/sessionInspect, establish, or clear the browser operator session.POST validates the API key
GET /diagnostics, GET /topologyResolver, Fiber RPC, worker, and topology health.No
GET /offersList compact offer summaries for an operator console.Yes
POST /offers, POST /demo/offersRegister a signed offer or create a local demo offer.Yes
GET /offers/:offer_idOffer, encoded payload, links, QR URLs, and metadata.No
POST /offers/:offer_id/checkValidate a payment request without creating an invoice.No
POST /offers/:offer_id/invoiceCreate or replay an invoice resolution.No
GET /offers/:offer_id/resolutionsList resolution records.No
GET|POST /offers/:offer_id/webhooksList or register webhook endpoints.Yes
PATCH|DELETE /offers/:offer_id/webhooks/:webhook_idPause, resume, update, or remove an endpoint.Yes
POST /offers/:offer_id/webhooks/:webhook_id/testSend a signed test event to one endpoint.Yes
POST /offers/:offer_id/webhooks/:webhook_id/rotate-secretRotate and reveal a replacement signing secret once.Yes
GET /offers/:offer_id/webhook-eventsInspect event and delivery attempt history.Yes
GET /.well-known/fiberoffer/:usernameResolve a Fiber Address.No

Create or register an offer

The demo endpoint generates a key pair and signed offer for local development. Production merchants create and sign the offer using the protocol package, then send the encoded offer to POST /offers.

curl -X POST http://localhost:8787/demo/offers \
  -H 'content-type: application/json' \
  -H 'Authorization: Bearer change-me' \
  -d '{
    "username": "coffee",
    "description": "Coffee checkout",
    "pricing_type": "fixed",
    "amount": "1000",
    "assets": [{ "asset_type": "ckb", "symbol": "CKB" }]
  }'
curl -X POST https://resolver.example/offers \
  -H 'content-type: application/json' \
  -H 'Authorization: Bearer change-me' \
  -d '{
    "username": "coffee",
    "encoded_offer": "fbroffer1..."
  }'

The registered response contains offer_id, payment_link, encoded_offer, qr_link_url, qr_offer_url, and the optional fiber_address.

Readiness before invoice creation

Call check whenever the user has selected an amount and asset. It validates signature, pricing rules, assets, single-use state, and merchant invoice availability. Payer route payability remains unknown until the payer wallet dry-runs the fresh invoice using its own node.

POST /offers/:offer_id/check

{
  "amount": "1200",
  "asset": { "asset_type": "ckb", "symbol": "CKB" }
}
{
  "ready": true,
  "confidence": "medium",
  "next_action": "request_invoice",
  "summary": "Request is valid; a fresh Fiber invoice can be created.",
  "checks": [],
  "blockers": [],
  "warnings": []
}

payable is omitted when the payer route is unknown. After invoice creation, the payer wallet calls FiberPaymentClient.checkPaymentRoute(); a successful dry-run returns payable: true and high confidence. A controlled pair fixture may perform this check through the resolver, but it is not required for merchant operation.

Invoice resolution and idempotency

Invoice creation is intentionally separate from readiness. The resolver creates a fresh invoice only after it accepts the request.

POST /offers/:offer_id/invoice
Idempotency-Key: checkout-order-42
content-type: application/json

{
  "amount": "1200",
  "asset": { "asset_type": "ckb", "symbol": "CKB" }
}

The first successful request returns 201. Retrying exactly the same request and idempotency key returns 200 with idempotent_replay: true. Reusing the key with a different amount or asset returns 409 IDEMPOTENCY_KEY_REUSED.

Scenario: mobile retry after a network timeout

The wallet sends an invoice request but loses the response. It retries with the same idempotency key. The resolver returns the original resolution and invoice, so the user never receives a second invoice for the same checkout attempt.

Records, receipts, and exports

GET  /offers/:offer_id/resolutions
GET  /offers/:offer_id/resolutions/:resolution_id
POST /offers/:offer_id/resolutions/:resolution_id/status
POST /offers/:offer_id/resolutions/:resolution_id/sync
POST /offers/:offer_id/resolutions/sync

GET /offers/:offer_id/resolutions/:resolution_id/receipt.json
GET /offers/:offer_id/reconciliation.json
GET /offers/:offer_id/reconciliation.csv

Status writes and sync operations are protected when an API key is configured. Receipts and reconciliation files are read-only views intended for merchant systems, support workflows, and accounting exports.