Duplicates are success
Same transaction payload and same identity returns a duplicate receipt.
Developer documentation
A workflow-first integration guide for licensed operators reporting transactions, tax details, device state, reconciliation totals, responsible-gaming events, corrections, and daily manifest attestations.
Quickstart
Operators report continuously over HTTPS. RegulaView accepts signed source events, deduplicates retries, validates the stream, reconciles independent totals, and seals each reporting day into a manifest.
Exchange issued client credentials for a short-lived access token and cache it until close to expiry.
Use the key for the UTC day of the transaction timestamp.
Send every wager, payout, void, refund, adjustment, deposit, and withdrawal.
Heartbeat devices, submit responsible-gaming events, and send cashier or payment-provider totals.
Submit aggregate tax details after the business day closes.
Use correction requests for after-the-fact changes instead of altering accepted events.
After the day is sealed, sign the Merkle root with the same daily key.
Environments and versioning
| Environment | Base URL | Purpose |
|---|---|---|
| Sandbox | https://sandbox.regulaview.io | Integration testing and certification rehearsal. |
| Production | https://api.regulaview.io | Live regulatory reporting. |
URL versioning is canonical. All endpoints in this guide use /v1. The optional
X-RegulaView-Api-Version: 1.0 header is accepted for client tooling metadata, but the URL segment is the source of truth.
Authentication
Each operator receives a client ID, client secret, and scopes during onboarding. The bearer token identifies the licensed entity and scopes every subsequent request.
POST /v1/auth/token HTTP/1.1
Host: api.regulaview.io
Content-Type: application/json
X-Correlation-Id: op-token-20260430-0001
{
"clientId": "<your-client-id>",
"clientSecret": "<your-client-secret>",
"grantType": "client_credentials"
}
{
"accessToken": "eyJhbGciOi...",
"tokenType": "Bearer",
"expiresIn": 3600,
"scope": "ingest:write read:own"
}
| Scope | Allows |
|---|---|
ingest:write | Transactions, tax declarations, cashier totals, heartbeats, corrections, responsible-gaming events, signing-key retrieval, and manifest attestation. |
read:own | Operator-scoped transactions, devices, tax summaries, cashier rows, corrections, policies, and manifests. |
read:all | Regulator or administrator read access. Normal operator clients are not issued this scope. |
Headers and data formats
| Header | Required | Applies to | Description |
|---|---|---|---|
Authorization | Yes | All authenticated endpoints | Bearer <accessToken> from the token endpoint. |
Content-Type | Yes for bodies | POST endpoints | Use application/json. |
Idempotency-Key | Strongly recommended | Single transaction ingest | Stable retry key for one immutable transaction submission. |
X-RegulaView-Signature | Yes in production and certification | Single transaction ingest | Lowercase hex HMAC-SHA256 over the canonical transaction string. |
X-Correlation-Id | No | All endpoints | Client trace identifier echoed in error payloads and logs. |
| Type | Format |
|---|---|
| GUID | Standard UUID string. |
| Date/time | ISO 8601 UTC, for example 2026-04-30T12:34:56Z. |
| Date only | yyyy-MM-dd. |
| Money | JSON number with currency in a separate ISO 4217 field. |
| Enum | String enum name in JSON. Numeric enum values are used only inside the transaction signing string. |
Transaction signing
Retrieve one daily key per UTC reporting day, then sign every transaction with the key for
that transaction's occurredAtUtc day. Single submissions carry the signature in
X-RegulaView-Signature; batch submissions carry signature on each item.
GET /v1/integrity/manifests/2026-04-30/signing-key HTTP/1.1
Authorization: Bearer <accessToken>
{
"day": "2026-04-30",
"keyId": "manifest-20260430",
"secretBase64": "<daily-operator-hmac-secret>",
"algorithm": "HMAC-SHA256",
"validFromUtc": "2026-04-30T00:00:00Z",
"validToUtc": "2026-05-01T00:00:00Z"
}
{keyId}|{deviceIdentity}|{externalId}|{type:int}|{product:int}|{amount:F4}|{currency}|{occurredAtUnixMs}|{chainReference}|{correlationId}
Use deviceExternalId as the device identity when present. Format amounts with four decimal places,
use UTC Unix milliseconds for timestamps, and leave empty segments for missing optional values.
| Transaction type | Signing value | Common product | Signing value |
|---|---|---|---|
Wager | 0 | OnlineCasino | 0 |
Payout | 1 | PhysicalCasino | 1 |
Adjustment | 2 | RetailGambling | 2 |
Void | 3 | SportsBetting | 3 |
Refund | 4 | Lotto | 5 |
Deposit | 5 | GamingMachine | 9 |
Withdrawal | 6 | Other | 99 |
const crypto = require("crypto");
function signTransaction(key, tx) {
const type = { Wager: 0, Payout: 1, Adjustment: 2, Void: 3, Refund: 4, Deposit: 5, Withdrawal: 6 }[tx.type];
const product = { OnlineCasino: 0, PhysicalCasino: 1, RetailGambling: 2, SportsBetting: 3, VirtualGames: 4, Lotto: 5, InstantWin: 6, Keno: 7, Bingo: 8, GamingMachine: 9, Jackpot: 10, ParimutuelRacing: 11, MobileGambling: 12, Poker: 13, VirtualSports: 14, ScheduledGames: 15, Other: 99 }[tx.product ?? "Other"];
const canonical = [
key.keyId,
tx.deviceExternalId ?? "",
tx.externalId,
type,
product,
Number(tx.amount).toFixed(4),
tx.currency,
new Date(tx.occurredAtUtc).getTime(),
tx.chainReference ?? "",
tx.correlationId ?? ""
].join("|");
return crypto.createHmac("sha256", Buffer.from(key.secretBase64, "base64"))
.update(canonical, "utf8")
.digest("hex");
}
Ingestion
Send each wager, payout, void, refund, adjustment, deposit, and withdrawal as a distinct event.
Use your own stable externalId for the transaction and deviceExternalId for the source device.
POST /v1/ingest/transactions HTTP/1.1
Host: api.regulaview.io
Authorization: Bearer <accessToken>
Content-Type: application/json
Idempotency-Key: 8c8a6a5b-6c37-4f1a-89c6-6264de4663c0
X-RegulaView-Signature: <lowercase-hex-hmac>
X-Correlation-Id: tx-OP-20260430-000001
{
"externalId": "OP-20260430-000001",
"deviceExternalId": "shop-014-terminal-02",
"type": "Wager",
"amount": 5.00,
"currency": "EUR",
"occurredAtUtc": "2026-04-30T10:30:00Z",
"product": "Lotto",
"chainReference": "TICKET-20260430-A1B2",
"correlationId": "ticket-processor-7"
}
{
"receipt": {
"transactionId": "f4c1a3d2-3b61-4a8b-a9cb-65258c03c503",
"externalId": "OP-20260430-000001",
"status": "accepted",
"payloadHash": "6e8c...",
"idempotencyKey": "8c8a6a5b-6c37-4f1a-89c6-6264de4663c0",
"location": "/v1/transactions/f4c1a3d2-3b61-4a8b-a9cb-65258c03c503",
"message": null
}
}
| Field | Required | Rules |
|---|---|---|
externalId | Yes | Unique per operator for one immutable transaction event. Maximum 64 characters. |
deviceExternalId | No | Recommended for events from a device, terminal, outlet server, or gaming system. Maximum 128 characters. |
type | Yes | Wager, Payout, Adjustment, Void, Refund, Deposit, or Withdrawal. |
amount | Yes | Non-negative decimal. Economic sign is derived from type. |
currency | Yes | ISO 4217 three-letter code. |
occurredAtUtc | Yes | UTC event time from the operator system. |
product | No | Defaults to Other if omitted. |
chainReference | No | Recommended link between lifecycle events, such as wager to payout or void. |
Batch and retry
The batch endpoint accepts up to 5000 transactions. Preserve the original occurredAtUtc,
sign each item individually, and put per-item idempotencyKey values in the request body.
POST /v1/ingest/transactions/batch HTTP/1.1
Authorization: Bearer <accessToken>
Content-Type: application/json
{
"transactions": [
{
"externalId": "OP-20260430-000002",
"deviceExternalId": "shop-014-terminal-02",
"type": "Wager",
"amount": 10.00,
"currency": "EUR",
"occurredAtUtc": "2026-04-30T12:35:01Z",
"product": "SportsBetting",
"idempotencyKey": "OP-20260430-000002",
"signature": "<lowercase-hex-hmac>"
}
]
}
Same transaction payload and same identity returns a duplicate receipt.
A reused idempotency key or external ID with different payload data returns conflict.
Retry transient 5xx, 429, and timeouts with jitter and the original payload.
Daily tax declarations
Transaction reporting is real time. Tax declarations are the operator's daily aggregate statement, submitted after the reporting day closes. A declaration for the same day replaces the previous declaration inside the accepted window, making late changes explicit and auditable.
POST /v1/tax/declarations HTTP/1.1
Authorization: Bearer <accessToken>
Content-Type: application/json
{
"day": "2026-04-30",
"grossWagers": 125000.00,
"payouts": 91000.00,
"declaredTax": 5100.00
}
{
"day": "2026-04-30",
"grossWagers": 125000.00,
"payouts": 91000.00,
"netRevenue": 34000.00,
"calculatedTax": 5100.00,
"declaredTax": 5100.00,
"variance": 0.00
}
Cashier reconciliation
Reconciliation totals give the regulator an independent ground-truth feed to compare against transaction-derived cash-in and cash-out activity.
POST /v1/recon/cashier-totals HTTP/1.1
Authorization: Bearer <accessToken>
Content-Type: application/json
{
"day": "2026-04-30",
"cashIn": 48000.00,
"cashOut": 36500.00,
"outletReference": "SHOP-014",
"source": "cashier-close-v2"
}
Devices and responsible gaming
Heartbeats show whether the reporting estate is alive. Responsible-gaming events surface policy triggers and high-risk patterns for regulatory review.
POST /v1/devices/external/terminal-alpha-07/heartbeat HTTP/1.1
Authorization: Bearer <accessToken>
Content-Type: application/json
{
"configurationVersion": "2026.04.30.1",
"configurationHash": "b6e4f8b7266f4d2e998c7f2a0f1be75c",
"gameEnabled": true,
"health": "Healthy"
}
POST /v1/rg/events HTTP/1.1
Authorization: Bearer <accessToken>
Content-Type: application/json
{
"type": "LimitBreach",
"severity": "High",
"deviceExternalId": "terminal-alpha-07",
"pseudonymousPlayerRef": "player-hash-91b2",
"summary": "Daily loss threshold breached",
"evidence": "loss=500;threshold=500;currency=EUR"
}
Corrections
Corrections create a reviewed delta record. They do not mutate the original accepted transaction or the manifest that sealed it.
POST /v1/corrections HTTP/1.1
Authorization: Bearer <accessToken>
Content-Type: application/json
{
"originalExternalId": "OP-20260430-000001",
"reason": "Operator settlement system corrected payout amount after manual review.",
"payloadDiff": [
{
"path": "/amount",
"from": 5.00,
"to": 4.50,
"reason": "Manual settlement review corrected the amount."
}
]
}
Daily attestation
After the platform seals the day's hash-chain entries into a Merkle manifest, retrieve the manifest, compute the attestation HMAC, and submit it within the jurisdiction's attestation window.
{merkleRoot}|{day:yyyy-MM-dd}|{operatorId:N}
POST /v1/integrity/manifests/2026-04-30/attest
Authorization: Bearer <accessToken>
Content-Type: application/json
{
"merkleRoot": "a803...b1",
"signature": "5e7d...a4"
}
The server signs the manifest to prove platform custody. The operator countersigns it to acknowledge that the sealed root matches the operator-facing reporting record.
Endpoint reference
/v1/auth/tokenIssue an access token.
/v1/operator-onboarding/meRead authenticated operator profile details.
/v1/integrity/manifests/{day}/signing-keyRetrieve the daily HMAC key.
/v1/ingest/transactionsSubmit one signed transaction.
/v1/ingest/transactions/batchSubmit up to 5000 signed transactions.
/v1/transactionsRead operator-scoped transaction records.
/v1/devicesRead mapped operator devices.
/v1/devices/external/{deviceExternalId}/heartbeatReport device liveness.
/v1/tax/declarationsSubmit daily aggregate tax details.
/v1/taxRead tax summaries and variance.
/v1/recon/cashier-totalsSubmit independent cashier totals.
/v1/correctionsAppend an after-the-fact correction request.
/v1/rg/eventsSubmit responsible-gaming events.
/v1/integrity/manifestsList daily manifests.
/v1/integrity/manifests/{day}/attestCountersign the daily manifest.
Errors
Errors use a standard problem envelope with errorCode, message, status,
correlationId, requestId, and timestampUtc. Quote the correlation and request IDs in support cases.
{
"type": "idempotency_conflict",
"title": "Idempotency key conflict",
"status": 409,
"detail": "The same Idempotency-Key was already used with a different transaction payload.",
"correlationId": "op-2026-04-30-000001",
"requestId": "0HMT...",
"timestampUtc": "2026-04-30T12:34:56Z",
"errors": null
}
| HTTP | Code | Meaning |
|---|---|---|
| 400 | signature_required | Transaction signing is required in this environment. |
| 400 | signature_source_mismatch | Header and body signatures were both supplied but differ. |
| 400 | signature_invalid | The calculated transaction or attestation HMAC did not validate. |
| 400 | no_signing_key | No daily key has been issued for the transaction day. |
| 409 | idempotency_conflict | The idempotency key was reused for different payload data. |
| 409 | duplicate_external_id_conflict | The transaction external ID was reused for different payload data. |
| 422 | timestamp_out_of_range | The transaction timestamp is outside the acceptance window. |
| 429 | rate_limited | The caller exceeded the configured rate limit. |
Rate limits
The defaults below describe the sandbox and certification environment used during integration testing. Production limits are agreed during operator onboarding and may differ based on certified throughput and regulatory requirements.
| Policy | Sandbox default | Partition | Applies to |
|---|---|---|---|
token | 60 requests/minute | Source IP | Access-token issuance. |
ingest | 6000 requests/minute | Authenticated operator identity | Transactions, batches, heartbeats, corrections, recon, signing-key retrieval, and attestation. |
read | 600 requests/minute | Authenticated operator identity | Operator-scoped queries and integrity reads. |
anonymous | 120 requests/minute | Source IP | Unauthenticated status and public policy reads. |
Certification checklist
OpenAPI
Use this guide for integration behavior and the OpenAPI document for schema validation, client generation, Postman imports, and automated contract checks. Swagger is reference tooling; this page is the operator integration guide.