# SofaScore Tennis Data Stream (`crawlstone/sofascore-tennis-data-stream`) Actor

Stream live tennis data from SofaScore over WebSocket, including current scores, accumulated point-by-point records, and match statistics.

- **URL**: https://apify.com/crawlstone/sofascore-tennis-data-stream.md
- **Developed by:** [Crawl Stone](https://apify.com/crawlstone) (community)
- **Categories:** Automation, Developer tools
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.01 / 1,000 snapshots

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## SofaScore Tennis Data Stream

This is a **Standby-only Actor** designed to stream live tennis scores, accumulated point-by-point history, and real-time statistics to your application over a persistent WebSocket connection.

We built this stream to address the limitations of standard bulk-scraping or polling models when handling live sports data. Unlike traditional Actors that write scraping outputs to an Apify Dataset, this product has no standard input-to-run-to-Dataset workflow. It runs continuously as a Standby service, maintaining connection state in memory and serving real-time events straight to your connected clients.

> **Unofficial Actor:** SofaScore Tennis Data Stream is an independent tool and is not affiliated with or endorsed by SofaScore.

> **Looking for historical data or standard exports?** If you need scheduled tournaments, match details, player profiles, or standard flat files (JSON, CSV, Excel) rather than live streaming updates, use our companion product: [Tennis Scraper](https://apify.com/crawlstone/tennis-scraper).

---

### Onboarding and Mental Model

The delivery model utilizes a simple connection and subscription flow:

1. **Connect:** Establish a persistent WebSocket connection to the Standby endpoint with your Apify API token.
2. **Discover:** Send a JSON command to retrieve the list of matches currently in progress (`liveMatches`).
3. **Subscribe:** Send a subscription command (`subscribe`) with the unique ID of the match you want to follow.
4. **Consume:** Receive combined snapshots containing full point progression and statistics. Snapshots are sent when fresh point-by-point or statistics data becomes available at the source, including a cached snapshot sent immediately after a successful subscription when available. Each snapshot replaces any previously received snapshot for that match.
5. **Clean Up:** Remove subscriptions when matches finish, or close the connection when you're done.

---

### Code Tutorials

Use these copy/paste-friendly, happy-path client examples to start streaming live data.

#### TypeScript Client

Install the pinned dependencies in your Node.js project:

```bash
npm install ws@8.21.1
npm install --save-dev tsx@4.23.1 typescript@7.0.2 @types/node@26.1.1 @types/ws@8.18.1
````

Save the code below as `client.ts`, replace `YOUR_APIFY_TOKEN`, and run it:

```bash
npx tsx client.ts
```

```typescript
import WebSocket from "ws";

const standbyUrl = "https://crawlstone--sofascore-tennis-data-stream.apify.actor";
const token = "YOUR_APIFY_TOKEN";

// Construct the WebSocket URL from the Standby HTTP URL
const websocketUrl = new URL(standbyUrl);
websocketUrl.protocol = websocketUrl.protocol === "http:" ? "ws:" : "wss:";
websocketUrl.pathname = `${websocketUrl.pathname.replace(/\/$/, "")}/v1/ws`;

console.log(`Connecting to ${websocketUrl.toString()}...`);

// Connect to the Standby WebSocket endpoint with Bearer header authentication
const socket = new WebSocket(websocketUrl.toString(), {
  headers: {
    Authorization: `Bearer ${token}`,
  },
});

// Once connected, request the list of currently live matches
socket.on("open", () => {
  console.log("Connected! Requesting live matches...");
  socket.send(JSON.stringify({ type: "liveMatches" }));
});

// Handle incoming messages from the stream
socket.on("message", (rawData) => {
  const message = JSON.parse(rawData.toString());

  switch (message.type) {
    case "liveMatches": {
      const matches = message.matches || [];
      console.log(`Found ${matches.length} live matches.`);

      if (matches.length === 0) {
        console.log("No live matches available right now. Closing connection.");
        socket.close(1000, "No live matches");
        return;
      }

      // Select a simple target: the first currently live match
      const targetMatch = matches[0];
      const matchId = targetMatch.id;
      const homeName = targetMatch.homePlayerName || targetMatch.homeTeamName || "Home Team";
      const awayName = targetMatch.awayPlayerName || targetMatch.awayTeamName || "Away Team";
      console.log(`Subscribing to: ${homeName} vs ${awayName} (ID: ${matchId})`);

      // Subscribe to receive real-time data for this match
      socket.send(JSON.stringify({ type: "subscribe", matchId }));
      break;
    }

    case "subscribed":
      console.log(`Successfully subscribed to match ${message.matchId}`);
      break;

    case "snapshot":
      // A snapshot contains the full point-by-point and statistics data currently available.
      // Important: Each snapshot replaces the previous snapshot; it is not a delta.
      console.log(`\n--- Received Snapshot for Match ${message.matchId} ---`);
      console.log(JSON.stringify(message, null, 2));
      break;

    case "subscriptionEnded":
    case "unsubscribed": {
      const reason = message.reason || "requested";
      console.log(`Subscription finished for match ${message.matchId} (Reason: ${reason})`);
      // If our subscription ended (e.g., match finished), we can close the connection
      console.log("Closing connection...");
      socket.close(1000, "Subscription ended");
      break;
    }

    case "error":
      console.error(`Received stream error: ${message.code} - ${message.message}`);
      console.log("Closing connection due to error...");
      socket.close(1000, "Error received");
      break;

    default:
      console.log(`Unhandled message type: ${message.type}`);
  }
});

// Handle connection closure
socket.on("close", (code, reason) => {
  console.log(`Connection closed (Code: ${code}, Reason: ${reason.toString() || "None"})`);
});

// Handle connection errors
socket.on("error", (error) => {
  console.error(`WebSocket error: ${error.message}`);
});
```

#### Python Client

Install the pinned dependency in your Python environment:

```bash
python -m pip install websockets==16.1.1
```

Save the code below as `client.py`, replace `YOUR_APIFY_TOKEN`, and run it:

```bash
python client.py
```

```python
import asyncio
import json
from urllib.parse import urlsplit, urlunsplit

from websockets.asyncio.client import connect
from websockets.exceptions import ConnectionClosed

STANDBY_URL = "https://crawlstone--sofascore-tennis-data-stream.apify.actor"
TOKEN = "YOUR_APIFY_TOKEN"

## Construct the WebSocket URL from the Standby HTTP URL
parts = urlsplit(STANDBY_URL)
scheme = "ws" if parts.scheme == "http" else "wss"
WEBSOCKET_URL = urlunsplit(
    (scheme, parts.netloc, f"{parts.path.rstrip('/')}/v1/ws", parts.query, "")
)


async def main():
    print(f"Connecting to {WEBSOCKET_URL}...")

    # Connect to the Standby WebSocket endpoint with Bearer header authentication
    try:
        async with connect(
            WEBSOCKET_URL,
            additional_headers={"Authorization": f"Bearer {TOKEN}"},
            max_size=None,  # Do not limit incoming message size for large snapshots
        ) as websocket:
            print("Connected! Requesting live matches...")
            # Once connected, request the list of currently live matches
            await websocket.send(json.dumps({"type": "liveMatches"}))

            # Handle incoming messages from the stream
            async for raw_message in websocket:
                message = json.loads(raw_message)
                message_type = message.get("type")

                if message_type == "liveMatches":
                    matches = message.get("matches", [])
                    print(f"Found {len(matches)} live matches.")

                    if not matches:
                        print("No live matches available right now. Closing connection.")
                        break

                    # Select a simple target: the first currently live match
                    target_match = matches[0]
                    match_id = target_match["id"]
                    home_name = (
                        target_match.get("homePlayerName")
                        or target_match.get("homeTeamName")
                        or "Home Team"
                    )
                    away_name = (
                        target_match.get("awayPlayerName")
                        or target_match.get("awayTeamName")
                        or "Away Team"
                    )
                    print(f"Subscribing to: {home_name} vs {away_name} (ID: {match_id})")

                    # Subscribe to receive real-time data for this match
                    await websocket.send(
                        json.dumps({"type": "subscribe", "matchId": match_id})
                    )

                elif message_type == "subscribed":
                    print(f"Successfully subscribed to match {message.get('matchId')}")

                elif message_type == "snapshot":
                    # A snapshot contains the full point-by-point and statistics data currently available.
                    # Important: Each snapshot replaces the previous snapshot; it is not a delta.
                    print(
                        f"\n--- Received Snapshot for Match {message.get('matchId')} ---"
                    )
                    print(json.dumps(message, indent=2))

                elif message_type in {"subscriptionEnded", "unsubscribed"}:
                    reason = message.get("reason", "requested")
                    print(
                        f"Subscription finished for match {message.get('matchId')} "
                        f"(Reason: {reason})"
                    )
                    # If our subscription ended (e.g., match finished), we can close the connection
                    print("Closing connection...")
                    break

                elif message_type == "error":
                    print(
                        f"Received stream error: {message.get('code')} - {message.get('message')}"
                    )
                    print("Closing connection due to error...")
                    break

                else:
                    print(f"Unhandled message type: {message_type}")

    except ConnectionClosed as error:
        print(f"Connection closed ({error.code}: {error.reason})")
    except Exception as error:
        print(f"WebSocket connection failed: {error}")


if __name__ == "__main__":
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        pass
```

***

### Connection and Service Endpoints

Deployed Standby routing requires a valid Apify API token for HTTP service requests and WebSocket handshakes. Bearer headers are recommended for server clients; restricted query tokens are the browser fallback.

- **Readiness Check (Optional):** `https://crawlstone--sofascore-tennis-data-stream.apify.actor/`
  An optional service-health check. Requesting with GET and the `X-Apify-Container-Server-Readiness-Probe: 1` header returns HTTP `200` with the text `ready` to confirm the Standby server is active. This confirms service availability, not match discovery.
- **WebSocket Endpoint:** `wss://crawlstone--sofascore-tennis-data-stream.apify.actor/v1/ws`
  Exposes the persistent connection for live commands and streaming snapshots.

***

### Scannable Protocol Reference

#### 1. Commands (JSON text frames)

- **List Live Matches:** `{"type":"liveMatches"}`
  Returns all matches currently active in the feed with their live score states.
- **Subscribe:** `{"type":"subscribe","matchId":12345678}`
  Starts streaming snapshots for the target match ID.
- **Unsubscribe:** `{"type":"unsubscribe","matchId":12345678}`
  Stops the streaming snapshot feed for that match ID.

#### 2. Message Types

- `liveMatches`: Contains a list of active matches and scores.
- `subscribed` / `unsubscribed`: Explicit command acknowledgements.
- `snapshot`: Combined point progression (`pointByPoint`) and period statistics (`statistics`).
- `subscriptionEnded` with `reason: "matchEnded"`: Sent when a match leaves the live feed.
- `unsubscribed` with `reason: "sourceErrors"`: Sent if the match polling worker registers three consecutive source failures.
- `error`: Sent when an operation fails (e.g., subscribing to an invalid or concluded match ID). Common codes: `INVALID_MESSAGE`, `INVALID_COMMAND`, `UNKNOWN_COMMAND`, `INVALID_MATCH_ID`, `MATCH_NOT_LIVE`, `SUBSCRIPTION_LIMIT`, `SOURCE_UNAVAILABLE`.

***

### Production Integration Checklist

When moving from our single-target happy-path tutorials to production-grade integrations, ensure your client design accounts for the following server limits and lifecycle behaviors:

- \[ ] **Connection Recovery Strategy:** Subscriptions are maintained in server memory and belong strictly to your active WebSocket connection. If the connection closes, implement exponential backoff, request `liveMatches` again, and resubscribe to desired match IDs that remain active.
- \[ ] **Zero-Subscription Grace Period:** The server closes any connection that maintains zero active subscriptions for 60 seconds (either upon initial connection readiness or after removing/ending the final subscription). Expiry closes the socket immediately with status code `1008` (Policy Violation) and reason `"subscription required"`.
- \[ ] **Snapshot Replacement Semantics:** Each incoming `snapshot` is a full replacement of the match state, not a delta. Overwrite your local storage or memory state for the matching ID completely.
- \[ ] **Command & Connection Limits:** The connection supports at most **200 active subscriptions**. Inbound messages must be text frames and are capped at **16 KiB**; larger commands or binary frames result in immediate connection closure.
- \[ ] **Slow-Consumer Backpressure:** Clients must consume messages promptly. If your client cannot keep up with updates, the server terminates the connection with status `1013` (Try Again Later) and reason `"client cannot keep up"`. Offload expensive database or AI tasks to workers or queues.
- \[ ] **Browser Token Restrictions:** Browser clients cannot set Bearer handshake headers and must authenticate using query parameters (`?token=...`). Since this exposes the token, use a narrowly scoped restricted token or run a server-side relay to mask your primary secrets.
- \[ ] **Billing Fan-Out:** You pay for snapshot writes. Subscribing to the same match from five separate clients results in five distinct fanned-out writes. Use a single central client to ingest the stream, then distribute updates within your internal network to avoid unnecessary event charges.

***

### Pricing

The service runs on a dual billing structure split between event charges and platform resources:

1. **Delivered Snapshots (Pay-Per-Event):** You are billed for successful snapshot writes. One `snapshot-delivered` event is charged for each merged snapshot successfully written to a WebSocket client. Connection handshakes, `liveMatches` queries, command acknowledgements, protocol errors, close frames, and failed/unwritten frames are not charged.
2. **Separate caller-paid platform usage:** Callers separately pay for all underlying compute, memory, data transfer, and automatic residential proxy routing consumed while serving your Standby connection. The Actor routes requests to SofaScore through proxies automatically; no user-side proxy setup is needed.

*Review current pricing rates and account usage ceilings in the Actor's **Pricing** tab and your Apify console billing panel.*

***

### Frequently Asked Questions

#### Why did I receive an empty live matches list?

No matches are currently available in the live feed (common between tournaments or during schedule gaps). Do not poll the readiness endpoint to search for matches; readiness remains only a service-health signal. Since Standby terminates idle connections after 60 seconds, close the connection and request the list again in a later connection.

#### Why is point-by-point or statistics data empty for some matches?

Coverage varies based on tournament tier. The Actor preserves empty lists when the source does not publish tracking data rather than injecting guessed values.

#### Can I retrieve past tournaments or completed match data?

No. This is a live stream. For completed tournaments, historical statistics, player profile splits, and flat files, use [Tennis Scraper](https://apify.com/crawlstone/tennis-scraper).

***

### Support

If you need assistance, please open a ticket on this Actor's **Discussion** tab and include:

- Approximate UTC timestamp of the issue.
- Client language and WebSocket library version.
- The WebSocket close code and close reason, if applicable.
- The command or match ID involved.
- A clear description of what you expected versus what occurred.

**Never share your primary Apify Token, credentials, or authenticated URLs in public support requests.**

## Actor input object example

```json
{}
```

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlstone/sofascore-tennis-data-stream").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("crawlstone/sofascore-tennis-data-stream").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call crawlstone/sofascore-tennis-data-stream --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=crawlstone/sofascore-tennis-data-stream",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "SofaScore Tennis Data Stream",
        "description": "Stream live tennis data from SofaScore over WebSocket, including current scores, accumulated point-by-point records, and match statistics.",
        "version": "1.0",
        "x-build-id": "AuXMgadwdbsQxfCg5"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/crawlstone~sofascore-tennis-data-stream/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-crawlstone-sofascore-tennis-data-stream",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/crawlstone~sofascore-tennis-data-stream/runs": {
            "post": {
                "operationId": "runs-sync-crawlstone-sofascore-tennis-data-stream",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/crawlstone~sofascore-tennis-data-stream/run-sync": {
            "post": {
                "operationId": "run-sync-crawlstone-sofascore-tennis-data-stream",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {}
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
