> Part of the API Mercado docs, in beta. Markdown for every page: append `index.md` to its URL. Site map: /llms.txt # For agents This page is the reference an agent reads first. Every page on this site is also markdown: append `index.md` to its URL, or send `Accept: text/markdown`. The site map is [/llms.txt](/llms.txt), and [/llms-full.txt](/llms-full.txt) holds every page in one file. ## Find an API Search the catalog with a goal or keywords: ``` GET https://apimercado.com/discover/llms.txt?q= ``` The answer is markdown, best match first. Words are OR-ed and ranked, so describe the goal and try two or three variants. Every public API is also listed in the catalog's own [llms.txt](https://apimercado.com/llms.txt). ## Read an API Each API page has two machine-readable twins, both readable without a Key: | URL | What it is | | ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | | `https://apimercado.com/discover///llms.txt` | The setup guide: gateway base URL, pricing, how to get a Key, a typed client, every endpoint. | | `https://apimercado.com/discover///openapi.json` | The OpenAPI document as consumers see it, with the gateway as its server. | ## MCP server The catalog is also a remote MCP server, read-only and without sign-in, over Streamable HTTP: ``` https://apimercado.com/mcp ``` To add it to Claude Code: ```sh claude mcp add --transport http apimercado https://apimercado.com/mcp ``` In Claude.ai or Claude Desktop, add the URL as a custom connector under Settings > Connectors. | Tool | Returns | | ---------------------------------- | --------------------------------------------------------------------- | | `search_apis({ q, category? })` | Catalog search results, the same markdown as `/discover/llms.txt?q=`. | | `get_api_guide({ provider, api })` | An API's setup guide, the same markdown as its `llms.txt`. | | `get_openapi({ provider, api })` | An API's OpenAPI document as JSON, with the gateway as its server. | `provider` and `api` are the two slugs in a result's link, `/discover//`. An unknown API returns a tool error. Calling an API still needs a Key, as described below. Tool names are stable: renaming one is a breaking change in the [Changelog](/changelog/). ## Call an API Every call goes through the gateway with a Key in the `X-API-Key` header: ``` curl -H "X-API-Key: $APIMERCADO_API_KEY" "https://eu-north-1.apimercado.com/v1/@//" ``` - A Key starts with `mk_live_` and needs a human: an org admin enables the API on its page and creates the Key there, or on the Keys page. - Keys stay server-side, in an environment variable. A Key spends its organization's balance, so it never belongs in a browser, a repository or a prompt. A Spend cap on the Key bounds what it can spend in a Month. - Response headers report what each call cost (`X-Mercado-Cost-Micros`, in micro-dollars) and the balance left. See [Response headers](/billing-and-keys/#response-headers). - To bound what one call may cost, send `X-Mercado-Max-Cost-Micros` (an integer in micro-dollars, proxy fee included). When the called operation's price cap plus the proxy fee is above it, the gateway answers `402 max_cost_exceeded` before the provider is called and charges nothing; otherwise the provider receives the value and can scale the work to it. See [Max cost](/billing-and-keys/#max-cost). ### TypeScript client `@apimercado/client` generates types from an API's OpenAPI document and wraps the gateway URL, the Key header and the error shape: ```sh npm install @apimercado/client npx @apimercado/client generate @/ -o .d.ts ``` `npx @apimercado/client check .d.ts` exits 1 when the provider has changed the spec since the file was generated. For any other language, point an OpenAPI generator at the API's `openapi.json`. The same package sets a [Max cost](https://docs.apimercado.com/billing-and-keys/#max-cost) on every call (`maxCostMicros`), reads the billing headers (`readCost`), types the balance and request lookup (`createAccountClient`), and, for providers, the [Provider API](https://docs.apimercado.com/publish-an-api/#6-provider-api) (`createProviderClient`). ## Errors Errors the gateway generates share one envelope: ```json { "error": { "code": "balance_exhausted", "message": "The organization balance is exhausted.", "resets_at": "2026-11-01T00:00:00.000Z", "docs": "https://docs.apimercado.com/billing-and-keys/#balance_exhausted" } } ``` Branch on `code`, never on `message`. `docs` links to that code's section under [Error codes](/billing-and-keys/#error-codes), which says what caused it and what to do. Errors from the provider's own API pass through unchanged. ## Provider API A provider's servers and CI use the Provider API to work with their own APIs without a portal login. It lives at `https://admin-api.apimercado.com` under `/v1/provider/*`: | Operation | What it does | | ----------------------------------------------- | ---------------------------------------------- | | `GET /v1/provider/whoami` | Checks a key: its id, organization and scopes. | | `POST /v1/provider/apis/{apiId}/refresh` | Re-reads an API's spec from its URL now. | | `POST /v1/provider/requests/{requestId}/settle` | Sets the final price of a deferred request. | | `GET /v1/provider/requests/{requestId}` | Returns a deferred request's hold and status. | Authenticate with a provider API key, `Authorization: Bearer mpk_...`. An org admin creates it under Settings > Provider API; it is shown once. It cannot call APIs or sign in to the portal. Its errors are `{ "error": ": " }`. The details are in [Provider API](/publish-an-api/#6-provider-api). To get an API ready to publish, read [Publish an API](/publish-an-api/). ## Watch for breaking changes API Mercado is in beta: features and fees may change. Every Release is listed in the [Changelog](/changelog/), newest first, and changes that need action are under a "Breaking changes" heading in that Release's entry. To watch it, fetch `https://docs.apimercado.com/changelog/index.md` now and then and look for that heading in entries newer than the last one you read. # Billing and keys Everything a developer needs to call paid APIs on API Mercado: how to authenticate, what each call costs, how balances, holds and spend caps work, and how to read every error the gateway can return. ## Authenticating requests Every request carries a Key in the `X-API-Key` header: ``` curl -H "X-API-Key: mk_live_…" "https://eu-north-1.apimercado.com/v1/@//" ``` Get a Key from any API's page: enable the API, then press **Create key** in the dialog that follows. The Keys page lists every Key and mints ones scoped to several APIs or capped per Month. Keys are shown once at creation. Keep them server-side; a leaked Key spends your balance. Revoke and re-create from the Keys page. There is no rotation window and no expiry. ### Keyless operations A few operations need no Key: those an API's provider made keyless (marked `security: []` in its published spec), and every API's health check path. They are free and not metered, so a browser can call them directly, and the gateway allows 60 of them per minute per IP address and API (`keyless_rate_limited` beyond that). A Key sent to one is removed and ignored, and the provider does not see who called. ### Test requests from an API page An org admin can send a test request from any API page their organization has enabled ("Try it"). The marketplace sends it through the gateway with your organization's **Portal test key**, which it creates on the first test and lists on the Keys page. A test request is billed exactly like any other call, from the same balance, and shows up in your requests and spend. You can give the Portal test key a Spend cap or revoke it; the next test creates a new one. Test requests are limited to 10 per minute per organization. ### TypeScript client `@apimercado/client` wraps [openapi-fetch](https://openapi-ts.dev/openapi-fetch/) with the gateway URL, the Key header and the gateway error shape. Every API page shows the one-liner that generates its types; it fetches the API's OpenAPI spec from the gateway and writes a `.d.ts` file you commit: ```sh npm install @apimercado/client npx @apimercado/client generate @/ -o .d.ts ``` ```ts import { createApimercadoClient } from "@apimercado/client"; import type { paths } from "./"; const api = createApimercadoClient({ provider: "@", api: "", apiKey: "mk_live_...", }); const { data, error } = await api.GET("/", { params: { query: { ... } } }); ``` Providers can publish new versions and the gateway always serves the current one. The generated file records the spec hash it was built from, so `npx @apimercado/client check .d.ts` exits 1 in CI when the spec changed; regenerate and let the compiler point at the calls that no longer match. The client also sets [Max cost](#max-cost) for you (`maxCostMicros`), reads every [response header](#response-headers) (`readCost`), and types the [balance endpoint](#the-balance-endpoint) and the [request lookup](#the-request-lookup) (`createAccountClient`). ## Base URL shape All API traffic goes through the marketplace gateway: ``` https://eu-north-1.apimercado.com/v1/@//… ``` `@` is the provider organization's slug, the same name as in the marketplace URL `https://apimercado.com/discover//`. The provider's public id (shown in small print at the bottom of every API page) works in its place, `/v1///…`, so URLs copied before slugs existed keep working. Every API page also has a markdown twin at `/llms.txt` with this whole setup written for a coding agent. The same gateway hosts two platform endpoints under the reserved public id `account`: ``` GET https://eu-north-1.apimercado.com/v1/account/balance GET https://eu-north-1.apimercado.com/v1/account/requests/{requestId} ``` They are authenticated with any of your org's Keys, exactly like an API call, and are never charged. ## The balance endpoint `GET /v1/account/balance` returns your organization's current billing state. All money fields are integer micro-dollars (1,000,000 = $1.00) with the unit in the field name: ```json { "monthly_balance_micros": 412000, "topup_balance_micros": 12500000, "available_balance_micros": 12912000, "month_resets_at": "2026-10-01T00:00:00.000Z", "key_spend_micros": 750000, "key_spend_cap_micros": 5000000, "next_expiring_lot": { "amount_micros": 12500000, "expires_at": "2028-03-01T00:00:00.000Z" } } ``` - `monthly_balance_micros`: what remains of this Month's Free buffer. - `topup_balance_micros`: what remains of your purchased Top-up balance. - `available_balance_micros`: the two combined; a request is denied when it would cost more than this. - `month_resets_at`: when the Monthly balance resets (the 1st of next Month, UTC). - `key_spend_micros`: what the calling Key has spent this Month. - `key_spend_cap_micros`: the calling Key's Spend cap, or `null` when unlimited. - `next_expiring_lot`: the soonest-expiring Top-up Lot with its remaining amount, or `null` when nothing is left to expire. ## Response headers | Header | On | Value | | -------------------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | | `X-Mercado-Request-Id` | every response to an API call, including the gateway's 400, 402, 403, 429 and 503 denials | The request's id. Use it for the [request lookup](#the-request-lookup) and in support questions. | | `X-Mercado-Cost-Micros` | every served response | The Cost of that request, so far. On a call to your own API it is the full Cost, though only the proxy fee was deducted. | | `X-Mercado-Fee-Micros` | every served response | The proxy fee part of that Cost. | | `X-Mercado-Charge` | calls to an API your own organization publishes | `internal`: the call is priced in full, but only the proxy fee is deducted. | | `X-Mercado-Balance-Micros` | every served response | Your Available balance after what was deducted. | | `X-Mercado-Resets-At` | every served response | When the Monthly balance resets. | | `X-Mercado-Settlement` | operations settled later | `pending`: the price comes later (see [Holds](#holds)). `instant`: charged in full now. | | `X-Mercado-Hold-Micros` | with `X-Mercado-Settlement: pending` | What is held until the provider settles. | The only response without `X-Mercado-Request-Id` is the gateway's static 403 for an unknown or revoked Key (see `api_not_enabled`). A rate-limited request returns `429` with a `Retry-After` header. The [TypeScript client](#typescript-client) reads all of them with `readCost(response)`. ## What is charged You pay the request's **Cost**: the API's Price plus a fixed proxy fee per request. Every price on the Marketplace is the provider's Price alone, marked "+ proxy fee", so an API with a $0 Price shows as Free; the enable dialog spells the fee out. Providers may vary the Price per request up to the price cap shown on the API page, so check `X-Mercado-Cost-Micros` rather than assuming a list Price. Calls to an API your own organization publishes are priced like any other call, but only the proxy fee is deducted: their response headers report the full Cost and carry `X-Mercado-Charge: internal`. To bound what a single call may cost, see [Max cost](#max-cost). Topping up costs a separate percentage fee, added on top of the amount you buy and shown on your Stripe invoice. The current figures (the proxy fee, the top-up fee, the Free buffer, the smallest top-up and how long purchased dollars last) are on the [fees overview](https://apimercado.com/distribute#fees). Signed in, your organization's own figures are on its [Billing page](https://apimercado.com/dashboard/billing). A request is charged when the upstream API answers with a 2xx or 4xx status, except 401, 403, and 429: those mean the provider's upstream rejected or throttled the gateway itself, so you are not charged for them. Upstream 5xx responses, timeouts, and every gateway denial are never charged. Your Key never leaves the gateway. The `X-API-Key` header is removed before the request is forwarded, and the provider identifies you only by the `X-Mercado-Consumer-Id` and `X-Mercado-Key-Id` headers. APIs with a $0 Price still require a Key and Access, and are rate-limited and logged. They earn the Provider nothing, and cost you only the per-request proxy fee. ## Prices and price changes An API page shows what its requests actually cost: the 5th to 95th percentile of the charged Price over the last 30 days, refreshed every 5 minutes, for example "$0.0004 to $0.0012 per request, up to $0.002". Until an API has 20 charged requests in that window it shows "Up to $0.002 per request". The cap, the most one request can cost, is always shown. Operations with their own pricing show their own range and cap in the endpoint list. When a provider raises a price or a cap, every organization with the API enabled gets an email, and the API page shows "Price raised on " or "Price cap raised on " for 30 days. A provider turning off the Free buffer for its API emails you too. Lowerings send nothing. Some APIs need a Top-up balance: their page says so. Your Free buffer pays only the proxy fee on them, so their free operations keep working without a top-up (see `topup_required`). An operation marked "Not available yet" is priced by a provider that cannot charge for calls yet. Calls to it are refused with `paid_pricing_unavailable` and cost nothing; the API's free operations work as usual. ## Max cost To bound what one call may cost you, proxy fee included, send `X-Mercado-Max-Cost-Micros` with the request: ``` curl -H "X-API-Key: mk_live_…" -H "X-Mercado-Max-Cost-Micros: 20000" "https://eu-north-1.apimercado.com/v1/@//" ``` - The gateway compares it with the most the call can cost: the called operation's price cap plus the proxy fee. When that is above your value, the call is refused with `402 max_cost_exceeded` before the provider is called, and nothing is held or charged. Set it against the cap shown on the API page, not against what calls usually cost. - An allowed call reaches the provider with the header unchanged, so it can scale the work to your Max cost. You are still charged at most the operation's cap plus the proxy fee. - The value is a whole number of micro-dollars, digits only. Anything else (a sign, a decimal point, spaces, an empty value, a number too large for a 64-bit integer) is ignored and not forwarded, as if you had sent none. - It applies to calls to your own organization's APIs too, checked against the full Cost. Keyless operations ignore it and do not forward it. The [TypeScript client](#typescript-client) sends it on every call when created with `maxCostMicros`. ## Balances: Free buffer and Month reset Spend draws from two pools, Monthly first: 1. **Monthly balance**: the Free buffer every organization gets each Month (see [What is charged](#what-is-charged) for the amount). It is a trial the Marketplace funds, so Spend from it earns the Provider nothing. What you do not spend does not carry over: the balance resets on the 1st of each Month at 00:00 UTC. 2. **Top-up balance**: prepaid dollars you purchase. It never resets, and is spent only after the Monthly balance is exhausted. ## Holds Before a request reaches the provider, the gateway holds the most it can cost: the called operation's price cap plus the proxy fee. Requests in flight at the same time cannot spend the same dollars, and a request is never half-paid. The hold ends when the response is charged, after at most 60 seconds. Some operations are **settled later**: the provider only knows the price once the work is done (a video render, a transcript). The API's spec declares them, and they work differently: 1. The gateway holds the operation's cap from your Top-up balance, minus your other open holds. The Free buffer never funds this hold. Without enough Top-up the request is denied with `topup_required` before the provider is called. 2. The response carries `X-Mercado-Settlement: pending` and `X-Mercado-Hold-Micros`. You pay the proxy fee now (`X-Mercado-Cost-Micros`). 3. The provider settles the request once, for 0 up to the hold. You pay the settled amount from Top-up and the rest is released. A hold the provider never settles is released after 48 hours. The proxy fee is not returned when a hold is released. Open holds count toward the Key's Spend cap, and a settled amount counts toward the Month the request was made in. A provider may answer such a request with `X-Mercado-Settlement: instant` (a cached result, a rejected input): it is then charged in full at once, like any other request. Example: an operation with a $0.25 cap. The submit holds `250000` micro-dollars and costs the proxy fee. The provider settles `182000`: you pay $0.182 and the other $0.068 is released. ## The request lookup `GET /v1/account/requests/{requestId}` returns one request of your organization by its `X-Mercado-Request-Id`. It is free and authenticated with any of your org's Keys: ``` curl -H "X-API-Key: mk_live_…" "https://eu-north-1.apimercado.com/v1/account/requests/4f1c2b9e-0d7a-4b8e-9a51-2f3c6d7e8a90" ``` ```json { "request_id": "4f1c2b9e-0d7a-4b8e-9a51-2f3c6d7e8a90", "status": "pending", "price_micros": 0, "fee_micros": 100, "cost_micros": 100, "raw_cost_micros": 100, "hold_micros": 250000, "internal": false } ``` The amounts in this example are illustrative; `fee_micros` is the proxy fee in force when the request was made. | `status` | Meaning | | ------------- | ------------------------------------------------------------------------------------------------------------ | | `charged` | Charged in full when the response came back. | | `pending` | Settled later: the proxy fee is charged, `hold_micros` is held until the provider settles. | | `settled` | The provider settled: `price_micros` is the settled amount, `cost_micros` adds the proxy fee. | | `released` | The hold was released without a price (a $0 settle or 48 hours without one). Only the proxy fee was charged. | | `not_charged` | Denied by the gateway or not charged (upstream 5xx, 401, 403 or 429). All amounts are 0. | - `price_micros`, `fee_micros`, `cost_micros`: what the request charged. On a call to an API your own organization publishes they are the full amounts, though only the proxy fee was deducted. - `raw_cost_micros`: deprecated, always equal to `cost_micros`. Read `cost_micros` instead; this field will be removed. - `hold_micros`: what is held now; 0 unless `pending`. - `internal`: `true` on a call to an API your own organization publishes. A request settled later is read from its hold record, and is final once `settled` or `released`. Any other request is read from the request log: it appears a few seconds after its response and is kept 90 days. A request id of another organization answers like an unknown one (`request_not_found`). ## Spend caps Each Key can carry an optional monthly Spend cap. When the Key's own Spend this Month reaches its cap, only that Key is denied; your other Keys keep working until the org balance runs out. An unset cap means unlimited (bounded by the org balance). ## Expiry Top-up dollars arrive in Lots, and each Lot expires a fixed number of months after it lands (see [What is charged](#what-is-charged) for how many). Spend consumes the soonest-expiring Lot first, so nothing goes stale while a later Lot could be spent. The balance endpoint's `next_expiring_lot` shows what expires next; expired amounts simply leave the Top-up balance. ## Error codes Gateway-generated errors share one body shape: ```json { "error": { "code": "balance_exhausted", "message": "The organization balance is exhausted.", "resets_at": "2026-10-01T00:00:00.000Z", "docs": "https://docs.apimercado.com/billing-and-keys/#balance_exhausted" } } ``` `resets_at` is the next Month reset (the 1st of next Month, 00:00 UTC). Every denial the billing gateway generates carries it, even `org_suspended`, `api_not_enabled`, and `billing_state_unavailable`, which are not really about the Month reset, so a client can always say when the error state may change. It is `null` only on the gateway's static 403 from its own key authentication (see `api_not_enabled`) and on the account endpoints' own `key_not_authorized` and `request_not_found`. `docs` links to the anchor below. ### key_not_authorized `401`: returned only by the account endpoints themselves, when the caller identity the gateway forwarded does not check out: the request bypassed the gateway, or the Key's platform metadata is stale. This is not what a revoked Key sees in normal use: the gateway rejects a revoked or unknown Key first, with `api_not_enabled` below. ### request_not_found `404`: the request lookup found no request with this id in your organization. The id may be mistyped, belong to another organization, or be older than 90 days. A request charged in full appears a few seconds after its response, so retry a just-made one shortly. ### api_not_enabled `403`: the Key has no Access to this API. Enable the API for your organization, or widen the Key's Scope, and retry. A revoked or unknown Key gets this same code: the gateway's own authentication rejects it before any billing check runs, answering HTTP 403 with a static body whose `resets_at` is `null`. Revoked Keys are gone for good: mint a new Key on the Keys page. ### org_suspended `403`: the organization is suspended. All Keys are denied until the suspension is lifted; contact support. ### balance_exhausted `402`: the Available balance (Monthly plus Top-up, minus your open holds) cannot cover the most the request can cost, which is the called operation's price cap plus the proxy fee. The check runs before the call reaches the provider, so a request is never half-paid. Top up, or wait for the Month reset in `resets_at`. ### topup_required `402`: the Price of this request must be paid from purchased dollars, and your Top-up balance (minus your open holds) cannot cover its price cap. This happens on an API whose provider asks for it (its page says calls need a topped-up balance) and on every operation settled later (see [Holds](#holds)). Your Free buffer still pays the proxy fee, so an API's free operations keep working. Top up and retry. ### key_spend_cap_reached `402`: this Key reached its monthly Spend cap, or has too little room under it for the hold an operation settled later needs. Raise the cap, use another Key, or wait for the Month reset in `resets_at`. ### max_cost_exceeded `402`: the most this call can cost, the called operation's price cap plus the proxy fee, is above the `X-Mercado-Max-Cost-Micros` you sent (see [Max cost](#max-cost)). The provider was not called, and nothing was held or charged. Raise the header, or leave it out, and retry. ### paid_pricing_unavailable `503`: the called operation is priced, and its provider cannot charge for calls yet (the API page marks it "Not available yet"). The provider was not called, and nothing was held or charged. The API's operations without a price still work. Retrying the same operation gets the same answer until the provider can charge. ### billing_state_unavailable `503`: the billing system could not read your balance or the API's pricing, so the gateway failed closed. Nothing was charged. Retry shortly. ### path_not_routable `400`: the gateway cannot tell which operation this path calls, so it cannot price it. This happens on APIs that price operations in their spec, when a path segment holds an encoded slash (`%2F`) or a backslash, or when the path is not under the API's base URL. Nothing was charged, and retrying the same URL gets the same answer: fix the URL. ### keyless_rate_limited `429`: too many calls to an API's keyless operations (see Keyless operations) from one IP address within a minute. Wait for the next minute and retry. ## Disputes Charged incorrectly? From your request log, an org admin can report any charged or settled request within 30 days of the request, with a description of what went wrong. A resolved refund returns the full Cost (for a settled request, the settled amount plus the proxy fee) to your Top-up balance and shows up in your balance history; the provider is deducted the Price portion and the platform forgoes its fee. ### request_not_settled A `pending` request cannot be disputed yet: it has no price. Report it once the provider settles it, or wait for its release. ### request_released A `released` request cannot be disputed: it charged only the proxy fee, which a release never returns, so there is nothing to refund. # Publish an API How to get an existing HTTP API ready to sell on API Mercado. It is written so you can hand it to a coding agent working in your API's repository: each section says what to change in the code and what to set in the portal. ## How a request flows A consumer calls the gateway with their Key: ``` https://eu-north-1.apimercado.com/v1/@// ``` The gateway checks their balance and holds the most the request can cost, strips their `X-API-Key`, adds your upstream credential and the platform headers, and forwards the request to your upstream base URL plus ``. When your response comes back, the gateway charges the consumer, removes your pricing headers, and returns the response with their Cost attached. You never handle keys, billing, or rate limits yourself. ## 1. Publish an OpenAPI spec at a URL The spec is imported from a URL, never pasted, and fetched again every hour. - OpenAPI 3.x, in JSON or YAML, at most 1 MB. - `info.version` is required. When it changes, the new version is released automatically, so bump it whenever the API changes. - `servers[0].url` suggests the upstream base URL: the origin the gateway forwards requests to. Server variables take their `default`, and a relative URL such as `/v1` is resolved against the spec URL. With no `servers`, the suggestion is the spec URL's own host. Consumers never see it: the published spec shows the gateway URL instead, and your own security schemes are removed, since consumers authenticate with their Key. - The URL must be publicly reachable over http or https. Addresses on private networks, loopback, and link-local ranges are rejected, for both the spec URL and the upstream base URL. Most frameworks can serve a generated spec (for example `/openapi.json`). Serve it from the same deployment as the API so it never drifts from the code. Creating the API in the portal starts from this URL. **New API** asks for the spec URL first and reads it straight away, so a spec that cannot be fetched or is not valid OpenAPI is reported before anything is created. The next step is prefilled from the spec: the name from `info.title`, the slug from the title, the description from `info.description`, and the upstream base URL as above. Check each one, change what is wrong (the slug is permanent), and create the API. It opens with the spec already loaded. The `@` segment is your organization's slug, set under Settings > General. Pick it before you publish: once any of your APIs has left Disabled, it is locked, because it is part of every consumer's gateway URL. ## 2. Accept only gateway traffic In the portal, open your API's Authorization tab and add the credential the gateway should send to your upstream: an API key header, a bearer token, basic auth, or a custom header. It is encrypted at rest and never shown to consumers. In your code, reject any request that does not carry that credential. Answer `401` or `403`: consumers are never charged for those statuses, so a misconfigured credential cannot bill anyone. The gateway also sends these headers on every request: | Header | Meaning | | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `X-Mercado-Key-Id` | The consumer's Key the request was made with. | | `X-Mercado-Consumer-Id` | The consumer organization. Use it for per-customer state. | | `X-Mercado-Consumer-Name` | The consumer organization's display name. | | `X-Mercado-Request-Id` | A per-request id. The consumer gets the same id on the response. Log it, and store it on deferred work: it is the id you [settle](#settle-and-read-a-request) with. | When the consumer set a Max cost for the call, the request also carries `X-Mercado-Max-Cost-Micros`, unchanged: the most they agreed to pay for it, the proxy fee included. The gateway has already checked that your operation's cap plus the fee fits under it, so you never need to refuse on it, but you can use it to scale the work (fewer results, a shorter output). It is absent when the consumer sent none or an invalid value. Trust them only on requests that passed your credential check. ## 3. Add a health endpoint Publishing requires a passing health check. Add a cheap endpoint (for example `GET /health`) that answers a fixed status without calling paid dependencies. In Settings you choose the path, the method (GET, HEAD, or POST), the expected status code, and a timeout between 500 and 30,000 ms. The gateway also serves that exact path without a Key, free (GET and HEAD for a GET or HEAD check, otherwise only the chosen method), so anyone can monitor your API through it; it need not appear in your spec. The marketplace's own probe calls your upstream base URL directly, without your credential, so keep the endpoint open in your code. ### Keyless operations To let callers reach an operation without a Key (for example a link token that is its own credential, called from a browser), declare `security: []` on that operation in your spec. Once that spec is released, the operation is listed in the Keyless operations card of Settings (Spec section): tick it and save to serve it keyless. Until you do, it needs a Key like any other. Keyless calls are free: nothing is charged and you earn nothing for them. They are limited to 60 per minute per caller IP. The gateway still sends your upstream credential, but `X-Mercado-Key-Id` and the `X-Mercado-Consumer-*` headers are empty, so authenticate the caller yourself. A `security: []` at the top level of the spec is ignored. ## 4. Pricing All amounts are integer micro-dollars: 1,000,000 micro-dollars = $1.00, so `1500` is $0.0015. Prices live in your spec, one operation at a time. There is no price to type in the portal: your API's Settings show what the live spec declares, and **Accept Free buffer** (see [Free buffer toggle](#free-buffer-toggle)) is the only pricing choice made there. To change a price, change the spec and bump `info.version`. Consumers pay the price plus a fixed proxy fee per request (the current amount is on the [fees overview](https://apimercado.com/distribute#fees)). You receive the price in full. Your API page shows your price alone, marked "+ proxy fee", so a $0 price shows as Free. Which responses are charged is explained in [What is charged](/billing-and-keys/#what-is-charged). Calls your own organization makes to your API are priced and reported like any other call, but only the proxy fee is deducted, and they earn you nothing. Before forwarding a request, the gateway checks that the consumer can pay the operation's cap plus the proxy fee, and holds that amount. A request is never forwarded on money the consumer does not have. ### Two levels The price of a request comes from two levels; the cap comes from the spec alone: | Level | Price (what is charged) | Cap (what the gate checks and holds) | | ----------------------- | ------------------------ | ------------------------------------ | | 1. Your response header | `X-Mercado-Price-Micros` | none: a response cannot change it | | 2. The spec operation | `x-mercado-price-micros` | `x-mercado-max-price-micros` | - A price header on your response sets the price of that one request; without one, the price the spec declares applies. - The charged price is clamped to the cap. A price above it charges the cap. - The gate holds the declared cap before your server is called, so no response changes the cap. A deferred request always holds the declared cap; to charge less, settle less. What an operation's extensions come to: | The spec operation declares | Price | Cap | | ---------------------------------- | ----------------------- | --------- | | a price and a cap | the price | the cap | | a price only | the price | the price | | a cap only | $0 base | the cap | | nothing, or no operation matches | $0 (the proxy fee only) | 0 | | keyless operation (`security: []`) | never charged | none | A price declared alone is also the cap, so a price header can lower it but never raise it. An operation with nothing declared has a cap of 0, so a price header on it charges nothing: declare a cap on every operation whose code sends one. ### Pricing in the spec Price an operation by adding these extensions to it in your spec: | Extension | Value | Effect | | ---------------------------- | -------------------- | --------------------------------------------------------------------------------------------------------- | | `x-mercado-price-micros` | non-negative integer | The operation's price. | | `x-mercado-max-price-micros` | non-negative integer | The operation's cap. `0` makes the operation cost only the proxy fee. | | `x-mercado-settlement` | `deferred` | The price is set after the response, by a settle call. See [Deferred settlement](#5-deferred-settlement). | ```yaml paths: /search: get: x-mercado-price-micros: 1000 x-mercado-max-price-micros: 10000 /videos: post: x-mercado-settlement: deferred x-mercado-max-price-micros: 250000 /jobs/{jobId}: get: x-mercado-max-price-micros: 0 ``` The import checks the extensions. Errors block the import (the spec is reported as `pricing_invalid`); warnings let it through and come back with the import result: | Finding | Kind | | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | | A price or cap that is not a non-negative integer (`1500.5`, `"1500"`, `-1`) | error | | A price or cap above 1,000,000,000 micro-dollars ($1,000) | error | | `x-mercado-settlement` with any value other than `deferred` | error | | `x-mercado-settlement: deferred` without an `x-mercado-max-price-micros` above 0: the hold would be 0, so every settle would fail | error | | A price above the cap declared on the same operation | error | | Extensions on a keyless operation (`security: []`): it is never charged, so they are ignored | warning | | A path segment that mixes a `{param}` with text, such as `/files/{id}.json`: the gateway never matches it, so calls to it are charged the proxy fee only | warning | A version that passes is released automatically, prices included (see [Price changes](#price-changes)), so these checks are what stands between a typo and your consumers. ### How a request finds its operation The gateway takes the path after `/v1/@/` and matches it, with the method, against the path templates of your released spec: - Whole segments only. A `{param}` segment matches any one segment; a literal segment matches the same text, compared with exact case first, then ignoring case. - When several templates match, the first segment where one is literal and the other a `{param}` decides, and the literal wins: `GET /jobs/latest` matches `/jobs/latest` before `/jobs/{jobId}`. - A `HEAD` request uses the `GET` operation when the spec declares no `HEAD`. - Segments are percent-decoded, empty segments and `.` are dropped, and `..` removes the segment before it, the way the gateway routes the request. - A request that matches no operation, or an operation without extensions, is charged the proxy fee only. - On an API whose spec declares pricing, a segment holding an encoded slash (`%2F`) or a backslash is refused with `400 path_not_routable`, because upstreams disagree on how to route it. So is a path outside the API's listen path. ### Charging a different amount per request When requests are not all worth the same (results returned, pages rendered, tokens generated), set headers on your **response**: | Response header | Effect | | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | `X-Mercado-Price-Micros` | The price of this one request, up to the operation's declared cap. | | `X-Mercado-Settlement: instant` | On a deferred operation: charge this request now and drop the hold. See [Deferred settlement](#5-deferred-settlement). | How the price header is read: | Your price header | What is charged | | -------------------------------- | -------------------------------------------- | | absent, empty, or not an integer | the price the spec declares ($0 without one) | | a negative number | $0 | | between 0 and the cap | exactly that amount | | above the cap | the cap | There is no response header for the cap: an `X-Mercado-Max-Price-Micros` on your response is removed and ignored. The gateway removes these headers before the response reaches the consumer, and adds `X-Mercado-Cost-Micros` with what they actually paid (your amount plus the proxy fee). It also removes any `X-Mercado-Cost-Micros`, `X-Mercado-Balance-Micros`, `X-Mercado-Hold-Micros` or similar money header you send, and replaces `X-Mercado-Request-Id` with its own. The headers only matter on responses that are charged at all. Rules for your code: - Send whole numbers only. `1500` works; `1500.5`, `$0.0015`, and `1.5e3` fall back to the declared price. - Compute it from the work the request actually did, after the work is done. - Raise the cap in the spec, and release it, before your code starts sending higher values, or they are silently capped. - If every request costs the same, do not send the header: declare only `x-mercado-price-micros`. > **Never copy request input into response headers.** If your server echoes > request headers back (some proxies and debug middlewares do), a caller can > send `X-Mercado-Price-Micros: 0` or `X-Mercado-Settlement: instant` and set > their own price. Example: $0.0005 per result returned, at least $0.001 and at most $0.01. The spec declares the floor as the price and the most as the cap, as `/search` above: ```yaml paths: /search: get: x-mercado-price-micros: 1000 x-mercado-max-price-micros: 10000 ``` Your code then sends the price of each request. Node (Express): ```js const PRICE_PER_RESULT_MICROS = 500; const MIN_PRICE_MICROS = 1000; app.get('/search', async (req, res) => { const results = await search(req.query.q); const price = Math.max(MIN_PRICE_MICROS, results.length * PRICE_PER_RESULT_MICROS); res.set('X-Mercado-Price-Micros', String(price)); res.json({ results }); }); ``` Hono: ```ts app.get('/search', async (c) => { const results = await search(c.req.query('q')); const price = Math.max(1000, results.length * 500); c.header('X-Mercado-Price-Micros', String(price)); return c.json({ results }); }); ``` Python (FastAPI): ```python @app.get("/search") async def search_route(q: str, response: Response): results = await search(q) price = max(1000, len(results) * 500) response.headers["X-Mercado-Price-Micros"] = str(price) return {"results": results} ``` Describe the pricing rule in your API's description or in each operation's description, so consumers know what a call will cost before they make it. ### Organizations that may not charge yet Paid pricing opens once provider payouts are live. Until then your spec imports and releases normally, prices included, but a priced operation (one with a cap above 0) is not available to consumers: a call to it gets `503 paid_pricing_unavailable` before your server is called, and nothing is charged or held. Operations without a price serve as usual, at the proxy fee only. Calls from your own organization, including the test call the publish checklist asks for, are still served at the proxy fee only. Your API page marks the priced operations "Not available yet", and the Pricing box in your API's Settings says why. When paid pricing opens for your organization, the prices your spec declares apply from the next call, without a price-raise email. ### Free buffer toggle Every consumer organization gets a Free buffer each Month (the current amount is on the [fees overview](https://apimercado.com/distribute#fees)). **Accept Free buffer** (Settings > Pricing, on by default) decides whether it may pay your Price: - **On**: consumers can try your API before they top up. Requests paid from the Free buffer earn you nothing. - **Off**: the Price of every call must come from the consumer's Top-up balance, so every charged request earns you the full Price. The proxy fee can still come from the Free buffer, so a $0 operation stays callable without topping up. A consumer whose Top-up balance cannot cover the price cap gets `402 topup_required`. Leave it on unless you have a reason: consumers are more willing to buy an API they could try first. Your own organization is never affected (it pays no Price). Deferred holds are always paid from Top-up, whatever the toggle says. ### Price changes A new spec version is released automatically, and its prices apply from the next call. Raising a price or a cap on a Public or Unlisted API emails every organization with your API enabled and shows "Price raised on " or "Price cap raised on " on your API page for 30 days. Turning off the Free buffer emails them too. Lowering sends nothing. Each operation is compared with its own previous declaration, or with the proxy fee alone when it had none, so putting a price on an existing operation that had none is a raise. A path that was not in the live spec is never a raise: it has no callers yet. Renaming a path makes it a new one. Consumers see the price range your API actually charged (5th to 95th percentile over 30 days, once there are 20 charged requests) and the cap. ### What you earn You earn the Price of every charged request once the consumer pays from purchased dollars. Requests paid from a consumer's monthly Free buffer are a trial funded by the Marketplace and earn nothing. A settled deferred request is always paid from Top-up, so it earns the settled amount in full. Calls from your own organization are priced and reported normally, pay only the proxy fee, and never earn. ## 5. Deferred settlement Some work only has a price once it is done: a video render, a transcript, an LLM job that runs longer than the [gateway's 30 seconds](#the-30-second-gateway-limit). Declare those operations `x-mercado-settlement: deferred`, with an `x-mercado-max-price-micros` above 0. The gate holds that cap, your server answers at once, and you settle the real price later. ### How it works 1. **Gate.** The gateway holds the operation's declared cap from the consumer's Top-up balance, minus their other open holds. The Free buffer never funds a hold. A consumer who cannot cover it gets `402` before your server is called, so you never start work nobody can pay for. 2. **Your response.** Answer quickly (for example `202` with a job id). A response the consumer is charged for (2xx or 4xx, except 401, 403 and 429) leaves the request **pending**: the consumer pays the proxy fee now and sees `X-Mercado-Settlement: pending` and `X-Mercado-Hold-Micros`. The hold is always the declared cap: no response header changes it, and a price header on a pending response is ignored. To charge less, settle less. 3. **Settle.** When the work ends, settle the request once with an amount from 0 up to the hold. The consumer pays that amount and the rest is released. Settle 0 for a job that failed. Other outcomes: | Response | Result | | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 5xx, 3xx, 401, 403, 429, or a gateway timeout | Not charged. The hold is released. | | Any charged status with `X-Mercado-Settlement: instant` | Charged now at the price header, else the price the spec declares, up to the hold. Nothing to settle. Use it for a cached result, a rejected input, or a repeat request for work already held. | | Any charged status without it | Pending until you settle. | A `400` for bad input is a charged status, so it stays pending unless you answer it with `X-Mercado-Settlement: instant` (add `X-Mercado-Price-Micros: 0` to charge only the proxy fee) or settle it for 0. Rules: - Settle once. Repeating the same amount returns the same response; a different amount is refused with `409`. There are no partial or repeated captures and no amounts above the hold. - A hold's `expiresAt` is 48 hours after the request. Settles close 5 minutes before it, and holds not settled by then are released: the consumer pays nothing beyond the proxy fee and you earn nothing. - The proxy fee is charged when the request is made and is never returned, whatever you settle. - The hold must be confirmed by your response within 60 seconds of the request. A response that reaches the gateway later holds nothing and can only be settled for 0. - Calls your own organization makes hold nothing beyond the proxy fee. You may settle them for any amount: the settled price is recorded in full on the request, marked internal, and nothing more is deducted. - In rare failures (the hold's record is lost before it is stored) the consumer pays only the proxy fee and your settle answers `404`. Settling needs a provider API key, see [Provider API](#6-provider-api). ### Settle and read a request Base URL: `https://admin-api.apimercado.com`. ``` POST /v1/provider/requests/{requestId}/settle Authorization: Bearer mpk_... Content-Type: application/json { "amountMicros": 182000 } ``` `requestId` is the `X-Mercado-Request-Id` the gateway sent with the request. `amountMicros` is an integer from 0 to the hold. Both endpoints answer the request's state: ```json { "requestId": "4f1c2b9e-0d7a-4b8e-9a51-2f3c6d7e8a90", "apiId": "b6a1e3f0-5c2d-4e8f-9b7a-1d2c3e4f5a6b", "operation": "POST /videos", "status": "settled", "heldMicros": 250000, "settledMicros": 182000, "expiresAt": "2026-10-31T09:12:44.000Z" } ``` ``` GET /v1/provider/requests/{requestId} ``` returns the same shape. `status` is `pending`, `settled` or `released`; `settledMicros` is `null` while pending and `0` once released. Errors are `{ "error": ": " }`: | Status | Code | Meaning | | ------ | ---------------------------------------------- | --------------------------------------------------------------------------------------- | | 400 | `validation_failed` | `amountMicros` is missing or not a non-negative integer. | | 400 | `settle_amount_exceeds_hold` | The amount is above the hold. The detail says the most you can settle. | | 401 | `missing bearer token`, `invalid provider key` | No key, or not a live key. | | 401 | `provider_key_revoked` | The key was revoked while the settle ran. | | 403 | `scope_required` | The key lacks the scope the endpoint needs. | | 403 | `ban` | Your organization is banned. | | 404 | `request_not_found` | No deferred request with this id on your APIs. | | 409 | `request_in_flight` | Your response is not recorded yet. Retry after a second. | | 409 | `request_already_settled` | Already settled for a different amount. The detail says which. | | 410 | `request_expired` | The hold expired (settles close 5 minutes before `expiresAt`). | | 410 | `request_released` | The hold was already released. A settle of 0 answers `200` instead. | | 429 | `rate_limited` | Over 600 calls a minute for your organization, or 1,200 from one IP. See `Retry-After`. | A settle is safe to retry with the same amount after a network error or a `5xx`. ### Example: submit and poll A job API in Hono. The spec declares the submit deferred with a $0.25 cap and the poll free of any Price: ```yaml paths: /videos: post: x-mercado-settlement: deferred x-mercado-max-price-micros: 250000 /jobs/{jobId}: get: x-mercado-max-price-micros: 0 ``` ```ts const SETTLE = 'https://admin-api.apimercado.com/v1/provider/requests'; app.post('/videos', async (c) => { const job = await jobs.create({ input: await c.req.json(), consumerId: c.req.header('X-Mercado-Consumer-Id'), requestId: c.req.header('X-Mercado-Request-Id'), }); c.header('Location', `/jobs/${job.id}`); return c.json({ jobId: job.id }, 202); // pending: the fee now, the price on settle }); app.get('/jobs/:jobId', async (c) => { const job = await jobs.get(c.req.param('jobId')); if (!job || job.consumerId !== c.req.header('X-Mercado-Consumer-Id')) { return c.json({ error: 'not_found' }, 404); } return c.json({ status: job.status, result: job.result ?? null }); }); // Called by the worker when the job ends, for good. async function settle(job: Job) { const amountMicros = job.failed ? 0 : Math.min(250000, priceFor(job.cost)); for (let attempt = 0; attempt < 10; attempt++) { const res = await fetch(`${SETTLE}/${job.requestId}/settle`, { method: 'POST', headers: { Authorization: `Bearer ${env.MERCADO_PROVIDER_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ amountMicros }), }); if (res.status !== 409 && res.status < 500) return res.json(); const { error } = await res.json().catch(() => ({ error: '' })); if (res.status === 409 && !String(error).startsWith('request_in_flight')) return; await new Promise((r) => setTimeout(r, 2000)); } throw new Error(`settle ${job.requestId} failed; retry it later`); } ``` Each poll costs the consumer only the proxy fee. Settle 0 only when the job has failed for good: a job you retry keeps its request id and settles when it finally ends. ### The 30-second gateway limit The gateway waits at most 30 seconds for your response headers. A slower response gets the consumer a `504`, is not charged, and its hold is released. For anything that can run longer, answer at once and let the consumer poll, as above. ## 6. Provider API The Provider API lets your servers and CI work with your own APIs without a portal login. Base URL: `https://admin-api.apimercado.com`. | Operation | Scope | What it does | | ----------------------------------------------- | ----------------- | -------------------------------------------------------------------------------------------------- | | `GET /v1/provider/whoami` | any key | Returns `{ keyId, providerOrgId, scopes }`, to check a key before you wire it in. | | `POST /v1/provider/apis/{apiId}/refresh` | `specs:refresh` | Re-reads the spec from its URL now. See [Refresh a spec](#refresh-a-spec). | | `POST /v1/provider/requests/{requestId}/settle` | `requests:settle` | Sets the price of a deferred request. See [Settle and read a request](#settle-and-read-a-request). | | `GET /v1/provider/requests/{requestId}` | `requests:read` | Returns a deferred request's hold and status. | ### Provider API keys Create a key in **Settings > Provider API** (org admins only; the tab appears once your organization has an API, even a draft). The key starts with `mpk_` and is shown once. Revoking it in the same place takes effect immediately. - Send it as `Authorization: Bearer mpk_...`. - Every key has every scope above. It cannot call APIs or sign in to the portal, and it only sees your own APIs and their requests. - At most 10 live keys per organization. From TypeScript, `createProviderClient({ providerKey })` in [`@apimercado/client`](https://www.npmjs.com/package/@apimercado/client) types every operation above. ### Refresh a spec We re-read your spec URL every hour. To pick up a change at once, for example as the last step of a deploy, call: ``` POST /v1/provider/apis/{apiId}/refresh Authorization: Bearer mpk_... ``` `apiId` is the id in your API's dashboard URL (`/dashboard/my-apis/{apiId}`). The answer is the same as **Check now** in the portal: ```json { "outcome": "released", "fromVersion": "1.2.0", "toVersion": "1.3.0" } ``` | `outcome` | Meaning | | -------------- | ------------------------------------------------------------------------------ | | `unchanged` | The spec matches what is served. | | `released` | `info.version` changed, so the new version is live and consumers were emailed. | | `draft_staged` | The spec changed but `info.version` did not. Raise it to release the change. | It answers `400 no_source_url` when the API has no spec URL, `422` with the reason when the spec cannot be fetched or is invalid, and `404` for an API that is not yours. At most 10 refreshes a minute per organization. ## 7. Go-live checklist Every item must pass before the API can go public. The Publish tab shows the same list with a link to fix each one. 1. An OpenAPI spec version is uploaded. 2. The spec is imported from a URL. 3. Your legal name, contact email, and country are set. 4. The current Provider Agreement is accepted. 5. Terms of Service and Privacy Policy URLs are set. 6. The health check is enabled and passing. 7. At least one successful call went through the gateway with your own Key while the API is Private. Enable your own API, create a Key, and call it. A summary and a category are recommended, so consumers can find the API. ## Prompt for your coding agent Paste this into a coding agent opened in your API's repository: ``` Read https://docs.apimercado.com/publish-an-api/index.md and prepare this repo to be published on API Mercado, including per-request pricing. ``` # Changelog Every Release of API Mercado, newest first. API Mercado is in beta: features and fees may change. ## 0.2.0 (2026-10-30) ### New - The TypeScript client now covers account and Provider API calls. - Set a Max cost on each call with the TypeScript client. Calls that could cost more than your Max cost are refused before they run. - The TypeScript client gives you every billing header on a response. - The request lookup now says whether a call was to your own organization's API (`internal`). ## 0.1.1 (2026-10-30) ### Fixes - The docs sidebar now highlights the section you are reading. ## 0.1.0 (2026-10-30) Earlier changes are not listed. First release of the public beta.