# Rental to Pay-Per-Event Migration Auditor — before 30 Sept (`highbrow_fame/actor-billing-auditor`) Actor

Apify retires monthly rental pricing on 30 September 2026. An Actor left without future pricing is auto-converted on 1 October and its revenue drops to zero. This audits yours first: ex-rental detection, runs that charged and returned nothing, negative-margin runs, dead tier pricing. Read-only.

- **URL**: https://apify.com/highbrow\_fame/actor-billing-auditor.md
- **Developed by:** [yestrue](https://apify.com/highbrow_fame) (community)
- **Categories:** Developer tools, Automation
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $190.00 / 1,000 actor auditeds

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

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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

## Actor Billing Auditor

**You migrated. Did you migrate correctly?**

Pay-per-event pricing is easy to configure and easy to get wrong. This Actor reads your own Actors'
pricing configuration and run history and tells you where the money is leaking — runs that charged but
produced nothing, runs that cost more than they earned, and tier ladders that quietly do nothing.

On its first run against its author's own Actors it found a net-losing Actor and 7 silently-billed empty runs.

### Your token

**Your token is used only for read API calls during the run and is never stored or transmitted to third
parties.**

That is enforced in code, not just promised:

- The API client refuses any request that is not a `GET`, so no code path — present or future — can
  modify your account.
- The token is held in a closure. It is never written to the dataset, never written to the key-value
  store, and never logged. Anything that does escape into an error message is passed through a scrubber
  that replaces the token with `<redacted-token>` first.
- There are **no external services**. The only host contacted is `api.apify.com`.

The token field is marked `isSecret`, so Apify encrypts it at rest in the run's input.

Create a token at **Settings → API & Integrations**. Read access to your Actors is all it needs.

### What it checks

| # | Check | Basis |
|---|---|---|
| 1 | **Zero-result charged runs** — runs that charged an event while writing nothing to the dataset | run history |
| 3 | **Margin audit** — charged revenue vs the real platform cost of each run, with the dominant cost driver named | run history |
| 4 | **Pricing consistency** — identical tier prices, inverted tier ladders, unpriced events | configuration |
| — | **Ex-rental detection** — whether the Actor was repriced off the retiring rental model, and when | configuration |
| — | **Rental deadline** — for Actors still on rental, days remaining before the automatic conversion | configuration |

Duplicate-start detection and operational-risk checks are planned for v0.2.

#### The findings that matter most

**Zero-result charged runs.** An Actor that charges a per-GB start fee bills on every attempt. When a
selector breaks or a credential expires, the Actor keeps "succeeding", keeps billing, and delivers nothing.
It is invisible in aggregate revenue because revenue goes *up*.

**Negative margin.** Compute is rarely what sinks an Actor — residential proxy transfer usually is. The
audit reads the run's real `usageUsd` breakdown rather than modelling cost from memory and runtime, so the
figure is what you were actually billed, and it names the driver.

**Pricing structure.** Identical prices across every tier (tiering configured but doing nothing) and
inverted tier ladders. These are rarer — about 1.3% of live pay-per-event Actors — but they are exact
findings, not estimates, and they persist silently once set.

#### Case study: our own fleet

The first run of this Actor against its author's own Actors found:

- a **net loss of $10.57 across 55 runs** (−$0.19 per run, 44 of 55 losing money), with residential proxy
  transfer at **98% of cost** and compute under 10% — a compute-based cost model would have called it healthy
- **7 of 55 runs (12.7%) charged but wrote zero rows**, billing for no data
- on a second Actor, a `FAILED` run that still billed four start events

Then it found a bug in itself: its own first run predated its pricing, and the audit scored that as a loss.
Fixed, with a regression test — ex-rental Actors would have hit the same thing on every pre-migration run.

### How to read the numbers

The report separates two kinds of finding, and the distinction is important:

- **Configuration findings are facts.** Pricing structure and rental status are read directly from your
  Actor's configuration. They are exact and complete.
- **Run findings are observations.** Apify does not expose your users' runs to you — `GET /acts/{id}/runs`
  returns only runs *you* started. So run-derived findings are a diagnostic sample of your own runs, not a
  billing statement.

A defect found in your own runs is still real: your users hit the same code path. But the dollar figures
are labelled "observed" and are never extrapolated to a fleet total, because that would be guessing.

### Input

| Field | Type | Default | Notes |
|---|---|---|---|
| `apifyToken` | string, **required**, secret | — | Your own Apify API token |
| `actorIds` | array | `[]` | Leave empty to audit every Actor on your account |
| `lookbackDays` | integer | `30` | Run-history window, 1–365 |

### Output

**Dataset** — one record per Actor: `actorId`, `name`, `pricingModel`, `findings[]` (each with
`severity` of `CRITICAL` / `WARNING` / `INFO`), `estimatedLossUsd`, `margin`, `zeroResult`, `exRental`.

**Key-value store** — `OUTPUT` holds the fleet summary plus the full report; `REPORT.md` holds a
ready-to-read markdown report.

### Pricing

Pay per event, one `actor-audited` event per Actor for which a full report was produced.

- A failed Actor is **not** charged.
- An invalid token exits before the first charge — the run fails rather than "succeeding" empty.
- On the free tier the audit is limited to 3 Actors per run.

### Still on rental pricing?

Rental sunsets on **2026-10-01**. An Actor with no new pricing configured by **2026-09-30** is
automatically converted to pay-per-usage, which pays the developer nothing — rental paid 80% of the
monthly fee, and that becomes $0. Configuring future pricing before the deadline prevents this; the 14-day
notice does not have to elapse first, and an Actor with no subscribers can reprice with immediate effect.

For the migration modelling itself, use Apify's own free
[rental to pay-per-event calculator](https://apify.com/apify/rental-to-pay-per-event-calculator) — it is
purpose-built, and it can submit per-user price overrides to Apify support, which this Actor cannot. This
audit tells you whether the pricing you landed on is actually sound.

### Development

```bash
npm install
npm test
```

Charging is exercised in simulation mode against the real code paths, so the billing gate is tested
without billing anyone:

```bash
ACTOR_TEST_PAY_PER_EVENT=1 ACTOR_USE_CHARGING_LOG_DATASET=1 node src/main.js
```

Charge events are then written to the local `charging_log` dataset instead of being billed.

# Actor input Schema

## `apifyToken` (type: `string`):

Your own Apify API token. Used only for read-only GET calls during this run — it is never logged, never written to the dataset or key-value store, and never sent anywhere except api.apify.com. Create one at Settings → API & Integrations.

## `actorIds` (type: `array`):

Actor IDs to audit. Leave empty to audit every Actor on your account.

## `lookbackDays` (type: `integer`):

How far back to read run history when checking for zero-result and negative-margin runs.

## Actor input object example

```json
{
  "actorIds": [],
  "lookbackDays": 30
}
```

# Actor output Schema

## `report` (type: `string`):

The full report, ready to read as-is: findings per Actor with severity, observed billing on zero-result runs, and margin figures.

## `summary` (type: `string`):

Counts of critical, warning and informational findings across every audited Actor, plus the observed billing total and how many Actors are still on rental pricing.

## `findings` (type: `string`):

One record per audited Actor: pricing model, findings with severity, observed loss, margin statistics and ex-rental status.

## `findingsCsv` (type: `string`):

The same per-Actor records as CSV for spreadsheets.

# 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 = {
    "actorIds": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("highbrow_fame/actor-billing-auditor").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 = { "actorIds": [] }

# Run the Actor and wait for it to finish
run = client.actor("highbrow_fame/actor-billing-auditor").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "actorIds": []
}' |
apify call highbrow_fame/actor-billing-auditor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,highbrow_fame/actor-billing-auditor"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/oSJj1XITkOW7mKbuE/builds/91v7vAiXrCE0NwBG1/openapi.json
