# NewWorld Provider API v1 — partner integration sandbox One integration, one base URL, many game IDs. Each website receives its OWN Key ID and secret from NewWorld Backoffice. Never use the internal game service key. API base in this package: https://api.nw0007.com/provider/v1 All operations below are POST with a JSON object. Backend-to-backend only. ## Authentication Headers: X-NW-Key-Id, X-NW-Timestamp (13-digit Unix milliseconds), X-NW-Nonce (unique UUID), X-NW-Signature (HMAC-SHA256 lowercase hex). Sign the exact UTF-8 bytes of these five lines, with four LF separators and NO final LF: POST /provider/v1/games TIMESTAMP NONCE EXACT_JSON_BODY Timestamp tolerance 30 seconds. Nonces are persisted and rejected on replay. Use a fresh nonce/timestamp for a new request; retain round transaction identity when retrying gameplay. Error responses: {error:string}, HTTP 400 invalid input, 401 auth failure, 403 scope/disabled, 404 missing, 409 replay, 500 server error. Secret never goes to browser, query string, logs or shared ZIP. Runnable dependency-free Node.js client: ExampleWebsite/client.mjs. Key rotation/revocation is managed in Backoffice. Revocation invalidates bound player sessions and unused launch tickets. Website identity derives from key, not a caller-supplied website ID. Owner cookies never substitute for website keys. ## Operations - `games` body `{}` => `{currency:"DEMO",games:[{gameId,name,version}]}`. Only enabled, assigned games. Fetch on lobby load; new allowed games appear without another integration. Internal service secrets/URLs are not in catalog. - `launch` body `{gameId:"night-market",playerId:"player123",currency:"DEMO"}` => `{gameId,launchUrl,expiresIn:120,currency}`. Redirect player to launchUrl. Website must authenticate its player BEFORE requesting launch. The returned link is a short-lived credential; do not log/share it. The ticket is consumed once on entry; get a new link for the SAME player if entry fails. Creating the link does not debit or start a round. Unknown/unassigned/disabled games rejected. - `balance` body `{playerId:"player123"}` => `{playerId,currency,balanceMinor}`. Call player-create first. One sandbox wallet per website+player across games. Unknown player returns 404, not an invented zero balance. - `rounds` body `{playerId?,gameId?,from?,to?,limit?:50,offset?:0}` => `{currency,limit,offset,total,rows:[{playerId,gameId,roundId,debitMinor, creditMinor,balanceMinor,profile,createdAt}]}`. Limit 1–100. Settled ledger only. Offset pagination is for local review; active concurrent traffic can shift pages. - `summary` same filters except pagination => `{currency,rounds,wagerMinor, payoutMinor,ggrMinor,observedRtp}`. GGR=wager-payout; includes free-spin winnings. Observed RTP is null when wager=0, not a configured target or guaranteed profit. Dates: UTC `YYYY-MM-DDTHH:mm:ss.sssZ`; from inclusive, to exclusive. Without dates, legacy undated rows are included; date filters exclude unknown timestamps. Reports never include another website, even when a playerId is shared. Amounts are integer minor units; 100 minor units = 1 DEMO credit. All records DEMO. No FX mixing. This is NOT MMK/USD accounting. Settled history stays reportable even if a game assignment is disabled. Pending recovery is in owner Backoffice. ## Transfer wallet (implemented, DEMO only) - player-create: {playerId,currency:"DEMO"} => {playerId,currency,balanceMinor}; starts at zero, idempotent. - transfer-in / transfer-out: {transactionId,playerId,currency:"DEMO",amountMinor} => receipt. - transfer-status: {transactionId} => original receipt or 404. - reconcile: {playerId} => openingMinor, transferInMinor, transferOutMinor, wagerMinor, payoutMinor, balanceMinor, expectedMinor, differenceMinor, pendingRound, currency, playerId. transactionId: 8–100 ASCII letters/digits/_/-. Unique per website, across both directions. amountMinor: integer 1..1,000,000,000,000. 100 minor = 1 DEMO. Receipt: transactionId,playerId,currency,direction,amountMinor,status,balanceMinor,createdAt, optional reason. status: completed or rejected. Rejected is a final durable receipt, not a pending request. Exact business retry returns original receipt. Changed payload with same ID =>409. Every HTTP retry requires NEW authentication nonce and timestamp, SAME transactionId/payload. Pending game round blocks transfers (409); active free spins block transfer-out (409). Website must reserve funds durably before transfer-in, finalize on completed, refund only on confirmed rejected. Credit website wallet once on completed transfer-out. Store durable website-side journal. Timeout/unknown result: keep funds reserved, query status, retry original ID. 404 is not proof of failure. expectedMinor = openingMinor + transferInMinor - transferOutMinor - wagerMinor + payoutMinor. differenceMinor must equal zero; pendingRound flags an unresolved settlement. A receipt balance is a historical snapshot. Use balance for current balance. ## Online services - API: https://api.nw0007.com/provider/v1 - Docs: https://docs.nw0007.com - Backoffice: https://admin.nw0007.com (separate private login) - Example website: https://api.nw0007.com/sandbox - Public game demo remains separate: https://demo.nw0007.com Example website starts with 1,000 DEMO in its own wallet; game wallet starts at zero. Transfer In 200 -> Play -> browser Back -> Transfer Out -> reconciliation. Signed browser cookie is test identity, not production customer authentication. Owner creates website, assigns game, issues API key and optional scoped report login. Secrets stay backend/private. HTTPS routes never expose internal service endpoints. Not implemented: real-money operation, seamless-wallet callbacks, configurable return_url, certification.