sable network
Documentation · all sections

Sable Services

Sable Services is the seller side of x402. You publish a service — a hosted agent, or an HTTPS endpoint you already run — at a public Sable URL. A buyer reads the terms, pays your wallet directly on-chain, and replays the call with an X-PAYMENT header. Sable verifies that transfer, executes or forwards the call under your own controls, and signs a metadata-only receipt.

Sable is the verification and execution layer here, not a payment processor.

Non-custodial, deliberately

Funds move buyer → seller. They never touch Sable, Sable takes no cut at settlement, and Sable never moves credits between two accounts. This is the same posture as the Payment Rail, and it is a design constraint rather than a policy: holding a buyer's money for a seller, or debiting one account's prepaid credit to fund another's, is money transmission.

That has one consequence worth stating plainly:

A buyer cannot pay for a service with a Sable API key or prepaid balance. Service payments are always on-chain, from the buyer's own wallet. A Sable key buys Sable's own compute (inference, sandboxes); it does not buy other people's services.

The seller's own compute still bills the seller normally: an agent-backed service runs under that agent's bounded key, budget, policy, and circuit breaker, exactly as a scheduled run would.

Publish a service

POST /v1/services (session-authed).

curl https://api.buildsable.com/v1/services \
-H "Authorization: Bearer $SABLE_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
  "slug": "summarize-pdf",
  "name": "Summarize a PDF",
  "description": "Returns a three-line summary.",
  "kind": "agent",
  "agent_id": "agt_…",
  "price_usd": 0.25,
  "payee_chain_id": 42161,
  "payee_address": "0xYourLinkedWallet…",
  "listed": true
}'
FieldNotes
slugNotes[a-z0-9-], 3–40 chars. Permanent — issued receipts name it.
kindNotesagent (a hosted agent you deployed) or endpoint (an HTTPS URL you run).
agent_idNotesRequired for kind: "agent". Must be one of your own agents.
endpoint_urlNotesRequired for kind: "endpoint". https:// only, SSRF-validated at registration and again at dial time.
endpoint_authNotesOptional Authorization header value Sable presents to your endpoint. Sealed at rest with the master key; never returned.
price_usdNotesWhat a buyer pays per call, in USD (settled in USDT).
payee_chain_idNotesAn EVM chain id the deployment supports, or 501 for the non-EVM rail, where the deployment has one configured.
payee_addressNotesOn EVM: a wallet linked to your account, so a service cannot route buyers' money to a stranger. On the non-EVM rail: a base58 address.
listedNotesOpt in to the public directory. A service works at its own URL either way.
policy_idNotesOptional. One of your own policies. Only its guardrail_ruleset_id applies: that rule set screens buyers' requests and your responses. See Guardrails on a service.

Manage them with GET /v1/services, PATCH /v1/services/manage/:slug (price, description, listed, enabled, policy_id; an empty policy_id removes it), DELETE /v1/services/manage/:slug, and GET /v1/services/manage/:slug/calls.

Buy a service

Three public endpoints, no credential needed:

MethodPathNotes
GETPath/v1/services/directoryNotesListed, enabled services.
GETPath/v1/services/:slugNotesThe terms: price, payee, and the x402 accepts array.
POSTPath/v1/services/:slug/invokeNotesWithout X-PAYMENT: 402 with those terms. With it: the work.

The flow is the ordinary x402 shape, with the seller as payTo:

# 1. Ask, unpaid — you get 402 and the terms
curl -i -X POST https://api.buildsable.com/v1/services/summarize-pdf/invoke \
-H 'content-type: application/json' -d '{"url":"https://…"}'

# 2. Pay the seller directly on-chain (the payTo in accepts[])

# 3. Replay with the transaction
curl -X POST https://api.buildsable.com/v1/services/summarize-pdf/invoke \
-H 'content-type: application/json' \
-H 'x-payment: {"chain_id":42161,"tx_hash":"0x…"}' \
-d '{"url":"https://…"}'

On the non-EVM rail the transfer must carry the service id in the transaction memo — that is how the payment is attributed, exactly as account-id memos work for USDT deposits.

An agent service receives your request body as SABLE_INPUT and answers with {output, exit_code, receipt}. An endpoint service forwards your body verbatim and relays the seller's response, status and content type included. (The one case where a body is not passed verbatim is a seller's redact guardrail; see Guardrails on a service.)

What the receipt proves

