Gateway manifest (bazantic.yaml)
Preview the proposed bazantic.yaml format for declaring one or more gateways as code.
Preview — not released yet
You cannot create a gateway from this file with the released CLI. The manifest workflow
is in design review, and its fields and commands can change. Today, use baz gateway add
as shown in Command line.
bazantic.yaml describes one or more gateways as desired state. You edit the file,
plan shows the difference against your live gateways, and apply reconciles it.
A second apply of the same file makes no changes and no writes. The running gateway
picks up each write within about 30 seconds. There is no redeploy step.
The default manifest needs no blockchain knowledge. You name your API and set a price. Bazantic provisions the payout wallet on a personal account. An organization account pays out to its default payout account. Networks come from the environment you deploy to. Chain identifiers never appear in the file.
A minimal manifest
version: 1
gateways:
- handle: acme-weather
listing:
name: "Acme Weather API"
category: DATA
upstream:
url: https://api.weather.example
spec:
type: openapi
url: https://api.weather.example/openapi.json
default_price: $0.001
methods:
- verb: GET
path: /v1/current
- verb: GET
path: /v1/forecastYou do not hand-type the method list. baz gateway init --from-spec <url> reads your
OpenAPI or OpenRPC document and writes the methods out, one per line, at default_price.
That command is part of the proposed workflow and is not available in the released CLI.
What you can do today
Use the same spec URL and upstream URL with the released command:
baz login
baz gateway add \
--spec-url https://api.weather.example/openapi.json \
--endpoint https://api.weather.example \
--name "Acme Weather API" \
--status draft \
--jsonThis registers one draft gateway. Set its method prices in the dashboard, then activate it with its server-generated slug:
baz gateway list --json
baz gateway activate <slug>Activation checks the stored methods, specification, credential, and payout setup. A failed check keeps the gateway in draft and prints the error code with correction instructions.
The released CLI does not read bazantic.yaml, calculate a plan, or apply a file.
The three names
Every gateway has three names. The manifest writes two of them.
| Name | Who writes it | What it does |
|---|---|---|
handle | You | The public name (handle: acme-weather). A DNS label, 3–63 characters. Globally unique, first come — like an npm package name. apply matches gateways on it. |
listing.name | You | The display title shown in the catalog. |
slug | The server | The permanent internal identifier. Every gateway URL routes on it. It never appears in the file. |
Fields
| Field | Meaning |
|---|---|
version | Always 1. |
handle | Public name. Required. |
listing | name (required, ≤60 chars), optional category (DATA, DEFI, INFRA, AI, ANALYTICS, MONITORING, PAYMENTS), and optional tagline, description, tags, product_website, docs_url. |
upstream.url | Your API's base URL. https only. Use the host that answers — see Redirects. |
upstream.spec | Optional API document: type (openapi or openrpc) and an https url. It drives discovery and generated MCP metadata. |
upstream.auth | Optional credential the gateway sends to your API. See Upstream authentication. |
upstream.extra_headers | Optional static headers sent on every upstream call. Do not put secrets here; values are stored as plaintext. |
upstream.protocol | Optional. rest, named-jsonrpc, positioned-jsonrpc, mcp-streamable-http, or mcp-http-sse. The two MCP values name an upstream server that already speaks MCP, and each one names the transport that reaches it. Normally, omit this and let Bazantic detect it from the spec. |
default_price | Required. The price for any method without its own price. |
methods | Required. An array of endpoints, or the literal string unmanaged. See below. |
status | active, paused, or retired. retired soft-deletes the gateway. Export can also write draft, but apply drops a draft value and does not write it. |
environments | Per-environment overrides, keyed dev, pre, or prd. See below. |
payout | Optional top-level field for an organization account. It pins every gateway in the file to a non-default payout account by UUID. Omit it to use the account default. |
Unknown fields fail validation. This catches misspellings instead of silently ignoring them.
Redirects
Point upstream.url at the host that answers your calls. Do not point it at a host that
redirects to that host.
Many sites answer the bare apex with a redirect to the www host. A GET survives this
redirect. The gateway follows the redirect, and your API answers. Each call then costs one
extra round trip.
A POST does not survive the redirect. The request body is lost, and the gateway charges the payer:
| Redirect answer | What your API receives | What the caller receives |
|---|---|---|
| 301, 302, 303 | a GET, with no body | the answer of your API to the wrong request |
| 307, 308 | nothing. The gateway makes no call. | the raw 307 or 308 |
A 307 or a 308 looks like the safe pair. Both codes keep the method. The gateway still does not follow them. The gateway sends the body of the caller one time. The gateway cannot rewind that body for a second send. Therefore the gateway returns the redirect to the caller.
Check the exact URL before you apply the file:
curl -sS -o /dev/null -w '%{http_code} %{redirect_url}\n' https://api.example.comA 200 means the host answers. Any 3xx prints the host to use instead. Put that host in
upstream.url.
Prices
All prices are USDC. Write them in any of three forms:
- Dollars:
$0.0025 - Cents:
0.25¢ - Integer millicents:
1000(= 1¢)
The minimum granularity is $0.00001 (1 millicent). 0 is valid and makes the call free.
Methods
The method list is the allow-list: the gateway serves what the file prices, and nothing else. One entry is one endpoint.
methods:
- verb: GET
path: /v1/current # REST: verb + path
- method: eth_getLogs # JSON-RPC: method name (the verb is always POST)
price: $0.002 # overrides default_price for this entryapply replaces the method set as a whole. Entries in the file are written, and
live methods absent from the file are removed.
An empty array clears every method on a draft or paused gateway. A new gateway with an empty method list is created as a draft and does not serve traffic.
An active gateway always keeps at least one live method. apply refuses an
empty array on an active gateway, and makes no write.
Write methods: unmanaged when the file must not manage methods at all. apply
then leaves the live methods untouched, and plan reports no method drift for
that gateway.
Do not use unmanaged to create a gateway. It is only useful when the gateway already has
live methods that another workflow owns.
Upstream authentication
upstream.auth describes how Bazantic authenticates to your API. It does not configure how
customers pay Bazantic.
type | Required fields | Use when |
|---|---|---|
none | None beyond type | The upstream is public. |
api-key | secret; also header_name for header or query delivery | Your API expects a key in a header, bearer token, query parameter, or {apikey} URL placeholder. |
basic | username; secret is the optional password | Your API uses HTTP Basic authentication. |
For delivery: header, header_name is the header name. For delivery: query, it is the
query parameter name. delivery: bearer sends the secret as a bearer token.
The manifest does not model OAuth 2.0. Create an OAuth 2.0 gateway in the dashboard, or with
baz gateway add --auth-type oauth2.
Static extra_headers are different: they are stored as plaintext and forwarded on every
request. Use them only for non-secret values such as an API version:
upstream:
url: https://api.weather.example
extra_headers:
Accept-Version: "2026-09-01"Secrets
A secret is always a ${ENV} reference, never an inline value:
auth:
type: api-key
delivery: header
header_name: X-API-Key
secret: ${ACME_API_KEY}The reference resolves from your environment at apply time. The value travels over
TLS, is encrypted at the API, and is never logged. validate fails on an unset
variable before anything is written.
Write secret references in block style, as above. In a flow map ({ … }) a bare
${ is a YAML parse error, so quote it there: { secret: "${ACME_API_KEY}" }.
Do not commit a .env file or replace the reference with a real credential.
Environments
environments holds sparse overrides, deep-merged onto the gateway's base fields.
The key must equal the --env value you pass at apply time.
environments:
pre:
upstream:
url: https://sandbox.api.weather.example
auth:
secret: ${ACME_SANDBOX_KEY}
prd: {} # uses the base as-isThe CLI workflow
baz login
baz gateway init --from-spec https://api.weather.example/openapi.json
# edit bazantic.yaml — prices, listing copy, handle
baz gateway validate
baz gateway plan --env prd
baz gateway apply --env prd| Command | What it does |
|---|---|
init --from-spec <url> | Reads your API document and scaffolds a bazantic.yaml. Writes nothing to Bazantic. Needs baz login, because discovery runs server-side. |
validate | Schema check plus secret-reference lint. No writes, no network. |
plan [--env <e>] | Shows the create / update / retire diff against your live gateways. Exits 2 on drift, which makes it a CI check. |
apply [--env <e>] | Reconciles the file into your account. Returns once the writes land; the gateway serves the change within about 30 seconds. |
export [--env <e>] | Regenerates a manifest from your live gateways. Secrets come out as ${ENV} placeholders, never as values. |
history <handle> | The audit trail: who changed what, and when. |
Example files
The repository includes proposed manifests for these common shapes:
bazantic.minimal.yaml— public REST API with one default price.bazantic.full.yaml— header API key, per-method pricing, and environment overrides.bazantic.query-auth.yaml— API key delivered as a query parameter.bazantic.openrpc.yaml— OpenRPC API with explicit JSON-RPC methods.
Each file lives in docs/specs/examples
and points editors at the draft JSON Schema. See the directory's README before copying one.
All names, URLs, and credential references in these files are fictional.