nArtifacts

API

A clean API for your platform.

Link our games to your platform and your wallet. Every call is named for what it does. Every field has a reason.

Tell us what you needWe send you a price.
Start a game: one call
POST /v1/session.start
{
  "requestId": "rq-77120",
  "playerId": "p-82731",
  "gameId": "mines",
  "currency": "EUR",
  …
}

→ {
  "ok": true,
  "result": {
    "url": "https://play.nartifacts.com/…"
  }
}

At a glance

The facts a developer needs.

AddressLivehttps://api.nartifacts.com/v1/Sandboxhttps://sandbox.api.nartifacts.com/v1/
CallsEvery call is a POST with JSON. Each is named for what it does.
SigningKey pairs, both ways. ECDSA P‑256 with SHA‑256.
HeadersKey-Id Environment Sent-At Signature
RepeatsOne requestId per change. Sent twice, done once.
Answersok, then result or error.code. Always a traceId.
Wallet timeoutswallet.balance: 3 seconds. Every other call: 5 seconds.
Limits20 calls a second in Sandbox. 200 in Live.
AppsWeb, iOS, Android, React Native and Flutter.

How it works

Seven calls on your side.

Your platform starts a game. We run it on the player's screen. We call your wallet for every round, and tell you when the session closes.

1
call to start a game
session.start
5
wallet calls on your server
wallet.balancewallet.stakewallet.winwallet.losswallet.refund
1
address for events
session.closed
Player's screenYour platformnnArtifactssession.startgame linkopen the linkwallet.balancegame.loadedthe player betswallet.stakewallet.win/losssession.closed
A callAn answerCalls you answer

What you get

Clean by design.

Named calls

Every call says what it does. The version is in the address.

Safe to send again

Send a change twice, and it happens once.

Clear sessions

Active or closed. Every close says who closed it, and why.

Every round ends

Every round reaches a final state. No bet is left without a result.

Many test environments

Live, plus as many sandboxes as you need: staging, UAT, one per branch.

Signed both ways

Key pairs on both sides. No secret is ever shared.

Support built in

Find any round, replay it, and see every wallet call.

Your team

Invite people as owners or members. Enterprise: SSO on request.

Live when you are ready

Test in Sandbox. Ask for Live when your wallet passes every check.

Starting a game

How a game starts.

  1. Your server calls session.start.With the player, the game and the bet settings.
  2. We answer with a game link.With our sessionId, and the time the link expires.
  3. You open the link.In your web site, or in a web view in your iOS or Android app.
  4. Our server calls your wallet.For the balance first. Then a stake, and a win or a loss, for every round.

The game link works once, and must be opened within 2 minutes. A copied link can't be used to play with your player's money.

session.start
POST /v1/session.start
{
  "requestId": "rq-77120",
  "firstSentAt": "2026-10-31T09:02:10Z",
  "playerId": "p-82731",
  "casinoSessionId": "c-5531",
  "gameId": "mines",
  "currency": "EUR",
  "language": "en",
  "market": "UK",
  "betSettings": {
    "min": 10, "max": 10000, "default": 100
  },
  "exitUrl": "https://casino.example/lobby"
}

→ {
  "ok": true,
  "result": {
    "sessionId": "s-01JC8Z…",
    "url": "https://play.nartifacts.com/s/s-01JC8Z…",
    "linkExpiresAt": "2026-10-31T09:04:11Z"
  },
  "traceId": "tr-01JC…"
}

Your wallet

Five calls on your server.

You build five calls at your server address. Our server calls them. Your balance is the only balance.

CallWe send it when
wallet.balanceThe game opens.
wallet.stakeA round starts.
wallet.winA round ends with a win.
wallet.lossA round ends with no win.
wallet.refundA stake had no answer in time.

A stake with no answer in time is refunded. A win, a loss or a refund is sent again with the same transactionId until you accept it. Nothing is paid twice, and nothing is lost.

Not accepted after 1 hour? It goes on your stuck list, and we email the owners of your account.

wallet.balance must answer within 3 seconds. Every other call within 5 seconds.

