Getting started
Signatures
Every call in both directions is signed with HMAC-SHA256 over a canonical string.
X-Timestamp: <unix seconds>
X-Request-Id: <8-128 of A-Z a-z 0-9 _ . : -> (your POSTs to us only)
X-Signature: hex( HMAC-SHA256( secret, canonical ) )
canonical = <label> \n <X-Timestamp> \n <METHOD> \n <path?query> \n <X-Request-Id or empty> \n <hex SHA-256 of the raw body>| Label | Used for |
|---|---|
| orrery-provider-v1 | Your calls to us |
| orrery-wallet-v1 | Our legs to your wallet |
| orrery-wallet-answer-v1 | Your wallet's answers, over the same path as the request |
A signature made for one direction, method, path, request id or body verifies for no other. A timestamp more than 120 s from our clock is refused. Each X-Request-Id is accepted once (409 DUPLICATE_REQUEST after that), and because it is signed a captured call cannot be replayed under a new id. A retry of a launch that timed out uses a new id and gets a new session.
Two secrets, which must differ: one signs your calls to us, the other our calls to your wallet. If your wallet signs its answers we check them, and an answer with a bad signature counts as no answer; once you sign every answer we can require it, and then an unsigned answer counts as no answer too.
Worked example#
Secret example-secret-0123456789abcdef0123456789, timestamp 1760961600. Both signatures below recompute from the canonical string above.
POST /provider/v1/sessions
X-Request-Id: a1b2c3d4e5f6a7b8c9d0e1f2
{"player_id":"p-42","operator_id":"op-7","currency":"EUR","platform":"mobile"}
X-Signature: 9b570dc8bdd65aede792e7a7cda3f21437343a43f759f7b3026f7de67edc08bd
GET /provider/v1/rounds/123
X-Signature: 25b430a9e9e4ec65aa13adaddf3838bae617db88f8f185c759b1b2c5450d6bf4Address allowlist
The /provider/* paths answer only your egress addresses: the proxy refuses others with 403 before the server, and the server checks the address again.