> ## Documentation Index
> Fetch the complete documentation index at: https://docs.joinmarkt.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Merchant notifications

> Read store notification channel preferences with a Bearer API key.

All routes require:

```txt theme={null}
Authorization: Bearer mk_live_<your_key>
```

The caller must be able to access that store. A key with store scope `SELECTED` must include that store. Access mode `FULL` skips the scope list and still requires dashboard permission `manageSettings`. Access mode `RESTRICTED` must include `notification:read` and that same permission. This route exports `GET` only.

```http theme={null}
GET /api/merchant/v1/stores/{storeId}/notifications
```

## Get notification settings

```http theme={null}
GET /api/merchant/v1/stores/{storeId}/notifications
```

Scope: `notification:read`. No body and no query parameters.

**storeId** `string` *required*

Store record id.

**hasDiscordWebhook** `boolean`

`true` when a Discord webhook URL is saved on the store.

**discordWebhookUrl** `string | null`

`null` when no URL is saved. When one is saved, the value is the string `[redacted]`.

**events** `object`

One entry for every event id. Each entry is `{ "email": boolean, "discord": boolean }`. With no saved config, `email` is `true` and `discord` is `false` for every id. A saved `order.delivered` entry is applied to `order.completed` when `order.completed` itself is absent. The response key is `order.completed`.

**event ids**

**order.created** `object`

Order created.

**order.completed** `object`

Order completed.

**order.pending** `object`

Order pending.

**order.undeliverable** `object`

Order undeliverable.

**inventory.out\_of\_stock** `object`

Product out of stock.

**inventory.low\_stock** `object`

Low stock.

**review\.added** `object`

Feedback submitted.

**ticket.created** `object`

Support ticket created.

**ticket.response\_added** `object`

Support ticket message.

```json theme={null}
{
  "hasDiscordWebhook": true,
  "discordWebhookUrl": "[redacted]",
  "events": {
    "order.created": { "email": true, "discord": false },
    "order.completed": { "email": true, "discord": true },
    "order.pending": { "email": true, "discord": false },
    "order.undeliverable": { "email": true, "discord": false },
    "inventory.out_of_stock": { "email": true, "discord": false },
    "inventory.low_stock": { "email": true, "discord": false },
    "review.added": { "email": true, "discord": false },
    "ticket.created": { "email": true, "discord": false },
    "ticket.response_added": { "email": true, "discord": false }
  }
}
```

```bash theme={null}
curl https://dash.joinmarkt.com/api/merchant/v1/stores/STORE_ID/notifications \
  -H "Authorization: Bearer mk_live_<your_key>"
```

## Errors

Failed responses use `{ "success": false, "error": "...", "code": "..." }`. A `500` also includes `errorId`.

| Status | Code | When |
| - | - | - |
| 401 | `UNAUTHORIZED` | Missing, invalid, or revoked token. `error` is `Unauthorized`. Expired keys use `API key expired`. |
| 403 | `FORBIDDEN` | Key cannot access this store, or `notification:read` / `manageSettings` is missing. `error` is `Forbidden`. |
| 404 | `NOT_FOUND` | `Store not found` |
| 429 | `RATE_LIMITED` | More than 120 requests in 60 seconds for this client IP, on the shared `merchant-api` bucket. The limit is checked before the key. `error` is `Too many requests`. |
| 500 | `INTERNAL_ERROR` | Unexpected failure. `error` is `Failed to load notifications`. |

## Related

* [Merchant Discord](https://docs.joinmarkt.com/api-reference/merchant-discord.md)
* [API keys](https://docs.joinmarkt.com/developers/api-keys.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.