API endpoints
Sill exposes its public surface from a single edge origin, https://edge.sill.so. All routes are unversioned at the host level; per-route versioning is in the path (/v1/… for the discovery and transactional routes, /.well-known/jwks.json for the verifier-facing key set). Every signed response is independently verifiable against the public JWKS using off-the-shelf ed25519 tooling — no Sill SDK is required, and there is no Sill SDK to vendor.
The transactional mandate endpoint is in Phase 2 and operates inside the dogfood-scope bounds documented there; the rest of the surface is live for every verified site.
Endpoint summary
Section titled “Endpoint summary”| Method | Path | Purpose | Auth | Doc |
|---|---|---|---|---|
POST | /v1/discovery/ingest | Discovery beacon from the embed script. | None (public, site-key scoped). | Embed script |
GET | /v1/agent-card/{site_key}.json | Per-site signed A2A-compatible agent card. | None. | Agent card |
GET | /v1/catalog/{site_key}.json | Per-site signed ARD ai-catalog.json. | None. | ARD catalog |
POST | /v1/mcp/{site_key} | Per-site Streamable-HTTP MCP server. | None at the transport; tool invocation is policy-gated. | MCP server |
POST | /v1/m/{site_key}/mandate | Transactional mandate submission. | ed25519-signed mandate in the request body. | Signed mandates |
GET | /.well-known/jwks.json | Public JWKS for verifying every Sill-issued signature. | None. | Public JWKS |
{site_key} is the public per-site credential issued in the dashboard. It is a public identifier, not a secret — the same posture as a Stripe publishable key. The site-key shape is validated at the edge against ^(sk_)?[A-Za-z0-9_-]{43}$ before any KV read.
Conventions
Section titled “Conventions”- Transport: HTTPS only. The edge does not serve plaintext.
- CORS: every route handles its own
OPTIONSpreflight at the edge. Public GET surfaces (agent-card,catalog,jwks) reply withAccess-Control-Allow-Origin: *. The mandate endpoint echoes the requestOriginand never setsAccess-Control-Allow-Credentials— authentication is the signed mandate body, not a cookie. - Caching: signed
GETsurfaces carryCache-Control: public, max-age=60(cards and catalogs) orpublic, max-age=300(JWKS). Error responses areno-storeto prevent intermediate caches from pinning a 404 for a key that may become valid. - Method-not-allowed: any method outside the documented set returns
405with anAllow:header naming the supported methods. - Anti-fingerprinting:
404responses for unknown or malformed site keys return a constant body ({"error":"not_found"}) so probing cannot distinguish “never existed” from “exists but you can’t see it”. - Timestamps: every timestamp on the wire is ISO-8601 UTC.
- Encoding: signatures and public keys use unpadded base64url per RFC 4648 §5.
- Canonicalization: every signed payload is canonicalized with RFC 8785 JCS before signing.
Architecture
Section titled “Architecture”flowchart LR
Browser[Merchant page<br/>+ embed.js] -->|POST /v1/discovery/ingest| Edge
Agent[AI agent] -->|GET, POST /v1/...| Edge
Verifier[Third-party verifier] -->|GET /.well-known/jwks.json| Edge
Edge[Edge · edge.sill.so] -->|signed records| Origin[Sill origin]
The edge owns the latency-sensitive surface — manifest serving, MCP transport, mandate verification, signing-key publication. The origin owns audit storage, the identity registry, and connectors. Every signed surface uses the same ed25519 key (kid: foyer/edge/card-signing-v1), so a single JWKS resolves both an agent card and an ARD trust manifest.
Discovery ingest
Section titled “Discovery ingest”POST https://edge.sill.so/v1/discovery/ingest
The fire-and-forget beacon the embed script emits once per page load. The body is a small JSON envelope (schema_version: "1") carrying the site key, an observed_at timestamp, and nested identification and page_context objects; success is 204 No Content with no body.
curl -i -X POST https://edge.sill.so/v1/discovery/ingest \ -H 'Content-Type: application/json' \ --data '{ "schema_version": "1", "site_key": "sk_EXAMPLE_REPLACE_WITH_YOURS_AAAAAAAAAAAAAAAAA", "observed_at": "2026-06-22T14:03:11.000Z", "identification": {}, "page_context": {} }'The merchant’s bundle does not have to call this directly — the embed script handles it via navigator.sendBeacon. The endpoint is documented here for completeness and for diagnostic curl. See Identifying agents for how Sill classifies the caller.
Agent card
Section titled “Agent card”GET https://edge.sill.so/v1/agent-card/{site_key}.json
Per-site, signed, A2A-compatible agent card. protocol_version: "a2a/1.2". The card’s skills[] is backing-filtered — only skills the site actually exposes through a wired backing appear.
curl -i "https://edge.sill.so/v1/agent-card/SITE_KEY.json"Response headers (200):
HTTP/2 200content-type: application/json; charset=utf-8cache-control: public, max-age=60access-control-allow-origin: *The card body includes a detached ed25519 JWS (alg: EdDSA, crv: Ed25519) over the canonical card payload. To verify, follow the Verify a signature recipe; the JWKS is at /.well-known/jwks.json.
404 is returned uniformly for unknown, malformed, or non-existent site keys; 503 is returned when an upstream dependency is unreachable on a cold path.
ARD catalog
Section titled “ARD catalog”GET https://edge.sill.so/v1/catalog/{site_key}.json
Per-site signed Agentic Resource Discovery ai-catalog.json. specVersion: "1.0". host.identity: did:web:{domain} per the did:web method. Each trustManifest carries a compact, detached ed25519 JWS over the JCS-canonical manifest body.
curl -i "https://edge.sill.so/v1/catalog/SITE_KEY.json"Response headers (200) match the agent card’s: Cache-Control: public, max-age=60, CORS *. The signature attests the host identity + provenance; the per-entry url / capabilities / description fields are not inside the signed payload — their integrity rests on did:web + TLS per the ARD spec.
MCP server
Section titled “MCP server”POST https://edge.sill.so/v1/mcp/{site_key}
Per-site Streamable-HTTP Model Context Protocol server. Implements the standard MCP handshake (initialize), tool discovery (tools/list, backing-filtered to match the agent card), and tool invocation (tools/call, recorded in the site’s signed audit log).
curl -i -X POST "https://edge.sill.so/v1/mcp/SITE_KEY" \ -H 'Content-Type: application/json' \ -H 'Accept: application/json, text/event-stream' \ --data '{ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2025-03-26", "capabilities": {}, "clientInfo": { "name": "example-client", "version": "0.0.0" } } }'MCP responses themselves are not signed — only the agent card’s pointer to the MCP endpoint is signed. Money-movement skills (e.g. place_order) require a signed mandate and route through the same transactional pipeline as /v1/m/{site_key}/mandate. See MCP server for the scope of claim.
Transactional mandate
Section titled “Transactional mandate”POST https://edge.sill.so/v1/m/{site_key}/mandate
Submits a signed mandate for verification, policy evaluation, and (on approval) processor authorization. Authentication is the ed25519 signature carried inside the request body — there is no Authorization header, no cookie, and no API key. The body is capped at 8 KB; oversize requests reject before parsing.
curl -i -X POST "https://edge.sill.so/v1/m/SITE_KEY/mandate" \ -H 'Content-Type: application/json' \ -H 'X-Sill-Request-Id: req_example_correlate_me' \ --data @mandate.jsonmandate.json is the two-part { signed, envelope } shape described in Signed mandates.
Response taxonomy
Section titled “Response taxonomy”The response body is a small JSON envelope discriminated by an outcome field. The HTTP status is the secondary signal — the outcome is load-bearing.
| Outcome | HTTP | When |
|---|---|---|
approved | 200 | Policy passed; the processor was asked to authorize. |
escalated | 202 | Policy escalated to human-in-the-loop review. |
rejected | 400 / 401 / 403 / 404 / 413 / 415 | Mapped to the rejection class — see Signed mandates → rejection taxonomy. |
rate_limited | 429 | Per-account or per-site limiter tripped; includes retry_after_seconds. |
unavailable | 503 | Verifier dependencies (nonce store, registry) could not answer. Fail-closed. |
Example approved response:
HTTP/2 200content-type: application/jsoncache-control: no-store
{ "outcome": "approved", "mandate_id": "mnd_01J9XYZABCDEFGHJKMNPQRSTVW", "record_id": "rec_01J9XYZAAAAAAAAAAAAAAAAAAA", "evaluated_at": "2026-06-22T14:03:11.000Z", "rules_evaluated": 28}Example rejected response (signature failed verification):
HTTP/2 401content-type: application/jsoncache-control: no-store
{ "outcome": "rejected", "reason": "signature_invalid"}Clients may send an X-Sill-Request-Id header for correlation; if present, it is echoed back on the response.
Public JWKS
Section titled “Public JWKS”GET https://edge.sill.so/.well-known/jwks.json
The public ed25519 signing key in RFC 7517 JWKS form. The same key signs every Sill-published agent card and ARD trust manifest, so a verifier resolves both surfaces with a single fetch.
curl -i "https://edge.sill.so/.well-known/jwks.json"Response (truncated for the example x value):
HTTP/2 200content-type: application/jwk-set+json; charset=utf-8cache-control: public, max-age=300, s-maxage=300access-control-allow-origin: *
{ "keys": [ { "kty": "OKP", "crv": "Ed25519", "alg": "EdDSA", "use": "sig", "kid": "foyer/edge/card-signing-v1", "x": "<base64url-32-byte-public-key>" } ]}Algorithm + key type follow RFC 8037 (EdDSA in JOSE) and JWS. See Verify a signature for the end-to-end recipe.
Verifier flow
Section titled “Verifier flow”The signed-surface endpoints are designed so that a third party can prove provenance without trusting Sill’s word for it.
sequenceDiagram
autonumber
participant Verifier as Third-party verifier
participant Edge as edge.sill.so
Verifier->>Edge: GET /v1/agent-card/{site_key}.json
Edge-->>Verifier: 200 + signed card (detached JWS)
Verifier->>Edge: GET /.well-known/jwks.json
Edge-->>Verifier: 200 + JWKS (ed25519 public key)
Verifier->>Verifier: JCS-canonicalize card payload
Verifier->>Verifier: Reconstruct JWS signing input
Verifier->>Verifier: ed25519.verify(sig, input, jwk.x)
The same flow applies to the ARD catalog’s trust manifest. The transactional mandate uses an analogous recipe but with a different domain-separation tag (sill-mandate-v1) and the agent’s registered key, not Sill’s; see Signed mandates → verifying a mandate signature.
Common questions
Section titled “Common questions”Is there a Sill SDK?
No. The verifier path uses only standard tools: any RFC 8785 (JCS) canonicalizer and any reputable ed25519 library (@noble/ed25519, pynacl, tweetnacl, OpenSSL). Sill publishes no client SDK for the verifier surface, and there is no Sill code in the verifier path.
Do I authenticate to call these endpoints?
The GET surfaces (agent-card, catalog, jwks) and the discovery ingest are unauthenticated. The MCP transport is unauthenticated; tool invocation is policy-gated, and money-movement tools require a signed mandate. The transactional mandate endpoint authenticates via the ed25519 signature inside the request body — there is no API key or bearer token.
Why is the site key in client-side HTML? The site key is a public identifier, not a secret. It is analogous to a Stripe publishable key. It identifies which Sill site an interaction belongs to; it does not authorize any privileged action on its own.
What happens if Sill’s verifier can’t answer?
The mandate endpoint returns 503 unavailable. Sill is fail-closed by design — an unreachable registry or nonce store never produces an approval. See Signed mandates → replay defense.
Which protocols does the mandate endpoint accept?
Currently a2a, ap2, and mcp on the edge allowlist. acp, ucp, and x402 are on the roadmap; see Protocols reference.
Is there a status page?
The origin liveness check is at https://api.sill.so/healthz. Sill does not currently publish an uptime SLA for the edge endpoints; see Security overview.
See also
Section titled “See also”- Embed script — install snippet and beacon shape.
- Agent card — signed identity surface.
- ARD catalog — signed resource catalog.
- MCP server — per-site Streamable-HTTP MCP transport.
- Signed mandates — request shape and rejection taxonomy.
- Policy engine — how rules drive
approve | escalate | reject. - Public JWKS — verifier key set.
- Verify a signature — end-to-end recipe.
- Audit envelope — signed, Merkle-chained record format.
- Protocols reference — A2A, AP2, MCP, and the roadmap.
- Security overview — fail-closed posture, threat model.
- External: RFC 7517 JWKS, RFC 8037 EdDSA in JOSE, RFC 8785 JCS, RFC 8032 ed25519, MCP, did:web, OWASP Top 10 for Agentic Applications, MITRE ATLAS, NIST AI RMF.