wallet.stake
POST {your server}/v1/wallet.stake
{
  "transactionId": "t-01JC90…",
  "roundId": "r-01JC90…",
  "sessionId": "s-01JC8Z…",
  "casinoSessionId": "c-5531",
  "playerId": "p-82731",
  "gameId": "mines",
  "amount": 100,
  "currency": "EUR",
  "traceId": "tr-01JC…"
}

→ { "ok": true, "result": { "balance": 24900 } }

Sessions

Active or closed. Nothing else.

A session is one player playing one game. Our server owns it. A closed session never opens again.

WhoReason
casinoyour own text, e.g. logout
playerexit
systemnot_opened
systemidle
systemreplaced
systemenvironment_deleted

Every close is sent to your server as session.closed, with who closed it and why. Your session and ours never drift apart.

We send it again until you accept it, for up to 30 days.

activeclosed
session.closed
POST {your server}/v1/session.closed
{
  "eventId": "e-01JC9A…",
  "sessionId": "s-01JC8Z…",
  "casinoSessionId": "c-5531",
  "playerId": "p-82731",
  "closedBy": "system",
  "reason": "idle",
  "openRoundId": "r-01JC90Z8",
  "startedAt": "2026-10-31T09:02:11Z",
  "openedAt": "2026-10-31T09:02:13Z",
  "closedAt": "2026-10-31T09:47:30Z"
}

Rounds

Every round ends.

A round is one spin, or one Mines game from the bet to collect or a mine.

A state ending in -ing waits for your wallet's answer. Every round reaches a final state: ended, declined or refunded.

A slot round goes from staking straight to ending. Only a Mines round is open, while the player picks tiles.

A result that exists is always paid. A round is refunded only if no result was made.

Free spins are part of the round that won them: one bet, one win. The round shows the paid spin's win, the number of free spins, and what they won.

A Mines round left open finishes by itself after 24 hours. The player gets what they collected so far. It is never a loss.

Stake accepted
stakingopenendingended
Stake refused
stakingdeclined
No answer to the stake
stakingrefundingrefunded
Waits for your walletFinal

Every call

The whole API on one page.

You call us

→You → us
  • games.listYour games, their images and the settings you chose.
  • session.startStarts a game for a player. Returns the game link.
  • session.updateBetSettingsChanges a player's bet settings during play.
  • session.closeCloses a session.
  • sessions.closeCloses all of a player's sessions. For example, when a player excludes themselves.
  • session.getOne session: its state, times and totals.
  • round.getOne round: its bet, its win, its free spins and every wallet call.
  • rounds.listA player's rounds, by time and state.
  • money.listEvery bet, win and refund in your account, by time. For your finance system.

We call your wallet

→We → you
  • wallet.balanceGets the player's balance.
  • wallet.stakeTakes the bet when a round starts.
  • wallet.winPays a win.
  • wallet.lossTells you a round ended with no win.
  • wallet.refundGives a bet back when a stake had no answer.

We tell your server

→We → you
  • session.closedA session closed: who closed it, and why.

Your environments

→You → us

Sandbox only. By hand, or from your build pipeline.

  • environment.createA new environment, with your server address. It can copy another one.
  • environment.updateChanges its server address or its settings.
  • environment.deleteDeletes an environment. Its sessions close. Wins still owed are still sent.
  • environments.listAll your environments and their settings.

The game and your app

⇄Game ⇄ your app

In your web site, and in iOS, Android, React Native and Flutter apps.

  • game.loadedThe game is on screen. Hide your loading screen.
  • game.failedThe link was used or expired: start a new session. The session closed: go back to the lobby.
  • balance.changedThe balance changed. Show the new one.
  • player.exitThe player pressed exit. Close the game.
  • balance.refreshYou tell the game the player added money.

Answers

One shape for every answer.

Your code checks ok, and acts on a fixed list of error codes, never on text.

Each error code comes with what to do next.

traceId finds every call and retry that one action caused, on both sides.

Every call, both ways, is signed with the sender's private key. A call older than 5 minutes is refused.

Every answer
{ "ok": true,
  "result": { … },
  "traceId": "tr-01JC…" }

