Deriv API
Migration guide/Profit table

Profit table

Account
Auth Required

Get profit and loss history. The loginid parameter removed, response fields now required, and validation relaxed.

Quick comparison

AspectLegacyNewAction required
Endpoint
✅ Same
profit_tableprofit_tableNone
Auth Required
✅ Same
YesYesNone
loginid Parameter
❌ Removed
SupportedRemovedRemove from requests
Response Fields
⚠️ Changed
OptionalRequiredUpdate error handling
app_id Type
⚠️ Changed
integer | nullintegerRemove null checks

Breaking changes

1. loginid parameter removed

What Changed: The loginid parameter is no longer supported in requests. Authentication is now handled via session tokens.

Migration: Remove the loginid parameter from your API requests. Use proper session-based authentication instead.

2. app_id no longer nullable

What Changed: The app_id field in transactions changed from integer | null to integer.

Migration: Remove null checks for app_id. The field will always contain a valid integer.

3. Response fields now required

What Changed: The profit_table object, count, and transactions are now required in the response. Previously they were optional.

Migration: You can simplify your code by removing defensive checks for missing profit_table data.

4. Transaction fields now required

What Changed: Transaction objects now have required fields: buy_price, payout, purchase_time, sell_price, transaction_id.

Migration: These fields are guaranteed to be present. Remove optional chaining or default values for these fields.

5. Validation relaxed

What Changed: Server-side validation is more lenient:

  • sort - No longer restricted to ASC/DESC enum
  • limit - No longer has default (50), maximum (500), or minimum (0) constraints
  • contract_type - No longer validates against strict enum of contract types
  • date_from/date_to - No longer validates against regex pattern

Migration: Implement client-side validation if you were relying on the server to reject invalid values.

Request structure

Legacy Request Example

1{
2  "profit_table": 1,
3  "description": 1,
4  "limit": 25,
5  "offset": 0,
6  "sort": "ASC",
7  "loginid": "CR12345"
8}

New Request Example

1{
2  "profit_table": 1,
3  "description": 1,
4  "limit": 25,
5  "offset": 0,
6  "sort": "ASC"
7}

Note: The loginid parameter has been removed in v4.

Response structure

Legacy Response Example

1{
2  "profit_table": {
3    "count": 100,
4    "transactions": [
5      {
6        "app_id": null,
7        "buy_price": 10.00,
8        "sell_price": 15.00,
9        "payout": 15.00,
10        "contract_id": 123456789,
11        "purchase_time": 1234567890,
12        "sell_time": 1234567900,
13        "transaction_id": 987654321
14      }
15    ]
16  },
17  "msg_type": "profit_table"
18}

New Response Example

1{
2  "profit_table": {
3    "count": 100,
4    "transactions": [
5      {
6        "app_id": 12345,
7        "buy_price": 10.00,
8        "sell_price": 15.00,
9        "payout": 15.00,
10        "contract_id": 123456789,
11        "purchase_time": 1234567890,
12        "sell_time": 1234567900,
13        "transaction_id": 987654321
14      }
15    ]
16  },
17  "msg_type": "profit_table"
18}

Note: app_id is no longer nullable in v4. All response fields (profit_table, count, transactions) are now required.

Code examples

Legacy Implementation

1async function getProfitTable() {
2  const request = {
3    profit_table: 1,
4    description: 1,
5    limit: 25,
6    loginid: "CR12345" // Supported in legacy
7  };
8
9  ws.send(JSON.stringify(request));
10
11  ws.onmessage = (event) => {
12    const response = JSON.parse(event.data);
13    if (response.msg_type === 'profit_table') {
14      // profit_table, count, transactions may be undefined
15      const count = response.profit_table?.count || 0;
16      console.log('Total:', count);
17      
18      response.profit_table?.transactions?.forEach(t => {
19        // app_id can be null
20        const appId = t.app_id ?? 'Unknown';
21        const profitLoss = t.sell_price - t.buy_price;
22        console.log(`App: ${appId}, P/L: ${profitLoss}`);
23      });
24    }
25  };
26}

New Implementation

1async function getProfitTable() {
2  const request = {
3    profit_table: 1,
4    description: 1,
5    limit: 25
6    // loginid removed - use session token
7  };
8
9  ws.send(JSON.stringify(request));
10
11  ws.onmessage = (event) => {
12    const response = JSON.parse(event.data);
13    if (response.msg_type === 'profit_table') {
14      // profit_table, count, transactions guaranteed
15      console.log('Total:', response.profit_table.count);
16      
17      response.profit_table.transactions.forEach(t => {
18        // app_id is always a number (not null)
19        const profitLoss = t.sell_price - t.buy_price;
20        console.log(`App: ${t.app_id}, P/L: ${profitLoss}`);
21      });
22    }
23  };
24}