> ## 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 blacklist

> List, create, and delete store blacklist rules with a Bearer API key.

All routes require:

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

`requireMerchantAuth` reads `Authorization` and accepts only `Bearer` plus a token that starts with `mk_live_`. A missing header, a non-Bearer scheme, any other prefix, an unknown key, a revoked key, or a completed account deletion is `401` with `error` `Unauthorized` and `code` `UNAUTHORIZED`. An expired key is `401` with `error` `API key expired` and the same code.

The key must be allowed to access `{storeId}`: the key owner can access that shop, and a key limited to selected shops must list it. The key owner must have `manageBlacklist` on that shop. A restricted key must include the scope named on the method. `blacklist:write` also satisfies `blacklist:read`. A full-access key skips the scope list and still needs `manageBlacklist`. A failed shop, scope, or permission check is `403` with `error` `Forbidden` and `code` `FORBIDDEN`.

`storeId` in the JSON body is ignored. The shop is the `{storeId}` in the path.

Merchant routes share one limit of 120 requests per 60 seconds per client IP. Over the limit the response is `429` with `error` `Too many requests` and `code` `RATE_LIMITED`.

There is no GET, PUT, or PATCH on a single entry. Delete is `DELETE /blacklist/{entryId}`.

## List

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

Scope: `blacklist:read`

Query:

| Param | Rule |
| - | - |
| `page` | Integer ≥ 1. Default `1` |
| `limit` | Integer 1–100. Default `50` |

Rows are the shop's blacklist, newest `createdAt` first, then sliced for the page. The response has no `hasMore` or cursor.

```json theme={null}
{
  "entries": [
    {
      "id": "cm...",
      "storeId": "cm...",
      "type": "email",
      "value": "abuse@example.com",
      "matchType": "exact",
      "reason": "Chargeback",
      "createdAt": "2026-10-25T12:00:00.000Z",
      "updatedAt": "2026-10-25T12:00:00.000Z"
    }
  ],
  "page": 1,
  "limit": 50,
  "total": 1
}
```

`createdAt` and `updatedAt` are ISO timestamps. `reason` is a string or null. A page past the end returns `entries: []` with the same `total`.

Invalid `page` or `limit` returns `400`.

## Create

```http theme={null}
POST /api/merchant/v1/stores/{storeId}/blacklist
```

Scope: `blacklist:write`

Status `201`. The body is the entry, not wrapped in `entries`.

```json theme={null}
{
  "type": "email",
  "value": "abuse@example.com",
  "matchType": "exact",
  "reason": "Chargeback"
}
```

| Field | Rule |
| - | - |
| `type` | `email`, `ip`, `userAgent`, `discordId`, `asn`, or `country` |
| `value` | String, trimmed, 1–500 characters |
| `matchType` | `exact` or `regex` |
| `reason` | Optional string, max 500 characters, or null. Saved trimmed. Empty or whitespace-only is stored as null |

`value` is trimmed again when saved.

`ip`, `userAgent`, `asn`, and `country` require Premium or Business. That check runs first and returns `403` with `error` `IP, user agent, ASN, and country blocks require Premium or Business.`, `code` `plan_blacklist_advanced_type`, `requiredPlan` `premium`, and `upgradePath` `/billing`. `regex` on a type the plan already allows requires Premium or Business and returns `403` with `error` `Regex blacklist rules require Premium or Business.`, `code` `plan_blacklist_regex`, and the same `requiredPlan` and `upgradePath`. `email` and `discordId` with `exact` are allowed on Free.

`matchType: "regex"` must be a safe pattern. An invalid or unsafe pattern returns `400`. `error` is the validator message and `code` is `blacklist_unsafe_regex`. Other body and query failures use `code` `BAD_REQUEST`. `Invalid JSON` means the body did not parse. `JSON body must be an object` means the body was not an object. Field errors are the Zod issues joined with `; `.

The created object uses the same fields as a list entry.

## Delete

```http theme={null}
DELETE /api/merchant/v1/stores/{storeId}/blacklist/{entryId}
```

Scope: `blacklist:write`

`{entryId}` is the entry `id`. A missing entry, or an entry that belongs to another shop, returns `404` (`Blacklist entry not found`).

Success is `200`:

```json theme={null}
{ "success": true }
```

## Errors

| Status | Meaning |
| - | - |
| 400 | `Invalid JSON`, `JSON body must be an object`, Zod issues joined with `; `, or an unsafe regex. `code` is `BAD_REQUEST`, or `blacklist_unsafe_regex` for the regex check |
| 401 | `Unauthorized` or `API key expired`. `code` is `UNAUTHORIZED` |
| 403 | `Forbidden` (`code` `FORBIDDEN`) or a plan limit (`plan_blacklist_advanced_type` or `plan_blacklist_regex`, plus `requiredPlan` and `upgradePath`) |
| 404 | `Blacklist entry not found` (`code` `NOT_FOUND`) |
| 429 | `Too many requests` (`code` `RATE_LIMITED`) |
| 500 | `Failed to list blacklist`, `Failed to create blacklist entry`, or `Failed to delete blacklist entry`. `code` is `INTERNAL_ERROR` and the body includes `errorId` |

Error JSON is `{ "success": false, "error": "...", "code": "..." }`. Plan limits also return `requiredPlan` and `upgradePath`. A 500 also returns `errorId`.

## Related

* [Merchant anti-fraud](https://docs.joinmarkt.com/api-reference/merchant-antifraud.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.