{ "ok": false,
  "error": {
    "code": "session_closed",
    "message": "This session is closed."
  },
  "traceId": "tr-01JC…" }

API keys

Your keys, in your back office.

Create API keys in your back office. Each key pair is made in your browser. You keep the private key. We keep only the public key.

Each key has a name, the environments it may use, what it can do, and the IP addresses it may call from. It can play, manage environments, or read money.

On Live, every key needs its IP addresses.

To change a key: create a new one, move your servers to it, then delete the old one.

See everything the back office does.

A signed call
POST /v1/session.start
Key-Id: key_7Hq2Xc9LpQ
Environment: staging
Sent-At: 2026-10-31T12:20:00Z
Signature: MEUCIQD3…

{ "requestId": "r-01JC9B…",
  "firstSentAt": "2026-10-31T12:20:00Z", … }

Going live

From Sandbox to Live.

  1. Build your five wallet calls.And the session.closed address.
  2. Run the wallet test run in Sandbox.We call your wallet with test players and test money, and check each rule.
  3. Ask for Live.Tell us what you need: games, markets, players.
  4. We send you a price.After you pay, we turn on Live and email you.

Live has real players and real money. Nothing is copied from Sandbox: you create new API keys for Live.

Limits

Clear limits, clear answers.

Each account may make 20 calls a second in Sandbox, and 200 in Live. It may create 100 environments an hour.

A call over a limit gets rate_limited, with retryAfter in seconds. Wait that long, then send the call again.

A refused call does not count. session.close and sessions.close never count, so a player can always be closed.

Our calls to your wallet never count against your limits. Live limits can be raised.

Over a limit
HTTP 429

{ "ok": false,
  "error": {
    "code": "rate_limited",
    "message": "Too many calls.",
    "retryAfter": 2
  },
  "traceId": "tr-01JC…" }

Link our games.

Tell us what you need. We send you a price.

contact@nartifacts.com
nArtifacts

API

A clean API for your platform.

Link our games to your platform and your wallet. Every call is named for what it does. Every field has a reason.

Tell us what you needWe send you a price.
Start a game: one call
POST /v1/session.start
{
  "requestId": "rq-77120",
  "playerId": "p-82731",
  "gameId": "mines",
  "currency": "EUR",
  …
}

→ {
  "ok": true,
  "result": {
    "url": "https://play.nartifacts.com/…"
  }
}

At a glance

The facts a developer needs.

AddressLivehttps://api.nartifacts.com/v1/Sandboxhttps://sandbox.api.nartifacts.com/v1/
CallsEvery call is a POST with JSON. Each is named for what it does.
SigningKey pairs, both ways. ECDSA P‑256 with SHA‑256.
HeadersKey-Id Environment Sent-At Signature
RepeatsOne requestId per change. Sent twice, done once.
Answersok, then result or error.code. Always a traceId.
Wallet timeoutswallet.balance: 3 seconds. Every other call: 5 seconds.
Limits20 calls a second in Sandbox. 200 in Live.
AppsWeb, iOS, Android, React Native and Flutter.

How it works

Seven calls on your side.

Your platform starts a game. We run it on the player's screen. We call your wallet for every round, and tell you when the session closes.

1
call to start a game
session.start
5
wallet calls on your server
wallet.balancewallet.stakewallet.winwallet.losswallet.refund
1
address for events
session.closed
Player's screenYour platformnnArtifactssession.start1game link2open the link3wallet.balance4game.loaded5the player bets6wallet.stake7wallet.win/loss8session.closed9
A callAn answerCalls you answer

What you get

Clean by design.

Named calls

Every call says what it does. The version is in the address.

Safe to send again

Send a change twice, and it happens once.

Clear sessions

Active or closed. Every close says who closed it, and why.

Every round ends

Every round reaches a final state. No bet is left without a result.

Many test environments

Live, plus as many sandboxes as you need: staging, UAT, one per branch.

Signed both ways

Key pairs on both sides. No secret is ever shared.

Support built in

Find any round, replay it, and see every wallet call.

Your team

Invite people as owners or members. Enterprise: SSO on request.

