Authentication

How provider keys are formatted and sent, how the partner header works, which routes each kind of key may call, effective scopes, and replacing a key without downtime.

Every call you make is authenticated with a provider key that Localoy issues to your company. A call made for a partner also names that partner in the X-Localoy-Partner-Id header.

Key format#

Format
ltp_{environment}_{prefix}_{secret}
PartValue
ltpThe fixed tag of Technology Provider keys, so a leaked key is easy to find with a secret scanner. Partner keys start lok.
environmentsbx for a sandbox key, live for a production key. A key keeps its environment for life.
prefix8 characters from a–z and 2–9, without the look-alikes l, o, 0 and 1.
secret43 characters of URL-safe base64. It may itself contain _.

A sandbox key is 60 characters long and a production key 61. The first three parts together — ltp_sbx_k7m2q9xa — are the key's public prefix: GET /ping returns it, so you can tell keys apart without exposing the secret.

Localoy stores only a SHA-256 hash of each key. A key is shown once, when Localoy issues it, and cannot be recovered afterwards. Localoy can also give a key an expiry date; after it, the key is refused.

Sending the key#

Send the key in either header:

Preferred
Authorization: Bearer ltp_live_r4t8wz3c_…
Alternative
X-Api-Key: ltp_live_r4t8wz3c_…

If a request carries both, the Authorization header is used.

Which routes a key can call#

RoutePartner key (lok_…)Provider key (ltp_…)
GET /healthNo key needed.No key needed.
GET /pingYes.Yes. The partner header is optional.
Catalogue, bookables and paymentsYes, for its own partner.Yes, for the partner named in X-Localoy-Partner-Id.
/connections… and /webhooks…403 provider_key_requiredYes. The partner header is ignored.

The catalogue, bookables and payment endpoints are the partner-scoped endpoints. The connection and webhook endpoints act for your company, not for a partner.

The partner header#

Header
X-Localoy-Partner-Id: cm1partnerid000000000000001

Send it on every partner-scoped call. Its value is the partnerId of a connection you claimed. Localoy then checks that connection:

SituationStatusCode
The header is missing or empty.400partner_id_required
The partner is not connected to you — never connected, its code not yet claimed, or disconnected.404connection_not_found
The partner has paused you.403connection_paused
The connection's effective scopes lack the scope the endpoint needs.403open_network_scope_required
Response · 404
{
  "success": false,
  "message": "That partner is not connected to you. A partner connects you by giving you a connection code to claim.",
  "code": "connection_not_found",
  "requestId": "3f0c9f8e-6a1d-4f5e-9b1a-2f1c0d9e7a41"
}

connection_not_found answers every partner you are not connected to in the same way, so it never confirms that an ID belongs to a real partner.

Effective scopes#

Each partner-scoped endpoint needs one scope, as in the Open Network API: REGISTRATION to create items, UPDATE to change or delete them, INVENTORY to read items and bookables, and PAYMENT for payment sessions. For you, the check uses the connection's effective scopes — what the partner granted that Localoy still allows you. See Effective scopes.

Response · 403
{
  "success": false,
  "message": "This partner has not granted you the UPDATE scope, which this endpoint requires.",
  "code": "open_network_scope_required",
  "details": {
    "requiredScope": "UPDATE",
    "grantedScopes": ["REGISTRATION", "INVENTORY"]
  },
  "requestId": "3f0c9f8e-6a1d-4f5e-9b1a-2f1c0d9e7a41"
}

details.grantedScopes holds the effective scopes. Do not retry: tell the partner which permission is missing. It can add a scope in its Partner Portal without a new code.

Verifying a key#

GET /ping accepts a provider key and needs no partner header:

Response · 200
{
  "success": true,
  "data": {
    "ok": true,
    "principal": "TECHNOLOGY_PROVIDER",
    "environment": "PRODUCTION",
    "keyPrefix": "ltp_live_r4t8wz3c",
    "provider": { "key": "example-pos", "name": "Example POS" }
  }
}

Send X-Localoy-Partner-Id as well and /ping checks that connection the way a partner-scoped call does — with the 400, 404 and 403 answers in the table above — though it needs no scope. For an active connection the response adds the partnerId, the connection's id and status, and your effective scopes for it: a quick check before a sync.

Response · 200 (with X-Localoy-Partner-Id)
{
  "success": true,
  "data": {
    "ok": true,
    "principal": "TECHNOLOGY_PROVIDER",
    "environment": "PRODUCTION",
    "keyPrefix": "ltp_live_r4t8wz3c",
    "provider": { "key": "example-pos", "name": "Example POS" },
    "partnerId": "cm1partnerid000000000000001",
    "connection": { "id": "cm7c0nn3ct10n00000000001", "status": "ACTIVE" },
    "scopes": ["REGISTRATION", "UPDATE", "INVENTORY"]
  }
}

When a key is refused#

A missing, malformed, unknown, revoked or expired key, or one with the wrong secret, gets one answer, whatever the reason:

Response · 401
{
  "success": false,
  "message": "Invalid or missing API key",
  "code": "open_network_key_invalid",
  "requestId": "3f0c9f8e-6a1d-4f5e-9b1a-2f1c0d9e7a41"
}

The response never says why, so it cannot help someone guessing keys. Compare the key's public prefix with the one Localoy gave you; if it still fails, send the requestId to your partnerships contact.

Errors#

CodeStatusMeaning
open_network_key_invalid401The key is missing, malformed, unknown, revoked or expired, or its secret is wrong.
provider_suspended403Localoy has suspended your company. Every key is refused until it resumes you.
provider_key_required403A partner key called a provider-only route: /connections… or /webhooks….
partner_id_required400A partner-scoped call has no X-Localoy-Partner-Id, or it is empty.
connection_not_found404The partner is not connected to you.
connection_paused403The partner has paused you.
open_network_scope_required403The connection's effective scopes lack the endpoint's scope.

Every provider error is listed in Errors.

Rotating a key without downtime#

Localoy issues and revokes your keys, so replacing one is a request to your partnerships contact:

  1. Ask for a second key in the same environment. You can hold up to 5 live keys in each.
  2. Deploy it everywhere the old key is used.
  3. Confirm that traffic has moved: GET /ping returns the new key's keyPrefix.
  4. Ask Localoy to revoke the old key. It stops working on its next request.

If a key has leaked, do not wait for a replacement: ask Localoy to revoke it at once.

Calling from a server only#

A provider key acts for every partner who connected you

Keep provider keys in your servers' secret store or environment variables, and send every request from your backend. Never put a key in a browser, a mobile app, a plugin or app you ship to partners, or a public repository. The API sends no CORS headers to arbitrary origins, so a browser page cannot call it.