# OIDC Discovery & JWKS Rotation Monitor (`monema/oidc-jwks-rotation-monitor`) Actor

Track public OpenID Connect discovery metadata and JWKS signing-key changes across runs. Emit structured rotation, endpoint, algorithm, and key-overlap signals for scheduled identity operations.

- **URL**: https://apify.com/monema/oidc-jwks-rotation-monitor.md
- **Developed by:** [Maarten Vreeburg](https://apify.com/monema) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.00 / 1,000 successful oidc issuer checks

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/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

## OIDC Discovery & JWKS Rotation Monitor

Track public **OpenID Connect discovery metadata and JSON Web Key Sets (JWKS)** between scheduled runs. Each issuer produces one structured dataset row with key identifiers, signing algorithms, a persistent snapshot hash, and review-oriented changes such as key additions/removals, endpoint changes, same-`kid` key-material changes, and missing required algorithms.

This Actor is for identity/platform, SRE, and integration teams that depend on public third-party identity issuers. It creates a lightweight change ledger that can feed Apify schedules, webhooks, and downstream incident or vendor-management workflows.

It does **not** validate live tokens, exercise a login flow, refresh your application's own JWKS cache, prevent authentication failures, or prove whether a provider used a safe rotation overlap. Production token validators should still use maintained libraries that refresh keys correctly when an unknown `kid` appears.

> **Independent community Actor:** This Actor is not affiliated with or endorsed by the OpenID Foundation, Google, Auth0, Okta, Microsoft, Amazon Web Services, or any identity provider whose public endpoints you monitor. Provider metadata remains the provider's source material; verify material identity/security decisions against the provider's documentation and your own runtime telemetry.

### Why monitor discovery and JWKS?

OIDC clients commonly discover endpoint URLs and signing keys automatically. That native behavior is essential, but a separate scheduled record can still help teams:

- notice that a vendor added or removed a published key;
- review issuer, `jwks_uri`, authorization, token, revocation, or introspection endpoint changes;
- detect key material changing while the same `kid` remains present;
- check that required signing algorithms are still advertised or represented by current keys;
- keep a provider-independent history across otherwise ephemeral application caches;
- route `changed` rows into an existing Apify integration or webhook workflow.

A monitor is an observability aid, not a replacement for runtime token-validation metrics. Polling can miss brief transitions between checks, so `no_key_overlap_observed_between_checks` means exactly that—it does not prove that no overlap occurred at any time.

### Input

| Field | Required | Description |
|---|---:|---|
| `monitorId` | Yes | Stable ID for one independent watchlist. Reuse it across scheduled runs to retain the same baselines. |
| `targets` | Yes | 1–50 public HTTPS OIDC discovery targets. Duplicate `discoveryUrl` values are checked once. |
| `targets[].discoveryUrl` | Yes | Full public `.well-known/openid-configuration` URL. |
| `targets[].label` | No | Internal environment, vendor, or owner label. |
| `targets[].expectedIssuer` | No | Exact `issuer` value expected in the discovery document. A mismatch is emitted without overwriting the previous successful baseline. |
| `targets[].requiredSigningAlgorithms` | No | Exact algorithms that should remain advertised or represented by current keys, for example `RS256` or `ES256`. |
| `timeoutSeconds` | No | Per-request timeout, 5–60 seconds (default `30`). |
| `maxConcurrency` | No | Issuers processed concurrently, 1–5 (default `3`). |

The default input checks Google's public OIDC discovery document and JWKS without credentials, so a default run produces a non-empty dataset. Replace the default `monitorId` and target before creating a production schedule.

Example:

```json
{
  "monitorId": "production-external-identity",
  "targets": [
    {
      "label": "Primary workforce IdP",
      "discoveryUrl": "https://accounts.google.com/.well-known/openid-configuration",
      "expectedIssuer": "https://accounts.google.com",
      "requiredSigningAlgorithms": ["RS256"]
    }
  ],
  "timeoutSeconds": 30,
  "maxConcurrency": 3
}
````

### Output

Every processed target emits one dataset row.

#### Successful comparison statuses

| `status` | Meaning |
|---|---|
| `initial_snapshot` | The first validated discovery/JWKS summary was stored. |
| `unchanged` | Monitored discovery fields and normalized public-key summaries match the previous successful snapshot. |
| `changed` | At least one monitored metadata or key field changed. |

#### Non-billable error statuses

| `status` | Meaning |
|---|---|
| `discovery_fetch_error` | Discovery URL was blocked, unavailable, redirected unsafely, too large, or returned a network/HTTP error. |
| `discovery_validation_error` | Discovery response was invalid, malformed, too deep, or lacked required `issuer`/`jwks_uri` fields. |
| `issuer_mismatch` | The returned issuer did not exactly match `expectedIssuer`. |
| `jwks_fetch_error` | The published JWKS URL could not be fetched safely. |
| `jwks_validation_error` | JWKS JSON was invalid, empty, oversized, or exposed private/symmetric key fields that the Actor refuses to store. |

Common successful fields include:

- `issuer`, `discovery_url`, `final_discovery_url`, `jwks_uri`, and `final_jwks_uri`;
- `authorization_endpoint`, `token_endpoint`, and advertised/key signing algorithms;
- `key_count`, `signing_key_count`, `key_ids`, `key_types`, duplicate IDs, and keys without IDs;
- `required_algorithms_missing` and `requirements_status`;
- `content_hash`, `previous_hash`, and `state_store_mode`;
- `added_key_ids`, `removed_key_ids`, `retained_key_ids`, and `same_kid_material_changed_ids`;
- `rotation_pattern`, priority counts, `change_summary`, and bounded `changes` records.

#### Rotation-pattern labels

- `initial_snapshot` / `no_change` — baseline or no monitored change.
- `key_addition_or_prepublication` — at least one key appeared and none disappeared.
- `key_retirement` — at least one key disappeared and none appeared.
- `partial_rotation_with_retained_kid` — keys appeared and disappeared while at least one prior `kid` remained.
- `no_key_overlap_observed_between_checks` — keys appeared and disappeared with no shared `kid` across the two observed snapshots. Polling cannot prove what happened between those snapshots.
- `same_kid_material_changed` — a retained `kid` now has different public key material or metadata and deserves prompt review.
- `metadata_only_change` / `key_metadata_changed` — monitored fields changed outside the simpler rotation patterns.

`review_priority` values are conservative routing hints (`high`, `review`, `informational`), not security findings or outage predictions.

### Persistence and scheduling

Successful normalized snapshots are stored in the named key-value store `oidc-jwks-rotation-monitor-state-v1`. The Actor does not rely on the default run-scoped store. Snapshot keys are SHA-256 derivatives of `monitorId` + `discoveryUrl`, so stable IDs retain history and separate watchlists do not collide.

Schedule the Actor at a provider-appropriate interval and route `changed`, error, or requirement rows through Apify integrations. The Actor itself sends no email, DM, chat message, or webhook.

Failed fetches, invalid documents, and issuer mismatches do not overwrite a prior successful baseline.

### Charging behavior

The implementation emits one `oidc_issuer_check` charge event only after both public documents are fetched, validated, normalized, compared, and stored. Invalid URLs, fetch failures, validation failures, and issuer mismatches are not charged. Refer to the live Store listing for the current event price.

The Actor honors Apify run charge limits before emitting the next billed dataset item.

### Security and data handling

- Production input accepts only public HTTPS endpoints on port 443.
- URL credentials, fragments, control characters, non-ASCII raw URLs, and non-standard ports are rejected.
- Discovery and JWKS redirects are bounded and revalidated on every hop.
- DNS is resolved before connecting; every resolved address must be globally routable. The socket connects to that already validated address while TLS certificate validation and SNI still use the original hostname, reducing DNS-rebinding exposure.
- Private, loopback, link-local, multicast, and reserved destinations are blocked.
- Discovery responses are capped at 512 KB; JWKS responses are capped at 1 MB; compressed responses are rejected.
- JSON is capped at 64 nesting levels and 50,000 nodes. Duplicate object fields and non-finite numbers are rejected.
- JWKS is capped at 100 keys.
- If a public JWKS contains private RSA/EC parameters or symmetric key material, the Actor rejects it and does not persist or reproduce those fields.
- Stored state contains normalized discovery fields and public-key fingerprints/summaries, not raw JWKS key material or complete source documents.
- No authentication-header, cookie, client-secret, token, or private-network input is supported.

### Local development

```bash
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/python smoke_test.py
npx --yes apify-cli validate-schema
npx --yes apify-cli run --purge
```

The deterministic smoke test uses a process-only local fixture mode and verifies:

1. `initial_snapshot`;
2. `unchanged` with named-store reuse;
3. `changed` after a key rotation and metadata update;
4. added/removed/retained key IDs and a partial-overlap pattern;
5. private URL blocking, deep/duplicate JSON rejection, private/symmetric JWK rejection, no-observed-overlap classification, and a one-event PPE charge limit.

The local private-fixture switch is environment-only and is not exposed through Actor input.

### Limitations

- Public endpoints only; private enterprise IdPs and authenticated metadata are intentionally unsupported.
- The Actor does not download `x5u` URLs, certificate chains, external references, tokens, or user information.
- Public JWK fingerprints include the published public JWK object, so metadata-only changes inside a key can alter its fingerprint.
- A scheduled snapshot cannot observe transitions that occur entirely between runs.
- Required-algorithm checks are simple exact membership checks, not cryptographic-policy advice.
- Native OIDC/JWT libraries may already refresh discovery and JWKS caches. This Actor adds an independent scheduled record; it does not modify those caches.

# Actor input Schema

## `monitorId` (type: `string`):

Stable ID for this independent issuer watchlist, such as production-external-identity.

## `targets` (type: `array`):

Each target needs a public HTTPS OpenID Connect discovery-document URL. Optional expected issuer and required algorithms add exact checks.

## `timeoutSeconds` (type: `integer`):

Per-request timeout for discovery and JWKS requests.

## `maxConcurrency` (type: `integer`):

Number of issuer checks processed in parallel.

## Actor input object example

```json
{
  "monitorId": "qa-default",
  "targets": [
    {
      "label": "Google Accounts",
      "discoveryUrl": "https://accounts.google.com/.well-known/openid-configuration",
      "expectedIssuer": "https://accounts.google.com",
      "requiredSigningAlgorithms": [
        "RS256"
      ]
    }
  ],
  "timeoutSeconds": 30,
  "maxConcurrency": 3
}
```

# 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 = {
    "targets": [
        {
            "label": "Google Accounts",
            "discoveryUrl": "https://accounts.google.com/.well-known/openid-configuration",
            "expectedIssuer": "https://accounts.google.com",
            "requiredSigningAlgorithms": [
                "RS256"
            ]
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("monema/oidc-jwks-rotation-monitor").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 = { "targets": [{
            "label": "Google Accounts",
            "discoveryUrl": "https://accounts.google.com/.well-known/openid-configuration",
            "expectedIssuer": "https://accounts.google.com",
            "requiredSigningAlgorithms": ["RS256"],
        }] }

# Run the Actor and wait for it to finish
run = client.actor("monema/oidc-jwks-rotation-monitor").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 '{
  "targets": [
    {
      "label": "Google Accounts",
      "discoveryUrl": "https://accounts.google.com/.well-known/openid-configuration",
      "expectedIssuer": "https://accounts.google.com",
      "requiredSigningAlgorithms": [
        "RS256"
      ]
    }
  ]
}' |
apify call monema/oidc-jwks-rotation-monitor --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "OIDC Discovery & JWKS Rotation Monitor",
        "description": "Track public OpenID Connect discovery metadata and JWKS signing-key changes across runs. Emit structured rotation, endpoint, algorithm, and key-overlap signals for scheduled identity operations.",
        "version": "0.1",
        "x-build-id": "hZWb78flWZ5nJxAO2"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/monema~oidc-jwks-rotation-monitor/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-monema-oidc-jwks-rotation-monitor",
                "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/monema~oidc-jwks-rotation-monitor/runs": {
            "post": {
                "operationId": "runs-sync-monema-oidc-jwks-rotation-monitor",
                "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/monema~oidc-jwks-rotation-monitor/run-sync": {
            "post": {
                "operationId": "run-sync-monema-oidc-jwks-rotation-monitor",
                "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": [
                    "monitorId",
                    "targets"
                ],
                "properties": {
                    "monitorId": {
                        "title": "Monitor ID",
                        "minLength": 1,
                        "maxLength": 200,
                        "type": "string",
                        "description": "Stable ID for this independent issuer watchlist, such as production-external-identity.",
                        "default": "qa-default"
                    },
                    "targets": {
                        "title": "OIDC issuers to monitor",
                        "minItems": 1,
                        "maxItems": 50,
                        "type": "array",
                        "description": "Each target needs a public HTTPS OpenID Connect discovery-document URL. Optional expected issuer and required algorithms add exact checks.",
                        "items": {
                            "type": "object",
                            "properties": {
                                "label": {
                                    "title": "Internal label",
                                    "type": "string",
                                    "description": "Optional environment, vendor, or owner label.",
                                    "maxLength": 200
                                },
                                "discoveryUrl": {
                                    "title": "OIDC discovery URL",
                                    "type": "string",
                                    "description": "Public HTTPS URL returning the issuer's .well-known/openid-configuration JSON document.",
                                    "minLength": 1,
                                    "maxLength": 2048
                                },
                                "expectedIssuer": {
                                    "title": "Expected issuer",
                                    "type": "string",
                                    "description": "Optional exact issuer value expected in the discovery document.",
                                    "maxLength": 2048
                                },
                                "requiredSigningAlgorithms": {
                                    "title": "Required signing algorithms",
                                    "type": "array",
                                    "description": "Optional exact algorithm names that must remain advertised or represented by current keys, for example RS256 or ES256.",
                                    "maxItems": 20,
                                    "items": {
                                        "type": "string",
                                        "minLength": 1,
                                        "maxLength": 100
                                    }
                                }
                            },
                            "required": [
                                "discoveryUrl"
                            ]
                        },
                        "default": [
                            {
                                "label": "Google Accounts",
                                "discoveryUrl": "https://accounts.google.com/.well-known/openid-configuration",
                                "expectedIssuer": "https://accounts.google.com",
                                "requiredSigningAlgorithms": [
                                    "RS256"
                                ]
                            }
                        ]
                    },
                    "timeoutSeconds": {
                        "title": "Request timeout (seconds)",
                        "minimum": 5,
                        "maximum": 60,
                        "type": "integer",
                        "description": "Per-request timeout for discovery and JWKS requests.",
                        "default": 30
                    },
                    "maxConcurrency": {
                        "title": "Maximum concurrent issuers",
                        "minimum": 1,
                        "maximum": 5,
                        "type": "integer",
                        "description": "Number of issuer checks processed in parallel.",
                        "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