Live when you are ready

Test in Sandbox. Ask for Live when your wallet passes every check.

Starting a game

How a game starts.

  1. Your server calls session.start.With the player, the game and the bet settings.
  2. We answer with a game link.With our sessionId, and the time the link expires.
  3. You open the link.In your web site, or in a web view in your iOS or Android app.
  4. Our server calls your wallet.For the balance first. Then a stake, and a win or a loss, for every round.

The game link works once, and must be opened within 2 minutes. A copied link can't be used to play with your player's money.

session.start
POST /v1/session.start
{
  "requestId": "rq-77120",
  "firstSentAt": "2026-10-31T09:02:10Z",
  "playerId": "p-82731",
  "casinoSessionId": "c-5531",
  "gameId": "mines",
  "currency": "EUR",
  "language": "en",
  "market": "UK",
  "betSettings": {
    "min": 10, "max": 10000, "default": 100
  },
  "exitUrl": "https://casino.example/lobby"
}

→ {
  "ok": true,
  "result": {
    "sessionId": "s-01JC8Z…",
    "url": "https://play.nartifacts.com/s/s-01JC8Z…",
    "linkExpiresAt": "2026-10-31T09:04:11Z"
  },
  "traceId": "tr-01JC…"
}

Your wallet

Five calls on your server.

You build five calls at your server address. Our server calls them. Your balance is the only balance.

CallWe send it whenYou answer
wallet.balanceThe game opens.The balance.
wallet.stakeA round starts.The new balance, or a refusal code.
wallet.winA round ends with a win.The new balance.
wallet.lossA round ends with no win.Accepted.
wallet.refundA stake had no answer in time.The new balance.

A stake with no answer in time is refunded. A win, a loss or a refund is sent again with the same transactionId until you accept it. Nothing is paid twice, and nothing is lost.

Not accepted after 1 hour? It goes on your stuck list, and we email the owners of your account.

wallet.balance must answer within 3 seconds. Every other call within 5 seconds.

wallet.stake
POST {your server}/v1/wallet.stake
{
  "transactionId": "t-01JC90…",
  "roundId": "r-01JC90…",
  "sessionId": "s-01JC8Z…",
  "casinoSessionId": "c-5531",
  "playerId": "p-82731",
  "gameId": "mines",
  "amount": 100,
  "currency": "EUR",
  "traceId": "tr-01JC…"
}

→ { "ok": true, "result": { "balance": 24900 } }

Sessions

Active or closed. Nothing else.

A session is one player playing one game. Our server owns it. A closed session never opens again.

WhoReasonWhen
casinoyour own text, e.g. logoutYou call session.close.
playerexitThe player pressed exit in the game.
systemnot_openedThe game link was not opened within 2 minutes.
systemidleNo player action for 30 minutes.
systemreplacedYou allow one session per player, and the player started a new one.
systemenvironment_deletedYou deleted the environment.

Every close is sent to your server as session.closed, with who closed it and why. Your session and ours never drift apart.

We send it again until you accept it, for up to 30 days.

activeclosed
session.closed
POST {your server}/v1/session.closed
{
  "eventId": "e-01JC9A…",
  "sessionId": "s-01JC8Z…",
  "casinoSessionId": "c-5531",
  "playerId": "p-82731",
  "closedBy": "system",
  "reason": "idle",
  "openRoundId": "r-01JC90Z8",
  "startedAt": "2026-10-31T09:02:11Z",
  "openedAt": "2026-10-31T09:02:13Z",
  "closedAt": "2026-10-31T09:47:30Z"
}

Rounds

Every round ends.

A round is one spin, or one Mines game from the bet to collect or a mine.

A state ending in -ing waits for your wallet's answer. Every round reaches a final state: ended, declined or refunded.

A slot round goes from staking straight to ending. Only a Mines round is open, while the player picks tiles.

A result that exists is always paid. A round is refunded only if no result was made.

Free spins are part of the round that won them: one bet, one win. The round shows the paid spin's win, the number of free spins, and what they won.

A Mines round left open finishes by itself after 24 hours. The player gets what they collected so far. It is never a loss.

