# API keys

Mercemur authenticates with a secret key sent as a bearer token. There is no OAuth
dance and no signing step for a merchant's own integration.

```bash
curl https://api.mercemur.com/api/v1/products \
  -H "Authorization: Bearer sk_..."
```

## Creating a key

Open **Settings, API keys** in your dashboard, create a key, and grant it the scopes
your integration needs. Grant the minimum: read, write and delete are separate ticks
on each resource family. See [Scopes](/authentication/scopes).

<Warning>
  The key value is shown **once**, at creation. Mercemur stores only a hash of it, so
  the plaintext cannot be recovered afterwards by you, by support, or by anyone with
  database access. Copy it into your secret store immediately.
</Warning>

## Storing it

A secret key can read and modify your store. Treat it like a production database
password.

- Keep it server side. Never ship it in a browser bundle, a mobile app, or any client
  a shopper can open.
- Load it from the environment or a secret manager, never from source.
- Never commit it. If it reaches a repository, rotate it, because git history is
  permanent even after the file is deleted.
- Never paste it into a support ticket, a screenshot, or a chat message.

<Note>
  If a key is exposed, rotate it rather than reasoning about whether anyone actually
  saw it. Rotation is cheap and takes about a minute.
</Note>

## Rotating without downtime

Because a key is not tied to a single integration slot, you can hold two working keys
at once. That is what makes a zero-downtime rotation possible.

<Steps>
  <Step title="Create the replacement key">
    Grant it the same scopes as the key you are replacing.
  </Step>
  <Step title="Deploy the new value">
    Update the secret in your environment or secret manager and roll your service.
  </Step>
  <Step title="Confirm the new key is serving traffic">
    Check your logs, or make one call with it. Do not skip this step. Revoking first
    and confirming afterwards is how a rotation becomes an outage.
  </Step>
  <Step title="Revoke the old key">
    Delete it in the dashboard. It stops working immediately.
  </Step>
</Steps>

## Revoking

Deleting a key in the dashboard takes effect immediately. There is no grace period, so
any service still holding it starts receiving `401`.

## Errors you will see

A missing, malformed, revoked or mistyped key returns `401`:

```json
{
  "error": {
    "code": "unauthorized",
    "message": "invalid api key"
  }
}
```

The message is deliberately the same for every one of those cases. Telling you *which*
way a credential is wrong tells an attacker the same thing, and it would turn this
endpoint into an oracle for which keys exist.

<Warning>
  Do not retry a `401` in a loop. Repeated authentication failures are counted in their
  own rate limit bucket, so a loop will convert your `401` into a `429` and delay the
  fix. Correct the credential instead.
</Warning>

## Scope refusals are not authentication failures

A `403 insufficient_scope` means the key is valid but not permitted for that route. The
message names the exact scope to add. Fix it by editing the key's scopes in the
dashboard rather than by creating a new key. See [Scopes](/authentication/scopes).

## Publishable keys are not accepted here

If your store also has a publishable key for storefront use, it will not authenticate
against this API. Publishable keys are safe to expose and therefore cannot be allowed
to reach merchant data. Only a secret key works on `/api/v1`.
