# Authentication

A key is how a script or an assistant gets into your programme. You make it in the app, choose what it may do, and send it with every call.

## Making a key

Keys are made on the **API keys** screen of the app: in Shopify admin, open Apps, then Matrix Rewards, then API keys. Only your store's staff can open it. The API itself cannot make a key: no permission lets one key make another, because a key that could make keys could widen its own reach.

Any store with the app installed can make keys. When you make one, you choose:

- a name, for your own list and your activity log, of up to 60 characters;
- what it may do, from the permissions below;
- whether it is for an AI assistant;
- whether it is a test key.

An account can hold at most 20 keys at once, test keys included. Revoked keys do not count.

## What a key looks like

A live key starts `mrk_live_` and a test key starts `mrk_test_`. The whole key has this shape: `mrk_live_<key id>.<secret><checksum>`.

The key is shown once, when it is made. Only a keyed hash of its secret is kept, so a lost key cannot be shown again: rotate it to get a new secret.

## Sending it

Send the key in the `Authorization` header of every call, after the word `Bearer`. The word can be written in any case.

```bash
export MATRIX_API_KEY='mrk_live_...'
curl "https://app.matrixrewards.co.uk/api/2026-10/me" -H "Authorization: Bearer $MATRIX_API_KEY"
```

Never paste a key into a chat or a file you share. One key reaches every store on your account, not only the store you made it in.

