# Product Matcher (`jan_hilgard/productmatcher`) Actor

Cross-shop product matcher: returns a confident match or nothing, never a wrong pair. Give it a sample product URL and target e-shop domains; it finds the same product on each, verified by EAN check-digit, spec agreement, AI variant judge and photo match, with a 0-1 confidence score.

- **URL**: https://apify.com/jan\_hilgard/productmatcher.md
- **Developed by:** [Jan Hilgard](https://apify.com/jan_hilgard) (community)
- **Categories:** E-commerce, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $8.00 / 1,000 successful matches

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.md):

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

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.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/platform/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

## Product Matcher

**Cross-shop product matching that would rather return nothing than the wrong pair.**

Give it a sample product and a list of shops. It finds the *same* product on each
shop — discovers the candidate itself, verifies it with several independent
signals, and returns a confidence score with a reason for every decision. When it
is not sure, it says so and returns no URL. No silent errors. No "closest guess".

Most matchers hand you the nearest result and a number. This one fails loud on an
uncertain match. I built it that way because a wrong pair is worse than no pair —
a bad match quietly poisons a price feed or a catalogue mapping for days before
anyone notices, and by then you have already made decisions on it.

Keywords: product matching, cross-shop product matching, confidence-scored
product matching, variant-aware matching, EAN / GTIN matching, product
deduplication, competitor catalog matching.

---

### What a real run looks like

Sample: **Apple iPhone 17 512 GB, Lavender**. Target shop: one large electronics
retailer. The shop sells many things that look almost right. Here is what the
matcher does with the candidates it found:

````

✗  iPhone 17 256 GB Lavender          rejected — different capacity (256 vs 512 GB)
✗  iPhone 17 Pro 512 GB Lavender      rejected — different model (Pro ≠ base 17)
✗  iPhone 17 512 GB (refurbished)     rejected — opened-box / refurbished, not a new-retail listing
✗  iPhone 17 512 GB Orange            rejected — color + photo mismatch (triple camera)
✗  iPhone 17 512 GB (no image)        rejected — placeholder image, photo check inconclusive
✓  iPhone 17 512 GB Lavender          MATCH  confidence 0.97
consensus: specs + AI variant judge + photo  (3 independent signals)
reason: same model, capacity and color; product photo confirms the variant

```

Five rejections with reasons before one confident match — that's the product.
Anything can return the sixth line. The value is the five lines above it, each with
a reason you can read.

---

### Why it is different

- **No silent errors.** An uncertain candidate is returned as `matched_url: null`
  with a reason, never as a maybe-match. The bar to call something a match is
  deliberately high (precision-first). You can trust a `true` without re-checking
  it by hand.
- **Discovery + match, not just match.** It does not need you to already have both
  catalogs. From the sample alone it *finds* the candidate on each target shop
  (web search → sitemap → the shop's own search box), then verifies it. A plain
  matcher that only compares two finished datasets cannot do the finding part.
- **Variant-aware.** 512 GB vs 256 GB, base vs Pro, lavender vs orange, new vs
  refurbished — these are different products, and they are exactly where naive
  name/price matching breaks. The whole design exists to get the variant right.
- **Every decision is explainable.** Confidence score, which signals fired, which
  layer decided, and a short human reason — per shop, in the output row.

---

### How it works

Per shop, from input to decision:

1. **Find candidates on the shop.** The actor goes and finds the products that could
   be the match on the target shop itself — discovery, not pairing a dataset you
   already have.
2. **Cheap pre-filter.** Obviously-different products are dropped with cheap checks
   before any expensive verification runs, so effort — and error — is not spent on
   things that were never going to match.
3. **Verify the survivors with independent signals.** Each remaining candidate is
   checked by several independent signals (the signals below), not one test.
4. **Consensus.** The confidence score is how many of those independent signals
   agree, not one model's opinion (see the scoring below).
5. **Decide or reject.** Above the threshold it returns the match with a readable
   reason; below it, it returns `null` — never a guess.

Why this is accurate: no decision rests on a single signal, the deterministic
EAN/GTIN check takes precedence wherever a code exists, and the visual check catches
a wrong variant that text alone would miss. That is why it would rather return
nothing than the wrong pair.

For each target domain it discovers candidate URLs, then verifies the best ones
with independent signals and takes a **consensus** — the score is not one model's
opinion, it is how many independent checks agree:

| Signal | What it checks |
|---|---|
| `ean` | EAN / GTIN match, including check-digit validity |
| `specs` | structured spec agreement (brand, model, capacity, …) |
| `ai_judge` | an AI variant judge reads both listings: same product or not, and why |
| `photo` | independent product-photo comparison of the matched variant |

`confidence_score` is `0`–`1` and reflects the consensus:

```

EAN match ........................ 0.99
3 independent signals ............ 0.97
2 independent signals ............ 0.92
1 signal ......................... 0.85
below threshold → url: null ...... "uncertain", returned but not a match

````

A candidate that no positive layer confirms is returned with `matched_url: null`.
That is a feature, not a gap.