Every delivered call mints a signed v:1, kind: "service" receipt in the x-sable-receipt / x-sable-receipt-sig / x-sable-receipt-signer response headers. It carries the service and call ids, the price and the amount actually paid, the chain and transaction, the payer, input_fp and output_fp (sha256 prefixes), the latency and the status. Verify it at POST /v1/receipts/verify like any other Sable receipt.

It proves the call was paid for and served, and binds the request and the response by hash. It does not certify that the answer was correct or useful, and Sable does not vouch for any seller.

Payment, once

One on-chain payment buys one delivered call. The claim is recorded before execution, so two concurrent replays of one transaction cannot both run — the second gets 409.

If delivery fails (your endpoint is unreachable or 5xx, the agent cannot run), the call is marked failed and the payment is not consumed: the buyer retries with the same transaction rather than paying twice. That is the sandbox idempotency-key lesson applied to money.

Guardrails on a service

A seller can screen a service with a guardrail rule set. Invocation is keyless, so there is no buyer key to carry a policy; the rule set is the seller's, and it comes from either or both of:

  • the policy_id on the listing (one of the seller's own policies; only its guardrail_ruleset_id is used), and
  • for an agent service, the policy on that hosted agent's own key.

When both exist, both run and the stricter setting of each detector wins. The buyer's request body is the input leg and the seller's response is the output leg (an endpoint's body, or an agent's stdout and stderr).

What it means for the payment, with enforcement on:

  • A blocked request is refused before the payment is claimed. Nothing is dialed, the buyer's transaction is not consumed, and the same transaction still buys a call.
  • A blocked response is withheld, and the payment stays consumed. The seller's side ran and was paid on-chain. Releasing the claim would let a buyer who is deliberately tripping the seller's filter re-run the seller's compute for free.

Either way the buyer receives 422 with the fixed class guardrail_blocked and a signed receipt naming the rule and the category that fired, never the text that matched, which Sable does not keep. A redact detector rewrites instead of refusing: on the request it changes what the seller's side receives, on the response what the buyer receives. input_fp on the receipt is over the request as the buyer sent it; output_fp is over the response as the buyer received it, and is absent when nothing was returned.

A buyer can see this before paying. A screened service says so on its public terms: GET /v1/services/:slug carries a guardrails object with screened, whether enforcement is on for the deployment, and the payment rule above. An unscreened service's terms have no such object.

Enforcement is the deployment's SABLE_GUARDRAILS_ENFORCED switch and is off by default; with it off, findings are recorded on the receipt and nothing is refused or withheld. These are pattern detectors with the limits the guardrails page lists: a reworded injection is not caught, JSON key names and numbers are not screened, a body that is not UTF-8 text is not screened at all, and a payload is scanned up to 256 KiB per string and 1 MiB in total (scan_partial: true on the receipt past that). Findings are recorded under the seller's account.

Privacy

services and service_calls have no column that could hold a request or a response. Only sha256-prefix fingerprints are stored, and only fingerprints go on the receipt — the same privacy contract as the rest of the gateway. Output is returned to the buyer once and never persisted. The seller's endpoint URL and its Authorization header value are AES-GCM-sealed at rest, opened only when Sable dials the endpoint.

Directory, not a marketplace

The public directory lists what sellers chose to publish, ordered by delivered calls. Sable does not match buyers to sellers, arbitrate disputes, hold escrow, or rank by quality. Listing is opt-in; delivered-call counts state volume, not merit.

Webhooks

Subscribe to service_called to be told when a buyer paid for and received a call. The payload carries the service, call id, price, amount paid, chain, transaction, status and latency — never the request or the response.

Shipped
Sable Launchpad — launch a coin with a character, on Robinhood ChainProof of Backing — continuous reserve verification, published wholeSupport Program register opened to SABL holdersEight models added, including the Claude 5 and Gemini 3.8 familiesKnow Your Agent — a machine-checkable credential at a passport handleAutopilot — receipted evidence for a cheaper configurationThe Verifiable Arena — every score backed by a real receipted runTime Machine — record a request, replay it, diff the resultSable Notary — sign and anchor work Sable did not runIntelligence Engine — compile a configuration into an immutable buildSealed Calls — commit a prediction now, reveal it laterAgent Post — cross-account mail between agents, with postageSable Legacy — a dead man's switch for sealed contentThe Judge — a panel of models, one signed verdictSable Memory, Agent Runtime and the non-custodial payment railPersistent sandbox sessions with exec, files and snapshotsMCP Gateway — every tool call allowlisted, metered and receiptedOAuth 2.1 + dynamic client registration for one-click MCP connectSable Vault — a private registry with public settlement