Appearance
Authentication
Basics
Communication with the anybill cloud platform is only possible after prior authentication.
anybill uses OAuth 2.0 or OpenId Access Tokens for authentication. The identities are managed in an Azure Active Directory B2C. To get an access token you need a client id and a service account with username and password.
- The client ID is assigned by anybill once per POS system manufacturer.
- Username and password of the service account are assigned by anybill to the merchant.
Scopes
The functional areas of the API are secured by scopes. A scope is a permission that you request together with the access token. The access token only contains the scopes you requested and that are assigned to your client ID, and an endpoint group that is secured by a scope rejects access tokens without it.
Scopes are passed in the scope parameter of the token request:
- anybill scopes are always written as the full URI, e.g.
https://ad.anybill.de/vendor/bill.offline_accessis written without a prefix. - Multiple scopes are separated by a single space, e.g.
https://ad.anybill.de/vendor/bill offline_access. - The
scopeparameter is required and must not be empty.
Available scopes
| Scope | Used for | Needed for sending receipts | Status |
|---|---|---|---|
https://ad.anybill.de/vendor/bill | Receipt endpoints (/v3/bill) | Yes – always request it | Active |
offline_access | Returns a refresh token together with the access token, see Refresh an Access Token | Optional, recommended for tills that run continuously | Active |
https://ad.anybill.de/vendor/store | Store endpoints (/v3/store) | No – only if the POS manages stores via the API | Active |
https://ad.anybill.de/vendor/customer | Legacy customer endpoint | No | Deprecated – do not request |
https://ad.anybill.de/vendor/user | Legacy user identification endpoint | No | Deprecated – do not request |
https://ad.anybill.de/vendor/category | Legacy category endpoints | No | Deprecated – do not request |
The client ID of a POS system manufacturer is set up with all of these scopes. The identity provider only issues scopes that are assigned to your client ID; the Vendor API does not check the requested scope string itself.
Which scopes to request
For sending receipts to anybill, request:
https://ad.anybill.de/vendor/bill offline_accessAdd https://ad.anybill.de/vendor/store only if the POS reads, searches, creates, updates or deletes stores via the API. Do not request the deprecated scopes in new integrations. Requesting every scope assigned to your client ID works, but grants the access token more permissions than the integration needs.
Always request the bill scope
The /v3/bill endpoints currently accept access tokens without the https://ad.anybill.de/vendor/bill scope, while other receipt endpoints already require it. This describes the current behaviour, not a guarantee: the scope check may be enforced for /v3/bill in the future. Always request the bill scope so that your integration keeps working.
Retrieving an Access Token
To retrieve an access token, an HTTP POST request with the following data must be sent to the token endpoint of the Vendor API.
URL
- Staging:
https://vendor.stg.anybill.de/api/oauth/token - Production:
https://vendor.anybill.de/api/oauth/token
HeaderContent-Type: application/x-www-form-urlencoded
Body
json5
{
grant_type: password
username: <service account username>
password: <service account password>
client_id: <client id of the POS system manufacturer>
scope: https://ad.anybill.de/vendor/bill offline_access
response_type: token
}The body is form-encoded, not JSON. grant_type must be password or refresh_token; username, password, client_id and scope are required for the password grant. The same request as a curl command against Staging:
bash
curl -X POST \
'https://vendor.stg.anybill.de/api/oauth/token' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=password' \
-d 'username=<service account username>' \
-d 'password=<service account password>' \
-d 'client_id=<client id of the POS system manufacturer>' \
--data-urlencode 'scope=https://ad.anybill.de/vendor/bill offline_access' \
-d 'response_type=token'If authentication is successful, the server outputs the access token as a response in the following format:
json5
{
"access_token": "*****",
"token_type": "Bearer",
"expires_in": "86400",
"refresh_token": "*****"
}For every communication with endpoints of the anybill API the access token must be specified in the header:
Authorization: Bearer <access_token>
Legacy token endpoint
Integrations that request tokens directly from the identity provider keep working; see Legacy token endpoint for the differences in error responses.
Refresh an Access Token
If the token request contained offline_access, the response also contains a refresh token. Use it to get a new access token without sending the service account password again:
URL
- Staging:
https://vendor.stg.anybill.de/api/oauth/token - Production:
https://vendor.anybill.de/api/oauth/token
HeaderContent-Type: application/x-www-form-urlencoded
Body
json5
{
refresh_token: <refresh token>
grant_type: refresh_token
client_id: <client id of the POS system manufacturer>
scope: https://ad.anybill.de/vendor/bill offline_access
response_type: token
}As a curl command against Staging:
bash
curl -X POST \
'https://vendor.stg.anybill.de/api/oauth/token' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=refresh_token' \
-d 'refresh_token=<refresh token>' \
-d 'client_id=<client id of the POS system manufacturer>' \
--data-urlencode 'scope=https://ad.anybill.de/vendor/bill offline_access' \
-d 'response_type=token'If the update is successful, the server outputs the access token as a response in the following format:
json5
{
"access_token": "*****",
"token_type": "Bearer",
"expires_in": "86400",
"refresh_token": "*****",
"refresh_token_expires_in": "*****"
}Legacy token endpoint
Before the Vendor API token endpoint was introduced, tokens were requested directly from anybill's identity provider (Azure AD B2C):
https://adanybill.b2clogin.com/ad.anybill.de/oauth2/v2.0/token?p=b2c_1_ropc_vendor
This endpoint is legacy and still supported. It accepts the same form body for both grants, and the endpoint is the same for Staging and Production. New integrations should use the Vendor API token endpoint of the respective environment.
The Vendor API token endpoint checks the request before forwarding it to the identity provider. Successful responses are identical, but error responses differ. If your integration evaluates the OAuth error codes of the identity provider (error, error_description), take the following cases into account when switching endpoints:
| Case | Vendor API token endpoint | Identity provider directly |
|---|---|---|
| Unknown service account username | 404 Not Found, plain text (VendorApiUser could not be found.) | 400, invalid_grant |
username, password, client_id or scope missing or empty; grant_type neither password nor refresh_token | 400, anybill problem details with an error code such as oauth-scope-missing (see Scope errors) | Response of the identity provider |
grant_type missing | 400, plain text (Missing grant_type) | Response of the identity provider |
Content-Type is not application/x-www-form-urlencoded | 415, problem details | Response of the identity provider |
Identity provider answers 400 (e.g. wrong password) | Passed through unchanged | 400 OAuth error |
| Identity provider answers with another status code | Same status code, no body | Response of the identity provider |
| Identity provider does not answer within 3 seconds (including internal retries) | 503, problem details (type: https://anybill.de/oauth-timeout) – retry with backoff | Depends on your client's timeout |
Scope errors
Token request without scope. If a password grant is sent to the Vendor API token endpoint without a scope parameter or with an empty one, no access token is issued. The response is 400 Bad Request with a problem details body:
json
{
"title": "One or more business logic errors occurred.",
"status": 400,
"errors": [
{ "code": "oauth-scope-missing", "message": "Missing scope" }
],
"traceId": "..."
}API call with an access token that lacks a scope. Endpoints secured by a scope answer with 403 Forbidden and a plain-text body that names the missing scope:
The access token is missing the right scope. Scope 'store' is required.Do not retry the request. Instead:
- Add the missing scope to the
scopeparameter of the token request and request a new access token with the password grant. - If the new access token still lacks the scope, the scope is not assigned to your client ID. Contact anybill.