[`GET /me`](https://matrixrewards.co.uk/docs/api/2026-10/account.md#getMe) is the call to make first. It says which account the key belongs to, its stores, what the key may do, and whether it is a test key or one for an assistant. It needs no permission beyond a valid key.

## What a key may do {#permissions}

Each permission is a box you tick when you make the key. The table gives each one, the words on its box, and the calls it opens.

| Permission | What the box in the app says | What it lets a key call |
| --- | --- | --- |
| `read_programme` | Your programme settings — rates, rewards, rules | [`GET /stores`](https://matrixrewards.co.uk/docs/api/2026-10/stores.md#listStores), [`GET /stores/{store_key}`](https://matrixrewards.co.uk/docs/api/2026-10/stores.md#getStore), [`GET /stores/{store_key}/programme`](https://matrixrewards.co.uk/docs/api/2026-10/stores.md#getProgramme), [`GET /stores/{store_key}/programme/rewards`](https://matrixrewards.co.uk/docs/api/2026-10/stores.md#listRewards), [`GET /stores/{store_key}/programme/offers`](https://matrixrewards.co.uk/docs/api/2026-10/stores.md#listOffers), [`GET /stores/{store_key}/programme/rules`](https://matrixrewards.co.uk/docs/api/2026-10/stores.md#listRules), [`GET /stores/{store_key}/design`](https://matrixrewards.co.uk/docs/api/2026-10/stores.md#getDesign), [`GET /stores/{store_key}/brand`](https://matrixrewards.co.uk/docs/api/2026-10/stores.md#getStoreBranding), [`GET /stores/{store_key}/images`](https://matrixrewards.co.uk/docs/api/2026-10/stores.md#listBrandImages) |
| `read_members` | Members, their points, their email addresses and the last four characters of their reward codes | [`GET /members`](https://matrixrewards.co.uk/docs/api/2026-10/members.md#listMembers), [`GET /members/{member_key}`](https://matrixrewards.co.uk/docs/api/2026-10/members.md#getMember), [`GET /members/{member_key}/codes`](https://matrixrewards.co.uk/docs/api/2026-10/members.md#listMemberCodes) |
| `read_reports` | The ledger, what you owe, and settlement between stores | [`GET /ledger`](https://matrixrewards.co.uk/docs/api/2026-10/reports.md#listLedger), [`GET /reports/liability`](https://matrixrewards.co.uk/docs/api/2026-10/reports.md#getLiabilityReport), [`GET /reports/settlement`](https://matrixrewards.co.uk/docs/api/2026-10/reports.md#getSettlementReport) |
| `read_usage` | Orders used this month and which plan you are on | [`GET /usage`](https://matrixrewards.co.uk/docs/api/2026-10/billing.md#getUsage), [`GET /plan`](https://matrixrewards.co.uk/docs/api/2026-10/billing.md#getPlan) |
| `read_audit` | The activity log — what each key did and saw | [`GET /audit-log`](https://matrixrewards.co.uk/docs/api/2026-10/log.md#listAuditLog) |
| `manage_keys` | The list of your keys (not their secrets) | [`GET /keys`](https://matrixrewards.co.uk/docs/api/2026-10/account.md#listKeys) |
| `write_members` | Change members’ points and cancel reward codes. This also reads members, their email addresses and the last four characters of their reward codes. Every change is logged | [`POST /members/{member_key}/adjustments`](https://matrixrewards.co.uk/docs/api/2026-10/members.md#adjustMemberPoints), [`POST /members/{member_key}/codes/void`](https://matrixrewards.co.uk/docs/api/2026-10/members.md#cancelMemberCode), [`GET /members`](https://matrixrewards.co.uk/docs/api/2026-10/members.md#listMembers), [`GET /members/{member_key}`](https://matrixrewards.co.uk/docs/api/2026-10/members.md#getMember), [`GET /members/{member_key}/codes`](https://matrixrewards.co.uk/docs/api/2026-10/members.md#listMemberCodes) |
| `write_webhooks` | Send every change to members’ points, by member key, to a web address the key chooses (webhooks). Not for an assistant key | [`GET /webhooks`](https://matrixrewards.co.uk/docs/api/2026-10/webhooks.md#listWebhookEndpoints), [`POST /webhooks`](https://matrixrewards.co.uk/docs/api/2026-10/webhooks.md#createWebhookEndpoint), [`DELETE /webhooks/{endpoint_id}`](https://matrixrewards.co.uk/docs/api/2026-10/webhooks.md#deleteWebhookEndpoint), [`POST /webhooks/{endpoint_id}/test`](https://matrixrewards.co.uk/docs/api/2026-10/webhooks.md#testWebhookEndpoint) |
| `write_programme` | Change your programme: the earn rate, the joining and birthday bonuses, what a point is worth, when points expire, the rewards and the offers. Every change is previewable and logged | [`POST /stores/{store_key}/programme`](https://matrixrewards.co.uk/docs/api/2026-10/stores.md#updateProgramme), [`POST /stores/{store_key}/programme/rewards`](https://matrixrewards.co.uk/docs/api/2026-10/stores.md#addReward), [`POST /stores/{store_key}/programme/rewards/{reward_id}`](https://matrixrewards.co.uk/docs/api/2026-10/stores.md#changeReward), [`POST /stores/{store_key}/programme/rewards/{reward_id}/remove`](https://matrixrewards.co.uk/docs/api/2026-10/stores.md#removeReward), [`POST /stores/{store_key}/programme/offers`](https://matrixrewards.co.uk/docs/api/2026-10/stores.md#addOffer), [`POST /stores/{store_key}/programme/offers/{offer_id}`](https://matrixrewards.co.uk/docs/api/2026-10/stores.md#changeOffer), [`POST /stores/{store_key}/programme/offers/{offer_id}/remove`](https://matrixrewards.co.uk/docs/api/2026-10/stores.md#removeOffer), [`POST /stores/{store_key}/design`](https://matrixrewards.co.uk/docs/api/2026-10/stores.md#updateDesign), [`POST /stores/{store_key}/images`](https://matrixrewards.co.uk/docs/api/2026-10/stores.md#uploadBrandImage), [`GET /stores`](https://matrixrewards.co.uk/docs/api/2026-10/stores.md#listStores), [`GET /stores/{store_key}`](https://matrixrewards.co.uk/docs/api/2026-10/stores.md#getStore), [`GET /stores/{store_key}/programme`](https://matrixrewards.co.uk/docs/api/2026-10/stores.md#getProgramme), [`GET /stores/{store_key}/programme/rewards`](https://matrixrewards.co.uk/docs/api/2026-10/stores.md#listRewards), [`GET /stores/{store_key}/programme/offers`](https://matrixrewards.co.uk/docs/api/2026-10/stores.md#listOffers), [`GET /stores/{store_key}/programme/rules`](https://matrixrewards.co.uk/docs/api/2026-10/stores.md#listRules), [`GET /stores/{store_key}/design`](https://matrixrewards.co.uk/docs/api/2026-10/stores.md#getDesign), [`GET /stores/{store_key}/brand`](https://matrixrewards.co.uk/docs/api/2026-10/stores.md#getStoreBranding), [`GET /stores/{store_key}/images`](https://matrixrewards.co.uk/docs/api/2026-10/stores.md#listBrandImages) |

What the reference says of the list:

> A scope a key can hold. This list is exactly the scopes some operation checks. `write_members` covers the two writes (changing a member's points, cancelling a reward code) and also covers `read_members`. The self-revoke needs no scope. `write_webhooks` covers the webhook endpoints — listing, creating, deleting and testing them — and a key for an AI assistant can never hold it. `write_programme` covers changing the programme (`POST /stores/{store_key}/programme`); a key for an assistant may hold it, and must preview each change and send back its confirmation.

## Test keys

A test key reads your real data: there is no separate test copy. It can preview a change, and even send back a preview's confirmation, but the change itself is always refused with [test_mode_key](https://matrixrewards.co.uk/docs/errors/test_mode_key.md). A test key cannot manage webhooks either.

## Keys for AI assistants

When you make a key you can mark it as being for an AI assistant. Such a key must preview a points change or a cancelled code, then send back that preview's confirmation, before anything changes. Without it the change is refused with [confirmation_required](https://matrixrewards.co.uk/docs/errors/confirmation_required.md). The one exception is a request that repeats a change already made, which changes nothing. A key for an assistant can never manage webhooks. [How the two steps work](https://matrixrewards.co.uk/docs/idempotency.md#assistant-keys).

A key for an assistant also moves the programme's money one step at a time ([assistant_limit](https://matrixrewards.co.uk/docs/errors/assistant_limit.md)), unless the merchant has lifted its limits on the API keys screen in the app. Only a person can lift or put back those limits, there; no API call can. [`GET /me`](https://matrixrewards.co.uk/docs/api/2026-10/account.md#getMe) says which: `key.limits_lifted`. Lifted, the key still needs the preview's confirmation for every change (which it sends itself: the API cannot see whether a person agreed), and still cannot manage webhooks.

## Rotating a key

Rotating gives a key a new secret and keeps what it may do. When you rotate from the app, the old secret keeps working for 1 day, so you can move whatever uses it; after that it gets `unauthenticated`. A call made with the old secret while it still works shows `key.used_previous_secret` as `true` in [`GET /me`](https://matrixrewards.co.uk/docs/api/2026-10/account.md#getMe).

## Revoking a key

Revoke a key on the API keys screen, or with the key itself: [`POST /keys/self/revoke`](https://matrixrewards.co.uk/docs/api/2026-10/account.md#revokeThisKey) needs no permission and never counts against the key's allowance.

If a key leaks, revoke it with itself first, then make a new one.

## A key that does not work

A missing, mistyped, unknown or revoked key, and an old secret whose rotation window has closed, all get the same answer: status `401`, with the code [unauthenticated](https://matrixrewards.co.uk/docs/errors/unauthenticated.md). That is on purpose: telling them apart would tell someone guessing keys how close they came.

## What a key never returns

No call returns a shopper's name, phone number or address, because the platform holds none of them, and no call returns a birthday. The only contact detail is `email`.

No answer carries a whole reward code either. A code is named by its last four characters, `code_ending`, and by its `ref`, which is what a cancel takes. The shopper holds the code itself.

## Everything is logged

Every read of a shopper's details is written to your account's activity log before it is returned. If that cannot be written, the call answers with status `503` and the code [access_not_recorded](https://matrixrewards.co.uk/docs/errors/access_not_recorded.md), and returns nothing. Every change made with a key is written to the log the same way, with the key's name. Entries are kept for 365 days.

You read the log with [`GET /audit-log`](https://matrixrewards.co.uk/docs/api/2026-10/log.md#listAuditLog), which needs `read_audit`. There is no screen for it in the app yet.

---

Page: https://matrixrewards.co.uk/docs/authentication
Contract: 2026-10 sha256:35af153960028890fea5738799f5a71e535e1eea4dd3f6b8d5f50b37f02363da
