Authentication
Every call to the Integration API carries a token in the Authorization header. A token belongs to a user of your app and works for the whole app: it reads and writes that app's data and nothing else.
Get a token#
In Admin, open User › Tokens and create a token for the system that will use it. Use a separate token for every system that talks to us, your ERP, your warehouse, your POS, so you can revoke one without touching the others.
A token is a key to your app's data. Keep it on your server, in an environment variable or a secrets store. Never put it in a browser, a mobile app or a repository. Apps and sites your customers use call the Storefront API with a session of their own instead.
Send it with every request#
Put the token in the Authorization header after the word Bearer:
- Write
Bearerexactly like that, followed by one space and the token. - Send one
Authorizationheader. A request with two is treated as having none. - The token goes in the header only, never in the URL or the body.
Basic authentication with app keys is not accepted on the Integration API. In the public API it only starts a storefront session.
curl "https://api.morffeus.com/api/v2/warehouses" \ -H "Authorization: Bearer $MORFFEUS_TOKEN"
const res = await fetch('https://api.morffeus.com/api/v2/warehouses', { headers: { Authorization: `Bearer ${process.env.MORFFEUS_TOKEN}` } });
$ch = curl_init('https://api.morffeus.com/api/v2/warehouses'); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Authorization: Bearer ' . getenv('MORFFEUS_TOKEN'), ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
{
"errors": {
"token": "API.Token.NotFound"
}
}
What a token carries#
A token is made for one user of one app. You never send an app id: everything below comes from the token.
| Part | What it decides |
|---|---|
| app | Whose data you read and write. Every call works inside this app. |
| client | The company the app belongs to. |
| user | Whose rights apply where an endpoint checks them. GET /orders, for example, returns only orders from the sales channels this user may see. |
| market, currency | The prices and currency in responses, for example on GET /products. |
| language | The language of translated texts in responses, such as unit names on GET /stocks. |
Expiry and revocation#
Tokens expire. How long a token lives is set for your app; once it has expired, calls fail with 401 and expired, and you create a new one in User › Tokens.
Revoking a token in User › Tokens stops it at once. We look every token up on every call, so a revoked token fails with API.Token.NotFound from the next request on.
When a token is refused#
A refused token gets 401 and a body that names the token field. The value tells you why:
| errors.token | Why |
|---|---|
| API.Authorization.Error | No Authorization header, or more than one. |
| Invalid authorization format | The header is not Bearer, one space and the token. |
| invalid, API.Token.Invalid | The token is not one of ours, or it was cut or changed on the way. |
| expired | The token's lifetime is over. Create a new one. |
| API.Token.NotFound | The token was revoked. |
| API.Autorization.Unauthorized | The token is valid but not accepted here, for example Basic authentication or a guest storefront session. The key is spelled this way in the API. |
Every other error has the same envelope with a different field. See Errors.
Storefront calls#
The Storefront API does not use these tokens. An app or site your customers use starts a session with the app's keys and signs the customer in; every call then carries that session's token in the same Authorization: Bearer header. See Sessions & sign-in.
Related#
- Your first request: the token in use, from an empty terminal to a stock update.
- Errors: the error envelope and the status codes we use.
- Base URL & environments: where to send requests while you build.