Appearance
Contract authority: OpenAPI is the machine-readable public v1 contract. This page is generated from the Privilege Integrator Pack. If prose and OpenAPI disagree, stop and contact Privilege.
3. Authentication
Wire format
http
Authorization: Basic base64(<clientKey>:<clientSecret>)| Role | Public name | Typical form |
|---|---|---|
| Username / client identifier | clientKey | starts with pic_ |
| Password / secret | clientSecret | starts with pcs_ |
These are Integration Client machine credentials — not Member, Partner App, or browser session tokens.
How merchants obtain credentials
Public API vs management UX
| Surface | Status |
|---|---|
https://dev.privilege.hr/api/integrations/v1 (validate / confirm / cancel / reverse) | Available in production |
| Merchant self-service (Partner Portal → Integrations) | Not available yet — coordinate with Privilege |
Today, vendors must coordinate credential and outlet-mapping provisioning with Privilege during onboarding. Privilege provisions an Integration Client for the agreed merchant/profile and shares clientKey / clientSecret securely (secret shown once). Merchant self-service for creating clients is not available yet — HTTP Basic with those credentials is the only supported auth for this API.
When Partner Portal → Integrations becomes available to merchants, the normal workflow will be:
- Company Admin opens Partner Portal → Integrations.
- Creates an Integration Client for the correct company/profile (operational company the POS serves).
- Privilege shows
clientKey+clientSecretonce. - Store the secret in your POS secure vault / HSM / server-side config.
Rules (apply regardless of who creates the client):
- Secret is shown once at create (and again only on rotate). It cannot be retrieved later.
- Store secrets server-side only. Never embed
clientSecretin browser, mobile apps, or public repos. - An Integration Client that is disabled (or not
enabled) cannot authenticate →403 CLIENT_DISABLED. - Wrong or unknown credentials →
401 UNAUTHENTICATED(generic message).
Required application scopes on the client (configured by Privilege at create; not OAuth):
redemptions:validateredemptions:confirmredemptions:cancelredemptions:reverse
Missing scope → 403 INSUFFICIENT_SCOPE.
Credential rotation (summary)
See §13 Credential rotation. Default grace for the previous secret is 24 hours (INTEGRATION_CREDENTIAL_ROTATION_GRACE_HOURS, default 24).
4. Outlet mapping
Your POS has its own stable outlet identifier. Privilege has its own outlets. They are linked by mapping:
text
POS externalOutletId ←→ Privilege Outlet- On every validate (and optionally on confirm/cancel), send your
externalOutletId. - Outlet mappings are configured in Privilege against that Integration Client (today: coordinated with Privilege during onboarding; later: Company Admin in Partner Portal → Integrations → locations/mappings when that UI is available).
- An Integration Client is bound to one operational company/profile. Mappings and redemptions for that client only apply inside that bound company. Credentials from Company A must not be used for Company B’s outlets.
Promotion mapping (POS-owned pricing)
Privilege does not send pricing instructions or basket/item eligibility rules. The POS owns % / fixed / B1G1 / SKU / stacking.
On successful validate, Privilege returns:
privilegePromotionId— stable public promotion identity (= Deal.id; map to your local POS promotion; not an authorization secret; not a pricing instruction)benefit: null— Privilege does not tell the till what amount or percent to apply
Configure the till so privilegePromotionId maps to a local promotion. An unknown/unconfigured mapping must not silently become a whole-basket discount — fail closed in the POS and cancel the reservation (or let TTL expire).
Supported authorized deal types: Percentage | Standard | B1G1. Privilege does not calculate their commercial benefit for POS. Stale aliases FixedAmount/BOGO and unknown types return OFFER_UNSUPPORTED and do not create a reservation.
Reservations without a frozen privilegePromotionId: cancel is allowed; validate replay / confirm return OFFER_SNAPSHOT_MISSING — cancel and re-validate.
Fictional example
| Side | Value |
|---|---|
| Merchant profile | “Demo Café Zagreb” (Privilege company/profile) |
| POS till id | store-zg-01-till-3 |
| Privilege outlet | “Demo Café — Ilica” |
| Mapping | externalOutletId=store-zg-01-till-3 → that Privilege outlet |
| Local POS promo | PRIV-FOOD-PROMO ↔ privilegePromotionId from validate |
Unmapped outlet → 404 OUTLET_UNMAPPED. Disabled mapping → 403 OUTLET_DISABLED (validate path).
13. Credential rotation
Rotation creates a new clientSecret (shown once). The previous secret remains usable only during rotation grace (default 24 hours, INTEGRATION_CREDENTIAL_ROTATION_GRACE_HOURS). After grace, the old secret stops authenticating. During grace, at most two secrets may authenticate (active + rotated-in-grace). Plan POS cutover inside that window. Disabling the Integration Client blocks all secrets for that client.
Today, request rotation through Privilege support/onboarding.
When Partner Portal → Integrations is available to merchants, the workflow will be:
- Partner Portal → Integrations → open the integration
- Generate new Secret (rotate)
- Copy the new
clientSecret(shown once) into the POS secure config - Verify validate/confirm with the new secret
- Complete cutover before grace ends