Mechanically: the actor is a thin client. The heavy work (headed browser, search,
LLM judging, photo comparison) runs on the [data.hilgard.cz](https://data.hilgard.cz)
service. The actor starts a **resumable job** (`POST /api/match/jobs` → `{ jobId }`),
streams its progress over SSE (`GET /api/match/jobs/:id/stream?cursor=N`), and
writes results to the dataset. A match can run minutes to hours, so the job runs
server-side independently of the connection: if the stream drops, the actor
**reconnects to the same job from the last event it saw** (cursor) — no lost work,
no duplicate logs. If the service has no job API, it falls back to the legacy
synchronous `POST /api/match` stream.

---

### Input

```jsonc
{
  "productPairs": [
    {
      "url": "https://www.alza.cz/apple-iphone-17-512gb",
      "domains": ["datart.cz", "mall.cz"]   // 1–20 target domains
    }
  ],
  "includeDebug": false,        // optional, keep the _debug block
  "requestTimeoutSecs": 3600,   // optional, total per-pair budget across reconnects
  "maxReconnects": 20,          // optional, give up after N stalled reconnects
  "reconnectBackoffSecs": 3     // optional, delay between reconnects
}
````

Each item in `productPairs` is one matching job. `url` must be an `http(s)` URL and
`domains` must contain 1–20 non-empty domains. Pairs are processed sequentially.
`requestTimeoutSecs` is the **total** budget for one pair across all reconnects;
`maxReconnects` only bounds *consecutive* reconnects that make no progress, so a
healthy long-running match is not cut short.

### Output

One dataset row **per target domain**, with the sample product's profile inlined:

```jsonc
{
  "source_url": "https://www.alza.cz/apple-iphone-17-512gb",
  "source_domain": "alza.cz",
  "product_name": "Apple iPhone 17 512 GB",
  "brand": "Apple",
  "model": "iPhone 17 512GB",
  "ean": "1949483485734",
  "source_price": 27990,
  "currency": "CZK",
  "image_url": "https://...",

  "matched_domain": "datart.cz",
  "matched_url": "https://datart.cz/iphone-17-512gb",  // null when no confident match
  "confidence_score": 0.99,
  "method": "sitemap",          // sitemap | brave | google | null
  "reason": "EAN match",
  "decided_by": "ean",          // ean | ai_variant_judge | photo | null
  "signals": ["ean"],           // ean | specs | ai_judge | photo
  "matched_fields": [{ "field": "ean", "agree": true }],
  "price_candidate": 26490,     // observed price on the matched shop

  "scraped_at": "2026-06-18T10:00:00.000Z",
  "success": true               // false when matched_url is null
}
```

When `includeDebug` is `true`, each row also carries the service's `_debug` block.
If a pair fails entirely, one placeholder row per requested domain is written with
`success: false` and an `error` message.

***

### Use cases

- **Pricing intelligence.** Map your product to the same product on competitor
  shops, then compare prices on pairs you can trust. `price_candidate` is the
  observed price on the matched shop; the comparison is yours to make.
- **Competitor monitoring.** Track whether — and where — a given product appears
  across a set of shops over time.
- **Catalog deduplication / matching.** Link the same product across two catalogs,
  variant-correct, with a confidence you can threshold on.

It is built for correctness on the hard cases (variants, refurbished, near-misses),
not for sheer volume. Pick it when getting the pair *right* matters more than
getting a pair at any cost.

***

### Pricing — two tiers

This actor uses **Pay Per Event**, with two events:

- **`shop-checked`** — a small fee for each shop we check.
- **`successful-match`** — the main fee, charged additionally when a product is
  confirmed on a shop (a `success: true` row with a `matched_url`, confidence above
  the threshold).

The `shop-checked` fee pays for **discovery**, not for a miss. Most matchers take
two finished catalogs you already have and pair them. This one does not assume you
have the other side — it goes and finds the product on each shop itself: web
search, anti-bot fetch, vision, multi-signal verification (EAN/GTIN, specs, AI
variant judge, photo). That search is the expensive part, and it runs in full
whether or not the product turns out to be on the shop. So you pay a small fee per
shop checked for that work, and the main fee only when a shop yields a confirmed
match.

To be clear upfront: a shop where we find nothing still costs the `shop-checked`
fee, because the discovery work was done there too. A confirmed match costs
`shop-checked` + `successful-match`.

No flat fee. No per-SLA pricing. You are billed per event, for work actually done.
The current price of each event is in the Apify Console pricing tab.

***

### When NOT to use this

I would rather you not waste money, so:

- **You already have both full catalogs (your products + theirs), cleanly keyed.**
  Then you do not need discovery — a plain dataset-to-dataset matcher is cheaper.
  This actor earns its price when you *don't* have the other side and need it found
  and verified.
- **You only have a handful of one-off products.** Just paste them into the
  [data.hilgard.cz](https://data.hilgard.cz) UI and read the result. No actor run
  needed.
- **You want the cheapest possible "good enough" matching at huge volume.** This
  one optimizes for being right on hard variants, not for being the cheapest. If a
  few wrong pairs in a thousand are acceptable to you, a lighter tool will cost
  less.

If the correctness story above is not what you need, one of these is the better
call.

***

### About

Built on the [data.hilgard.cz](https://data.hilgard.cz) matching engine — the same
self-healing stack that does anti-bot fetching, model-by-meaning extraction, and
independent verification, applied to cross-shop matching.

By Jan Hilgard (founder of Hosting90, acquired; core contributor to vllm-mlx). The
precision-first stance is deliberate: I would rather ship a matcher you can trust
on the hard cases than one that always answers.

### Development

```bash
npm install
npm run build      # tsc → dist/
npm run start:dev  # tsx src/main.ts, reads .actor/INPUT.json
```

# Actor input Schema

## `productPairs` (type: `array`):

List of matching jobs. Each item is a sample product URL plus 1–20 target e-shop domains to find that same product on.

## `includeDebug` (type: `boolean`):

When enabled, keep the service's internal \_debug block (tokens, per-domain internals) in each output row.

## `requestTimeoutSecs` (type: `integer`):

Total time budget for one product pair's match, ACROSS reconnects. The match runs server-side as a job, so a dropped connection is reconnected automatically until this budget is spent. Matching can take many minutes to hours.

## `maxReconnects` (type: `integer`):

How many times to reconnect to a job after the stream drops WITHOUT receiving new events before giving up on that pair. Healthy long runs reset this counter as they make progress.

## `reconnectBackoffSecs` (type: `integer`):

Delay before reconnecting to a job stream after the connection drops.

## Actor input object example

```json
{
  "productPairs": [
    {
      "url": "https://www.alza.cz/apple-iphone-17-512gb",
      "domains": [
        "datart.cz",
        "mall.cz"
      ]
    }
  ],
  "includeDebug": false,
  "requestTimeoutSecs": 3600,
  "maxReconnects": 20,
  "reconnectBackoffSecs": 3
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

# 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 = {
    "productPairs": [
        {
            "url": "https://www.alza.cz/apple-iphone-17-512gb",
            "domains": [
                "datart.cz",
                "mall.cz"
            ]
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("jan_hilgard/productmatcher").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 = { "productPairs": [{
            "url": "https://www.alza.cz/apple-iphone-17-512gb",
            "domains": [
                "datart.cz",
                "mall.cz",
            ],
        }] }

# Run the Actor and wait for it to finish
run = client.actor("jan_hilgard/productmatcher").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 '{
  "productPairs": [
    {
      "url": "https://www.alza.cz/apple-iphone-17-512gb",
      "domains": [
        "datart.cz",
        "mall.cz"
      ]
    }
  ]
}' |
apify call jan_hilgard/productmatcher --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Product Matcher",
        "description": "Cross-shop product matcher: returns a confident match or nothing, never a wrong pair. Give it a sample product URL and target e-shop domains; it finds the same product on each, verified by EAN check-digit, spec agreement, AI variant judge and photo match, with a 0-1 confidence score.",
        "version": "0.0",
        "x-build-id": "O12dLdteC1fMQPAj8"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/jan_hilgard~productmatcher/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-jan_hilgard-productmatcher",
                "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/jan_hilgard~productmatcher/runs": {
            "post": {
                "operationId": "runs-sync-jan_hilgard-productmatcher",
                "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/jan_hilgard~productmatcher/run-sync": {
            "post": {
                "operationId": "run-sync-jan_hilgard-productmatcher",
                "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",
                "required": [
                    "productPairs"
                ],
                "properties": {
                    "productPairs": {
                        "title": "Product pairs",
                        "type": "array",
                        "description": "List of matching jobs. Each item is a sample product URL plus 1–20 target e-shop domains to find that same product on."
                    },
                    "includeDebug": {
                        "title": "Include debug data",
                        "type": "boolean",
                        "description": "When enabled, keep the service's internal _debug block (tokens, per-domain internals) in each output row.",
                        "default": false
                    },
                    "requestTimeoutSecs": {
                        "title": "Total per-pair budget (seconds)",
                        "minimum": 60,
                        "maximum": 21600,
                        "type": "integer",
                        "description": "Total time budget for one product pair's match, ACROSS reconnects. The match runs server-side as a job, so a dropped connection is reconnected automatically until this budget is spent. Matching can take many minutes to hours.",
                        "default": 3600
                    },
                    "maxReconnects": {
                        "title": "Max reconnects without progress",
                        "minimum": 1,
                        "maximum": 1000,
                        "type": "integer",
                        "description": "How many times to reconnect to a job after the stream drops WITHOUT receiving new events before giving up on that pair. Healthy long runs reset this counter as they make progress.",
                        "default": 20
                    },
                    "reconnectBackoffSecs": {
                        "title": "Reconnect backoff (seconds)",
                        "minimum": 0,
                        "maximum": 120,
                        "type": "integer",
                        "description": "Delay before reconnecting to a job stream after the connection drops.",
                        "default": 3
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
