Connect your till to Encore

A REST API, one key per business, JSON. This takes ten minutes to read; the full reference is generated next door.

Full reference

Every field, every response, with a button to try it.

Getting started

Your customer creates a key from their account, under Integrations. The secret is shown once: if they lose it, they create another and revoke the old one.

Your first call

curl https://encore.ma/api/v1/programme \
  -H "Authorization: Bearer enc_xxxxxxxx_………"

Authentication

Send the key as `Authorization: Bearer`. The `X-API-Key` header works too. There is no session, no token to refresh and no `societe_id` to send: the key identifies the business, and nothing in your request can change it.

Scopes

Each key carries the list of what it may do. A till key does not need to read every member. A call outside its scope returns `403` with code `portee_absente` — which is different from an invalid key, which returns `401`.

  • membres.read
  • membres.write
  • mouvements.write
  • rachat
  • prepaye
  • referentiel.read

The location

Every action belongs to a location: that is what lets the merchant compare shops and follow their staff. If the key carries a single location, you have nothing to pass. If it carries several, add `site_id` — outside its scope, the call is refused.

A key with no location can read, never write an action: an action without a location would skew every figure the merchant relies on.

Idempotency

Every write requires an `Idempotency-Key` header of your choosing: your receipt number makes an excellent candidate. Replaying the same call with the same key never creates a second action — it returns the first, with `cree: false`.

curl -X POST https://encore.ma/api/v1/membres/42/mouvements \
  -H "Authorization: Bearer enc_xxxxxxxx_………" \
  -H "Idempotency-Key: ticket-2026-09-19-0187" \
  -H "Content-Type: application/json" \
  -d '{"quantite": 1}'

This is what lets you retry after a dropped connection without ever stamping twice. We do not invent it for you: two legitimate identical sales do happen, and only you know whether it is a replay.

Errors

Every refusal carries a machine `code` alongside its message. Read the code, show the message.

401 cle_invalide Key missing, unknown or revoked.
403 portee_absente The key exists but lacks this right.
403 chaine_inactive The business subscription is suspended.
422 Malformed request, or action refused by a rule (cap, cooldown).
429 trop_d_appels Too many calls: the `Retry-After` header says when to come back.

Webhooks

Rather than polling the API, give us an address: we call you when something happens. Eight events, as JSON `POST`.

The eight events

  • membre.cree
  • mouvement.ajoute
  • recompense.debloquee
  • recompense.rachetee
  • prepaye.vendu
  • prepaye.consomme
  • campagne.terminee
  • feedback.recu

Verify the signature

Every call carries `X-Encore-Timestamp` and `X-Encore-Signature`. Recompute the HMAC over `timestamp.raw_body` — the **exact** body you received, before any decoding.

$attendue = 'sha256=' . hash_hmac(
    'sha256',
    $request->header('X-Encore-Timestamp') . '.' . $request->getContent(),
    $votreSecret
);
hash_equals($attendue, $request->header('X-Encore-Signature'));

A failing call is retried five times, at growing intervals (1 min, 5, 30, 2 h, 6 h). After ten consecutive failures the address is suspended and your customer is told in their account.

A question?

Write to contact@encore.ma. Include your key prefix (`enc_…`): it is enough for us to find your calls, and it reveals nothing.