Skip to content

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_access is written without a prefix.
  • Multiple scopes are separated by a single space, e.g. https://ad.anybill.de/vendor/bill offline_access.
  • The scope parameter is required and must not be empty.

Available scopes ​

ScopeUsed forNeeded for sending receiptsStatus
https://ad.anybill.de/vendor/billReceipt endpoints (/v3/bill)Yes – always request itActive
offline_accessReturns a refresh token together with the access token, see Refresh an Access TokenOptional, recommended for tills that run continuouslyActive
https://ad.anybill.de/vendor/storeStore endpoints (/v3/store)No – only if the POS manages stores via the APIActive
https://ad.anybill.de/vendor/customerLegacy customer endpointNoDeprecated – do not request
https://ad.anybill.de/vendor/userLegacy user identification endpointNoDeprecated – do not request
https://ad.anybill.de/vendor/categoryLegacy category endpointsNoDeprecated – 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_access

Add 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

Header
Content-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

Header
Content-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:

CaseVendor API token endpointIdentity provider directly
Unknown service account username404 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_token400, anybill problem details with an error code such as oauth-scope-missing (see Scope errors)Response of the identity provider
grant_type missing400, plain text (Missing grant_type)Response of the identity provider
Content-Type is not application/x-www-form-urlencoded415, problem detailsResponse of the identity provider
Identity provider answers 400 (e.g. wrong password)Passed through unchanged400 OAuth error
Identity provider answers with another status codeSame status code, no bodyResponse 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 backoffDepends 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:

  1. Add the missing scope to the scope parameter of the token request and request a new access token with the password grant.
  2. If the new access token still lacks the scope, the scope is not assigned to your client ID. Contact anybill.

Built 2026-10-28 08:37 CET from commit eef6288