# Copystake Integration

## **CopyStake overview**

CopyStake consists of two parts:

* **Lobby**. The page of active streamers (with video streams) and regular users actively playing allowed games.
* **Broadcast**. The page of the selected streamer, where the live stream is displayed (or, if it's a regular user, an animation will be shown), and where users can watch the stream, monitor the streamer's bets, and start copying them.

CopyStake admin configuration:

* **Operator settings**. To integrate CopyStake, the operator needs to implement the API contract (provided below) and specify the following information on the Admin CopyStake page:
  * **X-API-KEY**. CopyStake will make requests to the operator with this value in the request’s header.
  * **Session TTL**. It’s needed to synchronize the session duration between the operator and CopyStake.
  * **Callback URL**. It’s required for sending requests from CopyStake.
* **CopyStake settings**. A section necessary for configuring games to be added to the whitelist, creating streamers, scheduling video streams, and more.

API Access:

* All requests from Copystake to the operator contain X-API-KEY with a value issued by the operator.
* All requests from the operator to Copystake contain X-API-KEY with a value issued by Copystake.

Signature:

* All requests from Copystake must be signed by Copystake and verified by the operator.
* All requests from the operator must be signed by the operator and verified by CopyStake.
* The SecretKey for signing the payload in both cases is issued by CopyStake.
* The signature will be placed in the X-REQUEST-SIGNATURE header of each request and uses Base64(HmacSHA512(SecretKey, MD5(request body))).
* Dealing with X-REQUEST-SIGNATURE.

<details>

<summary>Example of how to generate a signature for SecretKey = <code>secret</code></summary>

node \
\
Welcome to Node.js v16.13.0. Type ".help" for more information.\
\
var crypto = require('crypto'); \
undefined \
\
var hasher = crypto.createHash('md5'); \
undefined \
\
var hashed = hasher.update('{"id":"103193","action":"CREDIT","amount":4.123,"currency":"USD","exchangeRate":0.00203250655485,"tokenAmount":2500,"operatorId":123,"operatorUserId":"333"}') \
undefined\
\
var hash = hashed.digest('hex'); \
undefined \
\
var hmac = crypto.createHmac('sha512', 'secret'); \
undefined \
\
hmac.update(hash); \
Hmac { \_options: undefined, \[Symbol(kHandle)]: Hmac {}, \[Symbol(kState)]: { \[Symbol(kFinalized)]: false } } \
\
var sign = hmac.digest('base64'); \
undefined \
\
console.log('signature: ' + sign); \
signature: IifPVbfXptagZ6qSXH9vYrQiqSP4sKIC+hV+39z2K+FlLzRoEboPGTTymjmeuAhN1i0ICDyyrrufYspgAJmxHQ==

</details>

Callback URL:

* `callback_url` - provided by the operator, e.g. `callback_url=https://integration.operator.com/api/v1/copystake`

**IMPORTANT:**&#x20;

Operators need to whitelist the Trueplay IPs to receive transaction status callbacks. Otherwise, Trueplay will return errors for deposit/withdrawal tokens requests.

<details>

<summary><strong>IPs for whitelisting</strong></summary>

18.193.249.95

18.184.86.250

18.196.113.251

</details>

## **Original and Copied transactions**

<figure><img src="https://430841950-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FjvZELq9hA9JLIUfXr0fB%2Fuploads%2FilweetVYq36mDrt15xDz%2F523fd84f-e494-4384-8eff-2cdb7b81cd83.jpeg?alt=media&#x26;token=d9eba7ac-5096-4a76-bbd2-2df5aa646fc6" alt=""><figcaption></figcaption></figure>

## Get CopyStake page&#x20;

This API method allows operators to obtain a link to the CopyStake page, which can be embedded as an iframe into the operator's website.

*If a user accesses CopyStake, the system loads the lobby as the default entry point. However, when generating a Stream URL, it allows to bypass the CopyStake Lobby and be redirected directly to a broadcast page when a stream is active.*

<mark style="color:green;">`POST`</mark>

`https://integration.trueplay.io/api/v1/copystake/init`

**Headers**

{% code overflow="wrap" %}

```
Content-Type: application/json
X-API-KEY: value issued by CopyStake
X-REQUEST-SIGNATURE: value generated based on the request payload (secret key issued by CopyStake)
```

{% endcode %}

**Request**

<table data-header-hidden><thead><tr><th width="168"></th><th width="92"></th><th width="129"></th><th></th></tr></thead><tbody><tr><td><strong>Field</strong></td><td><strong>Type</strong></td><td><strong>Require</strong></td><td><strong>Description</strong></td></tr><tr><td>userId</td><td>String</td><td>mandatory</td><td>User identifier in the operator system</td></tr><tr><td>sessionId</td><td>String</td><td>optional</td><td>Unique session identifier in the operator system. If not provided, it will be generated by CopyStake</td></tr><tr><td>currency</td><td>String</td><td>mandatory</td><td>User's active currency (ISO 4217)</td></tr><tr><td>balance</td><td>Double</td><td>mandatory</td><td>User's current balance in the operator system, rounded to 8 decimal places</td></tr><tr><td>language</td><td>String</td><td>optional</td><td>User's UI language code from the permitted set in the backoffice (ISO 639)</td></tr><tr><td>streamId</td><td>String</td><td>optional</td><td>If this parameter is included in the request, Trueplay system will recognize it and automatically direct the user to the Broadcast page instead of the Lobby.</td></tr></tbody></table>

**Response success**

<table data-header-hidden><thead><tr><th width="158"></th><th width="118"></th><th width="158"></th><th></th></tr></thead><tbody><tr><td><strong>Field</strong></td><td><strong>Type</strong></td><td><strong>Require</strong></td><td><strong>Description</strong></td></tr><tr><td>url</td><td>String</td><td>mandatory</td><td>CopyStake URL with an authentication token</td></tr><tr><td>sessionId</td><td>String</td><td>mandatory</td><td>Unique session identifier in the operator system. If not provided, it will be generated by CopyStake</td></tr></tbody></table>

**Response error**

HTTP 400 Bad Request

<table data-header-hidden><thead><tr><th width="150"></th><th width="86"></th><th width="118"></th><th></th></tr></thead><tbody><tr><td><strong>Field</strong></td><td><strong>Type</strong></td><td><strong>Require</strong></td><td><strong>Description</strong></td></tr><tr><td>errorCode</td><td>String</td><td>mandatory</td><td><p>ERR_UNKNOWN<br>General error status, for cases without a special error code.</p><p>ERR_COPYSTAKE_OFF<br>CopyStake is disabled</p></td></tr><tr><td>errorMessage</td><td>String</td><td>optional</td><td>more detailed description of the error</td></tr></tbody></table>

<details>

<summary><strong>Request example</strong></summary>

{% code overflow="wrap" %}

```
Request
curl --location 'https://integration.trueplay.io/api/v1/copystake/init' \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: d922bd1c-e7ac-4c98-9b1a-baa724440b0e' \
--header 'X-REQUEST-SIGNATURE: XhNkfy6WCTdiewUu0mSUAGw4LwF7GVBa7GT7drJXCvHkI+ORHJQ07uxVKAi3pA/0vB8/shlzX16x+77DvqCGRw==' \
--data '{
    "userId": "1",
    "sessionId": "10XFTW12",
    "currency": "USDT",
    "balance": 820.00000000,
    "language": "en",
    "streamId": "7b699688-f4ad-407d-baf5-c006ba8d50e2"
}'
```

{% endcode %}

</details>

**Response example**

{% tabs %}
{% tab title="200: OK Request is succesful" %}
{% code overflow="wrap" %}

```
200 OK
{
    "url": "https://copystake.trueplay.io?token=eyJhbGciOiJIUzUxMiJ9.eyJpZF9vcGVyYXRvciI6”,
    "sessionId": "10XFTW12"
}
```

{% endcode %}
{% endtab %}

{% tab title="400: Bad Request " %}

```
400 Bad Request
{
    "errorCode": "ERR_COPYSTAKE_OFF",
    "errorMessage": "CopyStake is disabled"
}
```

{% endtab %}
{% endtabs %}

### **Get CopyStake page DEMO** <a href="#get-copystake-page-demo" id="get-copystake-page-demo"></a>

This API method allows operators to obtain a link to the CopyStake page, which can be opened in demo mode within an iframe on the operator’s website.

<mark style="color:green;">`POST`</mark>

`https://integration.trueplay.io/api/v1/copystake/init-demo`

**Headers**

{% code overflow="wrap" %}

```
Content-Type: application/json
X-API-KEY: value issued by CopyStake
```

{% endcode %}

**Request**

<table data-header-hidden><thead><tr><th width="168"></th><th width="92"></th><th width="129"></th><th></th></tr></thead><tbody><tr><td><strong>Field</strong></td><td><strong>Type</strong></td><td><strong>Require</strong></td><td><strong>Description</strong></td></tr><tr><td>language</td><td>String</td><td>optional</td><td>User's UI language code from the permitted set in the backoffice (ISO 639)</td></tr><tr><td>streamId</td><td>String</td><td>optional</td><td>User identifier for active stream. If present, followers are directed to the Broadcast page, skipping the Lobby</td></tr></tbody></table>

Response success

<table data-header-hidden><thead><tr><th width="183"></th><th width="132"></th><th width="141"></th><th></th></tr></thead><tbody><tr><td><strong>Field</strong></td><td><strong>Type</strong></td><td><strong>Require</strong></td><td><strong>Description</strong></td></tr><tr><td>url</td><td>String</td><td>mandatory</td><td>CopyStake url with auth token</td></tr></tbody></table>

Response error HTTP&#x20;

400 Bad Request

<table data-header-hidden><thead><tr><th width="156"></th><th width="126"></th><th width="161"></th><th></th></tr></thead><tbody><tr><td><strong>Field</strong></td><td><strong>Type</strong></td><td><strong>Require</strong></td><td><strong>Description</strong></td></tr><tr><td>errorCode</td><td>String</td><td>mandatory</td><td><p>ERR_UNKNOWN<br>General error status, for cases without a special error code.</p><p>ERR_COPYSTAKE_OFF<br>CopyStake is disabled</p></td></tr><tr><td>errorMessage</td><td>String</td><td>optional</td><td>more detailed description of the error</td></tr></tbody></table>

<details>

<summary><strong>Request example</strong></summary>

{% code overflow="wrap" %}

```
Request
curl --location 'https://integration.trueplay.io/api/v1/copystake/init-demo' \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: d922bd1c-e7ac-4c98-9b1a-baa724440b0e' \
--header 'X-REQUEST-SIGNATURE: XhNkfy6WCTdiewUu0mSUAGw4LwF7GVBa7GT7drJXCvHkI+ORHJQ07uxVKAi3pA/0vB8/shlzX16x+77DvqCGRw==' \
--data '{
    "language": "en",
    "streamId": "7b699688-f4ad-407d-baf5-c006ba8d50e2"
}'
```

{% endcode %}

</details>

**Response example**

{% tabs %}
{% tab title="200: OK Request is succesful" %}
{% code overflow="wrap" %}

```
200 OK
{
    "url": "https://copystake.trueplay.io?token=eyJhbGciOiJIUzUxMiJ9.eyJpZF9vcGVyYXRvciI6”
}
```

{% endcode %}
{% endtab %}

{% tab title="400: Bad Request " %}

```
400 Bad Request
{
    "errorCode": "ERR_COPYSTAKE_OFF",
    "errorMessage": "CopyStake is disabled"
}
```

{% endtab %}
{% endtabs %}

## Send game transaction

This method allows operators to send transaction data to Trueplay. Operators must provide the relevant details of each transaction.

<mark style="color:green;">`POST`</mark>&#x20;

`https://{operator-name}.proxy.trueplay.io/api/v1/accept`

**Headers**

```
Content-Type: application/json
X-API-KEY: value issued by CopyStake
```

<table data-header-hidden><thead><tr><th width="217"></th><th width="102"></th><th width="115"></th><th></th></tr></thead><tbody><tr><td><strong>Field</strong></td><td><strong>Type</strong></td><td><strong>Require</strong></td><td><strong>Description</strong></td></tr><tr><td>userId</td><td>String</td><td>mandatory</td><td>User identifier in the operator system</td></tr><tr><td>transactionId</td><td>String</td><td>mandatory</td><td>A unique identifier for each transaction type (BET, WIN, ROLLBACK). For every new action (BET, WIN, ROLLBACK) a distinct transactionId is generated to track that specific action.</td></tr><tr><td>referenceTransactionId</td><td>String</td><td>optional</td><td><p>Used to link related transactions.</p><p>• For BET transactions, this will be null as they are the starting point of the sequence.</p><p>• For WIN transactions, this field should reference the transactionId of the corresponding BET.</p><p>• For ROLLBACK transactions, this field should reference the transactionId of the original BET being rolled back. This also applies to rolling back WIN transactions; the referenceTransactionId should point to the transactionId of the WIN being rolled back.</p></td></tr><tr><td>type</td><td>String</td><td>mandatory</td><td>Type of game transaction (BET | WIN | ROLLBACK)</td></tr><tr><td>gameProvider</td><td>String</td><td>mandatory</td><td>Indicates the provider of the game or platform associated with the transaction </td></tr><tr><td>gamePublisher</td><td>String</td><td>mandatory</td><td>Specifies the game’s publisher</td></tr><tr><td>gameCode</td><td>String</td><td>mandatory</td><td>Unique game code</td></tr><tr><td>gameName</td><td>String</td><td>mandatory</td><td>An identifier for the specific game associated with the transaction</td></tr><tr><td>gameType</td><td>String</td><td>mandatory</td><td>The type of game</td></tr><tr><td>currency</td><td>String</td><td>mandatory</td><td>User's active currency (ISO 4217)</td></tr><tr><td>amount</td><td>Double</td><td>mandatory</td><td><ul><li>Fiat: Although fiat currencies typically allow up to two decimal places (e.g., USD: 10.25)</li><li>Cryptocurrency: The amount parameter adheres to a maximum of 8 decimal places</li></ul></td></tr></tbody></table>

<details>

<summary><strong>Request example</strong></summary>

{% code overflow="wrap" %}

```
Request
curl --location 'https://integration.trueplay.io/api/v1/copystake/init' \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: d922bd1c-e7ac-4c98-9b1a-baa724440b0e' \
--header 'X-REQUEST-SIGNATURE: XhNkfy6WCTdiewUu0mSUAGw4LwF7GVBa7GT7drJXCvHkI+ORHJQ07uxVKAi3pA/0vB8/shlzX16x+77DvqCGRw==' \
--data '{
    "userId": "1",
    "transactionId": "111",
    "type": "WIN",
    "gameProvider": "NOLIMIT_CITY"
    "gameProvider": "EVOLUTION",
    "gameCode": "Mental",
    "gameName": "Mental",
    "gameType": "Slots",
    "currency": "USDT",
    "amount": 25.00000000,
}
```

{% endcode %}

</details>

{% tabs %}
{% tab title="200: OK Request is successful" %}
{% code overflow="wrap" %}

```
200 OK
```

{% endcode %}
{% endtab %}

{% tab title="400: Bad Request " %}
{% code overflow="wrap" %}

```
400 Bad Request
{
    "errorCode": "ERR_COPYSTAKE_OFF",
    "errorMessage": "CopyStake is disabled"
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

## **Get user balance**

This method retrieves the current available balance of a user during the opening of the broadcast page and before starting the copy round.

<mark style="color:green;">`POST`</mark>&#x20;

```
{callback_url}/user-balance
```

**Headers**

{% code overflow="wrap" %}

```
Content-Type: application/json
X-API-KEY: value issued by Operator
X-REQUEST-SIGNATURE: value generated based on the request payload (secret key issued by CopyStake)
```

{% endcode %}

**Request**

<table data-header-hidden><thead><tr><th width="154"></th><th width="110"></th><th width="144"></th><th></th></tr></thead><tbody><tr><td><strong>Field</strong></td><td><strong>Type</strong></td><td><strong>Require</strong></td><td><strong>Description</strong></td></tr><tr><td>sessionId</td><td>String</td><td>mandatory</td><td>unique session identifier</td></tr></tbody></table>

**Response**

<table data-header-hidden><thead><tr><th width="135"></th><th width="112"></th><th width="143"></th><th></th></tr></thead><tbody><tr><td><strong>Field</strong></td><td><strong>Type</strong></td><td><strong>Require</strong></td><td><strong>Description</strong></td></tr><tr><td>balance</td><td>Double</td><td>mandatory</td><td><ul><li>rounding to 8 decimal places</li><li>current available user's balance</li></ul></td></tr><tr><td>currency</td><td>String</td><td>mandatory</td><td>user's active currency ISO 4217</td></tr></tbody></table>

<details>

<summary><strong>Request example</strong></summary>

{% code overflow="wrap" %}

```
curl --location '{callback_url}/user-balance' \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: e58d1990-31b9-41f5-aa39-fd150643a8fe' \
--header 'X-REQUEST-SIGNATURE: FbS2341Uu0mSUAGw4LwF7GVBa7GT7drJXCvHkI+ORHJQ07uxVKAi3pA/0vB8/shlzX16x234FD==' \
--data '{
    "sessionId": "10XFTW12"

```

{% endcode %}

</details>

{% tabs %}
{% tab title="Response example" %}

```
200 OK
{
    "balance": 830.00000000,
    "currency": "USDT",
}
```

{% endtab %}
{% endtabs %}

## **Send copied transactions (BET/WIN/ROLLBACK)**

### **Send BET copied transaction**

This API method sends a BET copied transaction to the operator immediately after receiving the transaction from the streamer during an active game round.

<mark style="color:green;">`POST`</mark>&#x20;

```
{callback_url}/bet
```

**Headers**

{% code overflow="wrap" %}

```
Content-Type: application/json
X-API-KEY: value issued by Operator
X-REQUEST-SIGNATURE: value generated based on the request payload (secret key issued by CopyStake)
```

{% endcode %}

**Request**

<table data-header-hidden><thead><tr><th width="222"></th><th width="98"></th><th width="119"></th><th></th></tr></thead><tbody><tr><td><strong>Field</strong></td><td><strong>Type</strong></td><td><strong>Require</strong></td><td><strong>Description</strong></td></tr><tr><td>sessionId</td><td>String</td><td>mandatory</td><td>Unique session identifier</td></tr><tr><td>roundId</td><td>String</td><td>mandatory</td><td>Unique round identifier representing one copy cycle (some number of game actions)</td></tr><tr><td>transactionId</td><td>String</td><td>mandatory</td><td>Unique CopyStake transaction identifier</td></tr><tr><td>transactionIdOriginal</td><td>String</td><td>mandatory</td><td>Original transaction identifier (the streamer's transaction)</td></tr><tr><td>currency</td><td>String</td><td>mandatory</td><td>User's active currency (ISO 4217)</td></tr><tr><td>amount</td><td>Double</td><td>mandatory</td><td><p></p><ul><li>Fiat: Although fiat currencies typically allow up to two decimal places (e.g., USD: 10.25)</li><li>Cryptocurrency: The amount parameter adheres to a maximum of 8 decimal places</li></ul></td></tr></tbody></table>

**Response**

<table data-header-hidden><thead><tr><th width="157"></th><th width="100"></th><th width="122"></th><th></th></tr></thead><tbody><tr><td><strong>Field</strong></td><td><strong>Type</strong></td><td><strong>Require</strong></td><td><strong>Description</strong></td></tr><tr><td>balance</td><td>Double</td><td>mandatory</td><td>Current available user's balance, rounded to 8 decimal places</td></tr><tr><td>currency</td><td>String</td><td>mandatory</td><td>User's active currency (ISO 4217)</td></tr></tbody></table>

**Response error**\
HTTP 400 Bad Request

<table data-header-hidden><thead><tr><th width="158"></th><th width="88"></th><th width="117"></th><th></th></tr></thead><tbody><tr><td><strong>Field</strong></td><td><strong>Type</strong></td><td><strong>Require</strong></td><td><strong>Description</strong></td></tr><tr><td>errorCode</td><td>String</td><td>mandatory</td><td>ERR_UNKNOWN<br>General error status, for cases without a special error code.</td></tr><tr><td>errorMessage</td><td>String</td><td>optional</td><td>More detailed description of the error</td></tr></tbody></table>

<details>

<summary><strong>Request example</strong></summary>

{% code overflow="wrap" %}

```
curl --location'https://{operator_base_url}/integration/copystake/bet'\
--header 'Content-Type: application/json' \
--header 'X-API-KEY: e58d1990-31b9-41f5-aa39-fd150643a8fe' \
--header 'X-REQUEST-SIGNATURE: FbS2341Uu0mSUAGw4LwF7GVBa7GT7drJXCvHkI+ORHJQ07uxVKAi3pA/0vB8/shlzX16x234FD==' \
--data '{
    "sessionId": "10XFTW12",
    "roundId": "1",
    "transactionId": "1",
    "transactionIdOriginal": "111",
    "currency": "USDT",
    "amount": 25.00000000
}'
```

{% endcode %}

</details>

**Response example**

{% tabs %}
{% tab title="200: OK Request is successful" %}

```
200 OK
{
    "balance": 795.00000000,
    "currency": "USDT",
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

```
400 Bad Request
{
    "errorCode": "ERR_COPYSTAKE_OFF",
    "errorMessage": "CopyStake is disabled"
}
```

{% endtab %}
{% endtabs %}

### **Send WIN copied transaction**

This API method sends a WIN copied transaction to the operator immediately after receiving the transaction from the streamer during an active game round.

<mark style="color:green;">`POST`</mark>&#x20;

```
{callback_url}/win
```

**Headers**

{% code overflow="wrap" %}

```
Content-Type: application/json
X-API-KEY: value issued by Operator
X-REQUEST-SIGNATURE: value generated based on the request payload (secret key issued by CopyStake)
```

{% endcode %}

**Request**

<table data-header-hidden><thead><tr><th width="229"></th><th width="100"></th><th width="120"></th><th></th></tr></thead><tbody><tr><td><strong>Field</strong></td><td><strong>Type</strong></td><td><strong>Require</strong></td><td><strong>Description</strong></td></tr><tr><td>sessionId</td><td>String</td><td>mandatory</td><td>Unique session identifier</td></tr><tr><td>roundId</td><td>String</td><td>mandatory</td><td>Unique round identifier representing one copy cycle (some number of game actions)</td></tr><tr><td>transactionId</td><td>String</td><td>mandatory</td><td>Unique CopyStake transaction identifier</td></tr><tr><td>transactionIdOriginal</td><td>String</td><td>mandatory</td><td>Original transaction identifier (the streamer's transaction)</td></tr><tr><td>currency</td><td>String</td><td>mandatory</td><td>User's active currency (ISO 4217)</td></tr><tr><td>amount</td><td>Double</td><td>mandatory</td><td><p></p><ul><li>Fiat: Although fiat currencies typically allow up to two decimal places (e.g., USD: 10.25)</li><li>Cryptocurrency: The amount parameter adheres to a maximum of 8 decimal places</li></ul></td></tr></tbody></table>

**Response**

<table data-header-hidden><thead><tr><th width="143"></th><th width="112"></th><th width="146"></th><th></th></tr></thead><tbody><tr><td><strong>Field</strong></td><td><strong>Type</strong></td><td><strong>Require</strong></td><td><strong>Description</strong></td></tr><tr><td>balance</td><td>Double</td><td>mandatory</td><td>Current available user's balance, rounded to 8 decimal places</td></tr><tr><td>currency</td><td>String</td><td>mandatory</td><td>User's active currency (ISO 4217)</td></tr></tbody></table>

<details>

<summary><strong>Request example</strong></summary>

{% code overflow="wrap" %}

```
curl --location https://{operator_base_url}/integration/copystake/win \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: e58d1990-31b9-41f5-aa39-fd150643a8fe' \
--header 'X-REQUEST-SIGNATURE: FbS2341Uu0mSUAGw4LwF7GVBa7GT7drJXCvHkI+ORHJQ07uxVKAi3pA/0vB8/shlzX16x234FD==' \
--data '{
    "sessionId": "10XFTW12",
    "roundId": "1",
    "transactionId": "1",
    "transactionIdOriginal": "111",
    "currency": "USDT",
    "amount": 25.00000000
}'
```

{% endcode %}

</details>

**Response example**

{% tabs %}
{% tab title="200: OK Request is successful" %}

```
200 OK
{
    "balance": 805.00000000,
    "currency": "USDT",
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

```
400 Bad Request
{
    "errorCode": "ERR_COPYSTAKE_OFF",
    "errorMessage": "CopyStake is disabled"
}
```

{% endtab %}
{% endtabs %}

### **Send ROLLBACK BET copied transaction**

This API method sends a ROLLBACK BET copied transaction to the operator immediately after receiving the transaction from the streamer during an active game round.

<mark style="color:green;">`POST`</mark>&#x20;

```
{callback_url}/rollback-bet
```

**Headers**

{% code overflow="wrap" %}

```
Content-Type: application/json
X-API-KEY: value issued by Operator
X-REQUEST-SIGNATURE: value generated based on the request payload (secret key issued by CopyStake)
```

{% endcode %}

**Request**

<table data-header-hidden><thead><tr><th width="295"></th><th width="86"></th><th width="120"></th><th></th></tr></thead><tbody><tr><td><strong>Field</strong></td><td><strong>Type</strong></td><td><strong>Require</strong></td><td><strong>Description</strong></td></tr><tr><td>sessionId</td><td>String</td><td>mandatory</td><td>Unique session identifier</td></tr><tr><td>roundId</td><td>String</td><td>mandatory</td><td>Unique round identifier representing one copy cycle (some number of game actions)</td></tr><tr><td>transactionId</td><td>String</td><td>mandatory</td><td>Unique CopyStake transaction identifier</td></tr><tr><td>referenceTransactionId</td><td>String</td><td>mandatory</td><td>Reference to BET CopyStake transaction identifier</td></tr><tr><td>transactionIdOriginal</td><td>String</td><td>mandatory</td><td>Original transaction identifier (the streamer's transaction)</td></tr><tr><td>referenceTransactionIdOriginal</td><td>String</td><td>mandatory</td><td>Reference to original BET transaction identifier</td></tr><tr><td>currency</td><td>String</td><td>mandatory</td><td>User's active currency (ISO 4217)</td></tr><tr><td>amount</td><td>Double</td><td>mandatory</td><td><p></p><ul><li>Fiat: Although fiat currencies typically allow up to two decimal places (e.g., USD: 10.25)</li><li>Cryptocurrency: The amount parameter adheres to a maximum of 8 decimal places</li></ul></td></tr></tbody></table>

**Response**

<table data-header-hidden><thead><tr><th width="137"></th><th width="133"></th><th width="143"></th><th></th></tr></thead><tbody><tr><td><strong>Field</strong></td><td><strong>Type</strong></td><td><strong>Require</strong></td><td><strong>Description</strong></td></tr><tr><td>balance</td><td>Double</td><td>mandatory</td><td>Current available user's balance, rounded to 8 decimal places</td></tr><tr><td>currency</td><td>String</td><td>mandatory</td><td>User's active currency (ISO 4217)</td></tr></tbody></table>

<details>

<summary><strong>Request example</strong></summary>

{% code overflow="wrap" %}

```
curl --location 'https://{operator_base_url}/integration/copystake/rollback-bet' \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: e58d1990-31b9-41f5-aa39-fd150643a8fe' \
--header 'X-REQUEST-SIGNATURE: FAE3S2341Uu0mSUAGw4LwF7GVBa7GT7drJXCvHkI+ORHJQ07uxVKAi3pA/0vB8/shlzX16x23d23d==' \
--data '{
    "sessionId": "10XFTW12",                   
    "roundId": "1",                            
    "transactionId": "3",                      
    "referenceTransactionId": "1",              
    "transactionIdOriginal": "333",             
    "referenceTransactionIdOriginal": "111",
    "currency": "USDT",                        
    "amount": 25.00000000                        
}'
```

{% endcode %}

</details>

**Response example**

{% tabs %}
{% tab title="200: OK Request is successful" %}

```
200 OK
{
    "balance": 830.00000000,
    "currency": "USDT"
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

```
400 Bad Request
{
    "errorCode": "ERR_COPYSTAKE_OFF",
    "errorMessage": "CopyStake is disabled"
}
```

{% endtab %}
{% endtabs %}

### **Send ROLLBACK WIN copied transaction**

This API method sends a ROLLBACK WIN copied transaction to the operator immediately after receiving the transaction from the streamer during an active game round.

<mark style="color:green;">`POST`</mark>&#x20;

```
{callback_url}/rollback-win
```

**Headers**

{% code overflow="wrap" %}

```
Content-Type: application/json
X-API-KEY: value issued by Operator
X-REQUEST-SIGNATURE: value generated based on the request payload (secret key issued by CopyStake)
```

{% endcode %}

**Request**

<table data-header-hidden><thead><tr><th width="276"></th><th width="92"></th><th width="117"></th><th></th></tr></thead><tbody><tr><td><strong>Field</strong></td><td><strong>Type</strong></td><td><strong>Require</strong></td><td><strong>Description</strong></td></tr><tr><td>sessionId</td><td>String</td><td>mandatory</td><td>Unique session identifier</td></tr><tr><td>roundId</td><td>String</td><td>mandatory</td><td>Unique round identifier representing one copy cycle (some number of game actions)</td></tr><tr><td>transactionId</td><td>String</td><td>mandatory</td><td>Unique CopyStake transaction identifier</td></tr><tr><td>referenceTransactionId</td><td>String</td><td>mandatory</td><td>Reference to WIN CopyStake transaction identifier</td></tr><tr><td>transactionIdOriginal</td><td>String</td><td>mandatory</td><td>Original transaction identifier (the streamer's transaction)</td></tr><tr><td>referenceTransactionIdOriginal</td><td>String</td><td>mandatory</td><td>Reference to original BET transaction identifier</td></tr><tr><td>currency</td><td>String</td><td>mandatory</td><td>User's active currency (ISO 4217)</td></tr><tr><td>amount</td><td>Double</td><td>mandatory</td><td><p></p><ul><li>Fiat: Although fiat currencies typically allow up to two decimal places (e.g., USD: 10.25)</li><li>Cryptocurrency: The amount parameter adheres to a maximum of 8 decimal places</li></ul></td></tr></tbody></table>

**Response**

<table data-header-hidden><thead><tr><th width="137"></th><th width="133"></th><th width="143"></th><th></th></tr></thead><tbody><tr><td><strong>Field</strong></td><td><strong>Type</strong></td><td><strong>Require</strong></td><td><strong>Description</strong></td></tr><tr><td>balance</td><td>Double</td><td>mandatory</td><td>Current available user's balance, rounded to 8 decimal places</td></tr><tr><td>currency</td><td>String</td><td>mandatory</td><td>User's active currency (ISO 4217)</td></tr></tbody></table>

<details>

<summary><strong>Request example</strong></summary>

<pre data-overflow="wrap"><code><strong>curl --location 'https://{operator_base_url}/integration/copystake/rollback-win' \
</strong>--header 'Content-Type: application/json' \
--header 'X-API-KEY: e58d1990-31b9-41f5-aa39-fd150643a8fe' \
--header 'X-REQUEST-SIGNATURE: FAE3S2341Uu0mSUAGw4LwF7GVBa7GT7drJXCvHkI+ORHJQ07uxVKAi3pA/0vB8/shlzX16x23d23d==' \
--data '{
    "sessionId": "10XFTW12",                   
    "roundId": "1",                            
    "transactionId": "4",                      
    "referenceTransactionId": "2",              
    "transactionIdOriginal": "444",             
    "referenceTransactionIdOriginal": "222",
    "currency": "USDT",                        
    "amount": 10.00000000                        
}'
</code></pre>

</details>

**Response example**

{% tabs %}
{% tab title="200: OK Request is successful" %}

```
200 OK
{
    "balance": 830.00,
    "currency": "USDT"
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

```
400 Bad Request
{
    "errorCode": "ERR_COPYSTAKE_OFF",
    "errorMessage": "CopyStake is disabled"
}
```

{% endtab %}
{% endtabs %}

## Update User account type

This API method allows you to update the user account type to either TEST or REGULAR. It is commonly used to mark a user as a test user.

<mark style="color:red;">`PUT`</mark>&#x20;

```
https://integration.trueplay.io/api/v1/copystake/user
```

**Headers**

{% code overflow="wrap" %}

```
Content-Type: application/json
X-API-KEY: value issued by CopyStake
```

{% endcode %}

**Request**

| **Field** | **Type** | **Require** | **Description**  |
| --------- | -------- | ----------- | ---------------- |
| userId    | String   | mandatory   | operator user id |
| userType  | String   | mandatory   | TEST REGULAR     |

**Response success**

```
204 OK
```

<details>

<summary><strong>Request example</strong></summary>

{% code overflow="wrap" %}

```
curl -X 'PUT' \
  'https://integration.trueplay.io/api/v1/copystake/user' \
  -H 'accept: */*' \
  -H 'X-API-KEY: d922bd1c-e7ac-4c98-9b1a-baa724440b0e' \
  -H 'Content-Type: application/json' \
  -d '{
  "userId": "local_user",
  "userType": "TEST"
}'
```

{% endcode %}

</details>

**Response example**

{% tabs %}
{% tab title="204: OK Request is successful" %}

```
204 OK
```

{% endtab %}

{% tab title="404: Not Found " %}

```
404 Not Found
{
    "message": "User [operatorUserId] not found"
}
```

{% endtab %}
{% endtabs %}

## Copystake Reward URL

The reward endpoint allows CopyStake to notify the operator’s bonus engine about a reward granted to a user as part of gamified features like Jackpot, Wheel of Fortune, or Sign-up Reward.

<mark style="color:green;">`POST`</mark>&#x20;

```
https://{callback_url}/reward
```

**Headers**

{% code overflow="wrap" %}

```
Content-Type: application/json
X-API-KEY: value issued by Operator
X-REQUEST-SIGNATURE: value generated based on the request payload (secret key issued by CopyStake)
```

{% endcode %}

<table data-header-hidden><thead><tr><th width="135.86328125"></th><th width="100.93359375"></th><th width="146.078125"></th><th></th></tr></thead><tbody><tr><td><strong>Field</strong></td><td><strong>Type</strong></td><td><strong>Require</strong></td><td><strong>Description</strong></td></tr><tr><td>userId</td><td>String</td><td>mandatory</td><td>user identifier in the operator system</td></tr><tr><td>transactionId</td><td>String</td><td>mandatory</td><td>unique CopyStake transaction identifier</td></tr><tr><td>rewardType</td><td>String</td><td>mandatory</td><td>COPYSTAKE_REWARD<br>the reward type sent by CopyStake</td></tr><tr><td>eventType</td><td>String</td><td>mandatory</td><td>JACKPOT, WHEEL_OF_FORTUNE, SIGN_UP_REWARD<br>the event type sent by CopyStake</td></tr><tr><td>bonusType</td><td>String</td><td>mandatory</td><td>CASINO, SPORT<br>the bonus type sent by CopyStake to identify Operator’s bonus engine</td></tr><tr><td>wager</td><td>Integer</td><td>mandatory</td><td><p>0: the charge is made to the main user’s account</p><p>1 and greater: coefficient used to calculate the amount a user must wager to transfer winnings from the bonus user’s account to the main user’s account (e.g. wager=5 and amount=100, then after wagering the amount of 5*100, the user will receive a bonus of 100 to to the main user’s account)</p></td></tr><tr><td>bonusTtlDays</td><td>Integer</td><td>mandatory</td><td><p>0: in case the wager=0</p><p>1 and greater: number of days during which the user can wager the bonus</p></td></tr><tr><td>currency</td><td>String</td><td>mandatory</td><td>user's active currency ISO 4217</td></tr><tr><td>amount</td><td>Double</td><td>mandatory</td><td><ul><li>fiat: two decimal places (e.g., USD: 10.25)</li><li>cryptocurrency: the amount parameter adheres to a maximum of 8 decimal places</li></ul></td></tr></tbody></table>

<details>

<summary>Request example</summary>

```
curl --location '{callback_url}/reward' \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: e58d1990-31b9-41f5-aa39-fd150643a8fe' \
--header 'X-REQUEST-SIGNATURE: FbS2341Uu0mSUAGw4LwF7GVBa7GT7drJXCvHkI+ORHJQ07uxVKAi3pA/0vB8/shlzX16x234FD==' \
--data '{
    "userId": "29e946a1-e801-4e27-952d-1d6ebbd19525",
    "transactionId": "01944be7-a260-7209-b16f-0d2d953e8c9f",
    "rewardType": "COPYSTAKE_REWARD",
    "eventType": "WHEEL_OF_FORTUNE",
    "bonusType": "CASINO",
    "wager": 0,
    "currency": "USD",
    "amount": 5.00
}'
```

</details>

{% tabs %}
{% tab title="200: OK Request is successful" %}

{% endtab %}

{% tab title="400 Bad Request" %}

```
{
    "errorCode": "ERR_REWARD_FORBIDDEN",
    "errorMessage": "user fraud detected"
}
```

{% endtab %}
{% endtabs %}

## **Error handling and retry mechanism**

CopyStake is very sensitive to the stability and speed of the operator's response and cannot allow long delays in response or a classic retry mechanism with several attempts. In the case of prolonged latency, CopyStack will **interrupt the game round** but keep the session active. If an error differs from those below, there will be **one retry attempt**.

**Response**

<table data-header-hidden><thead><tr><th width="150"></th><th width="96"></th><th width="116"></th><th></th></tr></thead><tbody><tr><td><strong>Field</strong></td><td><strong>Type</strong></td><td><strong>Require</strong></td><td><strong>Description</strong></td></tr><tr><td>errorCode</td><td>String</td><td>mandatory</td><td><p>ERR_UNKNOWN<br>General error status, for cases without a special error code.</p><p>ERR_INSUFFICIENT_FUNDS<br>Not enough money on the user's balance to process a transaction</p><p>ERR_DUPLICATE_TRANSACTION<br>A transaction with the same identifier was sent</p><p>ERR_USER_DISABLED<br>User is disabled/locked (cannot interact with user's balance)</p><p>ERR_INVALID_SIGNATURE<br>Operator couldn't verify the signature on request from</p></td></tr><tr><td>errorMessage</td><td>String</td><td>optional</td><td>more detailed description of the error</td></tr></tbody></table>

**Response example**

{% tabs %}
{% tab title="400: Bad Request " %}

```
400 Bad Request
{
    "errorCode": "ERR_INSUFFICIENT_FUNDS",
    "errorMessage": "Insufficient balance"
}
```

{% endtab %}
{% endtabs %}
