> Part of the API Mercado docs, in beta. Markdown for every page: append `index.md` to its URL. Site map: /llms.txt

# 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/@<provider-slug>/<api-slug>/<path>
```

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 `<path>`.
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 `@<provider-slug>` 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/@<provider-slug>/<api-slug>` 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 <date>" or
"Price cap raised on <date>" 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": "<code>: <detail>" }`:

| 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.
```