Stake accepted
stakingopenendingended
Stake refused
stakingdeclined
No answer to the stake
stakingrefundingrefunded
Waits for your walletFinal

Every call

The whole API on one page.

You call us

→You → us
  • games.listYour games, their images and the settings you chose.
  • session.startStarts a game for a player. Returns the game link.
  • session.updateBetSettingsChanges a player's bet settings during play.
  • session.closeCloses a session.
  • sessions.closeCloses all of a player's sessions. For example, when a player excludes themselves.
  • session.getOne session: its state, times and totals.
  • round.getOne round: its bet, its win, its free spins and every wallet call.
  • rounds.listA player's rounds, by time and state.
  • money.listEvery bet, win and refund in your account, by time. For your finance system.

We call your wallet

→We → you
  • wallet.balanceGets the player's balance.
  • wallet.stakeTakes the bet when a round starts.
  • wallet.winPays a win.
  • wallet.lossTells you a round ended with no win.
  • wallet.refundGives a bet back when a stake had no answer.

We tell your server

→We → you
  • session.closedA session closed: who closed it, and why.

Your environments

→You → us

Sandbox only. By hand, or from your build pipeline.

  • environment.createA new environment, with your server address. It can copy another one.
  • environment.updateChanges its server address or its settings.
  • environment.deleteDeletes an environment. Its sessions close. Wins still owed are still sent.
  • environments.listAll your environments and their settings.

The game and your app

⇄Game ⇄ your app

In your web site, and in iOS, Android, React Native and Flutter apps.

  • game.loadedThe game is on screen. Hide your loading screen.
  • game.failedThe link was used or expired: start a new session. The session closed: go back to the lobby.
  • balance.changedThe balance changed. Show the new one.
  • player.exitThe player pressed exit. Close the game.
  • balance.refreshYou tell the game the player added money.

Answers

One shape for every answer.

Your code checks ok, and acts on a fixed list of error codes, never on text.

Each error code comes with what to do next.

traceId finds every call and retry that one action caused, on both sides.

Every call, both ways, is signed with the sender's private key. A call older than 5 minutes is refused.

Every answer
{ "ok": true,
  "result": { … },
  "traceId": "tr-01JC…" }

{ "ok": false,
  "error": {
    "code": "session_closed",
    "message": "This session is closed."
  },
  "traceId": "tr-01JC…" }

API keys

Your keys, in your back office.

Create API keys in your back office. Each key pair is made in your browser. You keep the private key. We keep only the public key.

Each key has a name, the environments it may use, what it can do, and the IP addresses it may call from. It can play, manage environments, or read money.

On Live, every key needs its IP addresses.

To change a key: create a new one, move your servers to it, then delete the old one.

See everything the back office does.

A signed call
POST /v1/session.start
Key-Id: key_7Hq2Xc9LpQ
Environment: staging
Sent-At: 2026-10-31T12:20:00Z
Signature: MEUCIQD3…

{ "requestId": "r-01JC9B…",
  "firstSentAt": "2026-10-31T12:20:00Z", … }

Going live

From Sandbox to Live.

  1. Build your five wallet calls.And the session.closed address.
  2. Run the wallet test run in Sandbox.We call your wallet with test players and test money, and check each rule.
  3. Ask for Live.Tell us what you need: games, markets, players.
  4. We send you a price.After you pay, we turn on Live and email you.

Live has real players and real money. Nothing is copied from Sandbox: you create new API keys for Live.

Limits

Clear limits, clear answers.

Each account may make 20 calls a second in Sandbox, and 200 in Live. It may create 100 environments an hour.

A call over a limit gets rate_limited, with retryAfter in seconds. Wait that long, then send the call again.

A refused call does not count. session.close and sessions.close never count, so a player can always be closed.

Our calls to your wallet never count against your limits. Live limits can be raised.

Over a limit
HTTP 429

{ "ok": false,
  "error": {
    "code": "rate_limited",
    "message": "Too many calls.",
    "retryAfter": 2
  },
  "traceId": "tr-01JC…" }

Link our games.

Tell us what you need. We send you a price.

contact@nartifacts.com