Capabilities

A capability is the unit of paid API access in Lipafy. Every capability has:

  • A globally-unique slug (eats.glovo.order, airtime.safaricom.topup, kyc.smile-id.verify)
  • A price in some currency (today, KES)
  • An upstream HTTP endpoint the gateway forwards to
  • An auth config Lipafy injects when forwarding (Bearer / API key header / Basic / none)
  • A status (active / draft / disabled)

When an agent calls /gateway/<slug>/..., Lipafy:

  1. Looks up the capability
  2. Validates the caller’s spending controls
  3. Holds the price against their wallet
  4. Forwards to the upstream URL with the injected auth
  5. Settles the hold on success, releases on failure

Anatomy

1{
2 "slug": "eats.glovo.order",
3 "name": "Glovo food order",
4 "description": "Place a food order on Glovo Kenya. Returns order id + ETA.",
5 "provider_type": "passthrough",
6 "provider_config": {
7 "endpoint_url": "https://api.glovoapp.com/v3/orders",
8 "auth_type": "bearer",
9 "auth_value": "<encrypted at rest>"
10 },
11 "price_amount": "500",
12 "price_currency": "KES",
13 "status": "active",
14 "owner_account_id": "uuid"
15}

Slug conventions

Dotted, lowercase, hyphens allowed inside segments:

<domain>.<brand>.<action>
SlugReads as
eats.mama-oliech.orderEats domain, Mama Oliech brand, order action
airtime.safaricom.topupAirtime domain, Safaricom brand, topup action
kyc.smile-id.verify-documentKYC domain, Smile ID brand, verify-document action

The first segment doubles as the merchant identifier for intent-mandate allow-listing. A mandate that lists eats allows all eats.* slugs.

Auth types

Lipafy never gives the agent the provider’s credential. The agent only authenticates against Lipafy; Lipafy authenticates against the provider on every forward.

auth_typeWhat gets injected on the forwarded request
nonenothing (the upstream is public)
bearerAuthorization: Bearer <auth_value>
api_key<header_name>: <auth_value> — see provider_config.header_name
basicAuthorization: Basic base64(<auth_value>)

auth_value is encrypted at rest with AES-256-GCM. Only the gateway path decrypts it.

Lifecycle states

  • draft — registered but not yet callable. Use for development.
  • active — live, callable by any account with funds.
  • disabled — soft-deleted. The row is preserved (so historical capability_requests still reference a valid id) but the gateway 422s on calls.

A delete on a capability is always a soft-delete; rows in wallet_transactions and capability_requests keep referring to it.

Pricing

Today’s model: flat per-call price in one currency. If one upstream service needs different prices for different operations, register separate capability slugs for those operations.

Visibility

A capability has one of three statuses, and visibility follows from that:

  • draft — only the owner sees it (GET /v1/capabilities/mine). Self-serve registrations default here.
  • active — listed in the public registry (GET /v1/capabilities, no auth required) and callable by any funded wallet.
  • disabled — hidden from public listings; existing receipts and references stay intact.

Two paths to a public listing:

  1. Self-serve — register at /capabilities/new, then PATCH the status to active when ready. Useful for capabilities you own and operate yourself.
  2. Apply — for third-party devs submitting a service for inclusion: /capabilities/apply. Lipafy reviews submissions before listing them publicly. See Apply for a public capability.

Forwarding semantics

The gateway forwards the agent’s request as-is to the upstream, except:

  • Authorization, X-Payment-Authorization, Cookie, and hop-by-hop headers are stripped (they belong to Lipafy ↔ agent, not Lipafy ↔ upstream)
  • The configured auth_type injects its own header
  • Request method, path (everything after /gateway/<slug>/), and body pass through unchanged

The upstream’s response — status, body, content-type — is returned to the agent, augmented with Lipafy’s X-Payment-* headers that quote the price and reference id of the charge.