
API Authentication
Overview
OKQ8 APIs enforce mandatory subscription key authentication. Some APIs also require OAuth 2.0 (Client Credentials) as an additional layer. If an API requires OAuth, both the subscription key and bearer token must be provided.
Subscription Key (Mandatory on All APIs)
OKQ8 uses subscription keys to enforce access control and apply per-product quotas/usage. A valid subscription key must be sent with every API request in the HTTP header:
Ocp-Apim-Subscription-Key: <your-subscription-key>
⚠️ Important: APIs cannot be called without a valid subscription key. OAuth (Client Credentials) may be required on top of the subscription key for specific APIs, but it never replaces the subscription key.
How to obtain your subscription key (Developer Portal)
Sign in to the Developer Portal.
Navigate to Products, select the product that contains the API(s) you need (e.g.,
OKQ8 Core APIs,Payments APIs).Click Subscribe.
If the product requires approval, your subscription will enter Pending status.
You will be notified once it is approved.
After approval, go to Profile → Subscriptions to view your Primary and Secondary keys.
You can regenerate either key at any time (e.g., during rotation or if compromised).
How to send the subscription key (Header)
Include the header in every request:
curl -i -X GET \
'https://<api-base-url>/<resource-path>' \
-H "Ocp-Apim-Subscription-Key: <your-subscription-key>"
✅ OKQ8 mandates header-based subscription keys. The APIM query parameter (?subscription-key=...) is not supported.Common error responses & troubleshooting
401 Unauthorized — Missing or invalid subscription key
Message example:Access denied due to invalid subscription key. Make sure to provide a valid key for an active subscription.
Fix: Ensure the header is present, the key is correct, and the subscription is active.403 Forbidden — Subscription not authorized for the selected product/API, or subscription is suspended
Fix: Verify your subscription status and product/API pairing.429 Too Many Requests — Quota/rate limit exceeded for your subscription
Fix: Respect throttling guidance or contact support to adjust quotas.
Key rotation and security best practices
Use Primary/Secondary keys to perform seamless rotation:
Configure clients to accept either key.
Switch clients to Secondary.
Regenerate Primary.
Switch clients back to Primary.
Treat keys as secrets:
Store in Azure Key Vault or a secure secrets manager.
Do not embed in client-side JavaScript, mobile apps, or public repos.
Log redaction: avoid logging headers that contain secrets.
OAuth 2.0 (Client Credentials)
Many OKQ8 APIs require OAuth 2.0 in addition to the subscription key. The OAuth token is obtained using the Client Credentials flow. Each client has a client_id and a client_secret along with parameters specifying the limited scopesent to the API via POST to receive an access token which is used for subsequent calls.
OAuth 2.0 token endpoint - https://login.microsoftonline.com/a53d724c-15ea-4469-a987-82a5b30ec167/oauth2/v2.0/token
Scope is nothing but the API name, which OKQ8 has provided each API along with specific access levels like - api://apim-xxxxx-xxxxx-api/.default
(.default specifies default access level, other access levels may be - get, post, put, delete)
DEMO REQUEST: Authentication
curl -X POST 'https://login.microsoftonline.com/a53d724c-15ea-4469-a987-82a5b30ec167/oauth2/v2.0/token' -H "Content-Type: application/x-www-form-urlencoded" -d 'grant_type=client_credentials&client_id=xxxxxxxx-xxxx-xxxx-xxxxxx-xxxxxxxxxx&client_secret=xxxxxxxxxxxxxxxxxxxxxxx&scope=api%3A%2F%2Fapim-xxxxx-xxxxx-api%2F.default'
DEMO RESPONSE: Authentication
HTTP/1.1 200 OK Cache-Control: no-store, no-cache Pragma: no-cache Content-Type: application/json; charset=utf-8 Expires: -1 Strict-Transport-Security: max-age=31536000; includeSubDomains X-Content-Type-Options: nosniff P3P: CP="DSP CUR OTPi IND OTRi ONL FIN" x-ms-request-id: 6abfe8d2-a2b6-4a4e-b0a9-f6a97ddf9f00 x-ms-ests-server: 2.1.11898.12 - NEULR2 ProdSlices Set-Cookie: fpc=AhnzB1NSHFVHqPNvtbC5udiBKrogAQAAAGKxmdgOAAAA; expires=Wed, 01-Sep-2021 09:26:59 GMT; path=/; secure; HttpOnly; SameSite=None Set-Cookie: x-ms-gateway-slice=estsfd; path=/; secure; samesite=none; httponly Set-Cookie: stsservicecookie=estsfd; path=/; secure; samesite=none; httponly Date: Mon, 02 Aug 2021 09:26:59 GMT Content-Length: 1236 {"token_type":"Bearer","expires_in":3599,"ext_expires_in":3599,"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik1uQ19WWmNBVGZNNXBP..."}An access_token is valid for one(1) hour.
A new access_token can be requested any time. If a request to the API is issued with a non-valid access_token a http-response with the HTTP-header 401 is returned such as HTTP/1.1 401 Unauthorized. With the use of a valid access_token request to the API can be done as the example below.
Note: Client Credentials and Access Tokens needs to be treated securely, It is how you securely identify your application's rights and identity when accessing the OKQ8 API. Do not distribute Client Credentials or Access Tokens in email, distributed native applications, client-side javascript, or public code repositories.
Common error responses & troubleshooting (OAuth / Bearer Token)
401 Unauthorized — Missing or invalid bearer token Message examples:
{"statusCode": 401, "message": "Unauthorized. Access token is missing or invalid."}Fix :
Ensure the Authorization header is present and correctly formatted: Authorization: Bearer <access_token>
Obtain the token using Client Credentials (grant_type=client_credentials)
Verify the audience matches the API’s Application ID URI (for example: api://apim-xxxxx-xxxxx-api)
Use the correct scope for Client Credentials (for example: api://apim-xxxxx-xxxxx-api/.default)
Check token expiry (~1 hour) and allow for small clock skew; refresh before expiry
Combined example (OAuth + Subscription Key)
curl -i -X GET \
'https://<api-base-url>/<resource-path>' \
-H "Ocp-Apim-Subscription-Key: <your-subscription-key>" \
-H "Authorization: Bearer <access_token>"
Please send email to integration@okq8.se to help you to get required clientId and clientSecret.