# SEO Retainer Overservice Audit with Proof Rows (`steadyworks/seo-retainer-overservice-audit`) Actor

Audit any SEO retainer in one run by joining quoted scope against actual delivered work to surface overservice hours with evidence rows. This Actor is the one-run audit only with no weekly tracking in this Actor; it never monitors anything. $0.30/audit; demo is $0 trial.

- **URL**: https://apify.com/steadyworks/seo-retainer-overservice-audit.md
- **Developed by:** [steadyworks](https://apify.com/steadyworks) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.18 / completed audit

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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## SEO Retainer Overservice Audit with Proof Rows

Audit any SEO retainer in one run by joining quoted scope against actual delivered work to surface overservice hours with evidence rows. Paste two small CSV-shaped lists — quoted hours and actual hours — and get one proof row per overservice client with unbilled dollars, margin impact, and repricing numbers. \[Try it — the input opens prefilled with a $0 demo.]

This Actor is the one-run audit only with no weekly tracking in this Actor; it never monitors anything.

Price: `audit-completed` $0.30 per completed audit (rows or zero-leak quiet) · the fixed demo input runs a $0 trial with no charge · floor $0.31 (charge limits below this skip billing at $0 with counts only). Console Pricing tab is authoritative.

### What it does / What you get

Find unbilled SEO retainer hours before they eat your margin. This Actor compares what you quoted against what you actually worked and prices the gap — one run, no logins, no fetching, no monitoring.

- **Quoted-vs-actual join** — matches each client + service pair across your quote rows and your time-tool rows.
- **Overservice proof rows** — one dataset row per leaking pair with `unbilledAmount`, `marginErasedPct`, and `phantomFte`.
- **Evidence reference on every row** — `evidenceUrl` points at the winning quote-row index plus `checkedAt` and a check notice, so each number is verifiable.
- **Repricing numbers (arithmetic only)** — `repricingHrs`, `repricingRate`, and `repricingFeeUplift` suggest the corrected fee; you send it, the tool never pushes anything.
- **Quiet suppression** — pairs at or inside scope emit nothing; a clean book returns zero rows by design.
- **Run summary in KV `OUTPUT`** — counts, quiet flag, and billing keys (`billed`, `chargeUsd`, `trial`, `skip`) for every completed audit.
- **Privacy by design** — a `person` column is accepted and dropped at ingest; person-level data never appears in any row.

### Quick start

1. Click **Try for free** — the input opens prefilled with the $0 demo (5 quote + 5 actual rows).
2. Keep the demo labels (`runId`, `scopeBook`, `checkedAt`) or set your own.
3. Click **Save & Start**, then open the **Dataset** tab.
4. Check the 3 overservice rows and the unbilled total of 2280 — this run is the $0 trial, no charge.
5. Replace the rows with your own book (max 5 + 5 rows) and run again for a $0.30 audit.

### Input

Minimal JSON (required-only — all five fields are required, so this is also the full shape; values below equal the schema prefill exactly):

```json
{
  "quoteCsv": [
    {"client": "Acme", "quotedHrs": 40, "rate": 90, "service": "SEO-retainer"},
    {"client": "Acme", "quotedHrs": 20, "rate": 120, "service": "PPC"},
    {"client": "Beta", "quotedHrs": 10, "rate": 100, "service": "Web-care"},
    {"client": "Gamma", "quotedHrs": 30, "rate": 80, "service": "SEO Monthly"},
    {"client": "Delta", "quotedHrs": 15, "rate": 150, "service": "Audit"}
  ],
  "actualCsv": [
    {"client": "Acme", "service": "SEO-retainer", "date": "2026-09-01", "actualHrs": 52},
    {"client": "Acme", "service": "PPC", "date": "2026-09-02", "actualHrs": 20},
    {"client": "Beta", "service": "Web-care", "date": "2026-09-03", "actualHrs": 18},
    {"client": "Gamma", "service": "SEO Monthly", "date": "2026-09-04", "actualHrs": 35},
    {"client": "Delta", "service": "Audit", "date": "2026-09-05", "actualHrs": 12}
  ],
  "runId": "demo-audit-001",
  "scopeBook": "demo-book-001",
  "checkedAt": "2026-09-28T12:00:00Z"
}
```

| field | type | required | default | units | limits |
|---|---|---|---|---|---|
| `quoteCsv` | array of objects (`client`, `service`, `quotedHrs`, `rate`, optional `retainerFee`) | yes | — | rows | 1–5 rows (`maxItems: 5`) |
| `actualCsv` | array of objects (`client`, `service`, `date`, `actualHrs`, optional `person` dropped at ingest) | yes | — | rows | 1–5 rows (`maxItems: 5`) |
| `runId` | string | yes | — | label | min length 1, echoed in the report |
| `scopeBook` | string | yes | — | label | min length 1, echoed on every row |
| `checkedAt` | string | yes | — | ISO-8601 date-time | stamped on every row |

Job-titled recipes (one-line each):

- `demo trial` — prefill as-is → 3 rows, $0 trial, no charge.
- `agency monthly book` — 3 quote + 3 actual leaking pairs → 3 rows, $0.30.
- `full-cap boundary` — 5 quote + 5 actual rows including at-scope quiet pairs → 3 rows, $0.30.
- `quiet check` — every pair at or inside scope → 0 rows by design, still a completed $0.30 audit.

Over-cap books (a 6th row on either side) are rejected by the platform schema before the run starts — $0, no dataset, no charge.

### Output

Overservice rows go to the **default dataset** (one item per overservice client + service); the run summary goes to **`OUTPUT` in the default key-value store**. Quiet audits and rejections write `OUTPUT` with zero dataset rows.

Dataset fields (15 per item; `duplicateNote` only where quote rows repeated the pair):

| field | type | meaning |
|---|---|---|
| `client` / `service` | string | pair identity, as written in your quote |
| `quotedHrs` / `actualHrs` | number | quoted hours vs summed actual hours |
| `unbilledAmount` | number (USD) | `(actualHrs − quotedHrs) × rate`, positive only |
| `phantomFte` | number | excess hours over a 160h month, informational |
| `marginErasedPct` | number | share of the contracted fee given away, in percentage points |
| `repricingHrs` / `repricingRate` / `repricingFeeUplift` | number | suggested corrected hours, rate, and fee uplift (arithmetic only) |
| `duplicateNote` | string (optional) | records collapsed duplicate quote rows, first row wins |
| `scopeBook` / `evidenceUrl` / `checkedAt` / `notice` | string | book label, source-row reference, timestamp, check notice |

Real example rows (shortened for viewing — 2 of the 3 demo rows):

```json
{ "client": "Acme", "service": "SEO-retainer", "quotedHrs": 40, "actualHrs": 52, "unbilledAmount": 1080, "phantomFte": 0.075, "marginErasedPct": 30.0, "repricingHrs": 52, "repricingRate": 90, "repricingFeeUplift": 1080, "scopeBook": "demo-book-001", "evidenceUrl": "file:fixtures/demo-audit/input.json#/quoteCsv/0", "checkedAt": "2026-09-28T12:00:00Z", "notice": "checked on record" }
```

```json
{ "client": "Beta", "service": "Web-care", "quotedHrs": 10, "actualHrs": 18, "unbilledAmount": 800, "phantomFte": 0.05, "marginErasedPct": 80.0, "repricingHrs": 18, "repricingRate": 100, "repricingFeeUplift": 800, "scopeBook": "demo-book-001", "evidenceUrl": "file:fixtures/demo-audit/input.json#/quoteCsv/2", "checkedAt": "2026-09-28T12:00:00Z", "notice": "checked on record" }
```

<details>
<summary>Full OUTPUT record shape (KV <code>OUTPUT</code>)</summary>

```json
{ "ok": true, "rowsEmitted": 3, "report": { "runId": "demo-audit-001", "scopeBook": "demo-book-001", "checkedAt": "2026-09-28T12:00:00Z", "clientsChecked": 4, "leakingCount": 3, "unbilledTotal": 2280, "repricingCsvRows": 3 }, "quiet": false, "billed": false, "chargeUsd": 0, "chargeEvent": null, "trial": true, "skip": false }
```

Pin-skipped runs return counts with `{ "ok": true, "rowsEmitted": 0, "billed": false, "chargeUsd": 0, "skip": true, "skipReason": "PIN_BELOW_PRICE" }` and no dataset rows. Rejections return `{ "ok": false, "status": "HARD-FAIL", "reason": "…", "billed": false }` with zero rows. Designed outcomes (completed, quiet, skipped, rejected) all finish SUCCEEDED; only genuine crashes fail.

</details>

Runs finish in seconds on any allowed book size. Download rows as CSV or JSON from the Dataset tab; the `repricing` dataset view shows the suggested-fee columns together.

### How much will it cost?

`from $0.30 / completed audit` — one flat price on every plan (Free / Starter / Scale / Business all $0.30). Billable event: `audit-completed`, fired exactly once per COMPLETED audit — with rows or zero-leak quiet alike (per-audit, never per-row). The frozen demo input, rejections, over-cap trips, and pin-skips never charge.

| plan | $/completed audit |
|---|---|
| Free / Starter / Scale / Business | $0.30 / $0.30 / $0.30 / $0.30 |

Worked math:

- 1 demo-trial audit (prefill as-is) → **$0** (no charge call, logged as trial).
- 1 real audit (any 1–5 + 1–5 book, rows or quiet) → **$0.30**.
- 10-audit monthly loop → **$3.00**.
- $5 free credit → **≈16 real audits** after the $0 demo.

Caps, floor, quiet costs: `maxItems: 5` on each CSV is the cost ceiling — bigger books never reach the run and cost $0. Floor **$0.31** (minimal max-total-charge): a charge limit below it skips billing at $0 with counts only and no dataset rows; set `ACTOR_MAX_TOTAL_CHARGE_USD` at or above it for real audits. $0.31 is also the platform's minimum settable limit for this actor, so no settable value falls between the $0.30 audit price and the floor — the two thresholds coincide in practice. No usage add-on (pay-per-event-plus-usage stays OFF), no proxy or AI multipliers, start event at platform default.

`event:audit-completed | $/audit 0.30/0.30/0.30/0.30 (Free/Starter/Scale/Business) | includes_usage:false | billed_on_empty:true (zero-leak quiet audits bill) | caps:[quoteCsv maxItems 5, actualCsv maxItems 5] | quiet:[actor-start default]`

### Trial / Free tier

$5 credit ≈ 16 real audits plus unlimited $0 demo runs. The first run is prefilled and small (5 + 5 rows, the frozen demo envelope): it rides the $0 trial path with no charge call. Any one-byte change to the demo input makes it a real $0.30 audit — that is the anti-farming rule, and it keeps copy-paste agent loops free. Same 5 + 5 caps on free; no paid plan needed for the demo or your first audits.

Click **Try for free** — input opens prefilled. Start as-is, check rows, then run your own book.

### Compatibility

Works with any 2-CSV audit joining quoted scope against actual hours. Verified live on anonymized excerpts, Oct 2026:

- **Over-scope excerpt** — quoted-vs-actual pair with actual above quoted emitted 1 proof row with evidence reference, Oct 2026.
- **At-scope quiet excerpt** — pairs at or inside scope correctly suppressed to 0 rows, Oct 2026.
- **Frozen demo envelope** — synthetic 5 + 5 demo emitted 3 rows with unbilled total 2280 on the $0 trial path, Oct 2026.

Not covered: over-cap books above 5 + 5 rows, login-shaped or malformed input. These are rejected with zero rows — never a guessed row.

*Proof excerpts are anonymized; no affiliation, endorsement, or sponsorship implied.*

### What people use it for

- **Agency owner month-end check** — join this month's quote against the time-tool export, find every leaking retainer.
- **Retainer repricing evidence** — take the suggested fee uplift into the renewal conversation as arithmetic, not assertion.
- **Scope-creep proof** — show the client which service grew past its hours, with a source reference per pair.
- **Clean-month verification** — run a quiet book to prove nothing leaked, still one flat $0.30.

### What this Actor does NOT do

- Does not export a repricing CSV — one-run audit only; proof rows stay in the dataset.
- Does not keep weekly history or benchmarks — no weekly tracking in this Actor.
- Does not fetch pages, take logins, or monitor anything — owner-assembled rows in, evidence rows out.
- Does not emit person-level verdicts — suggested numbers are arithmetic only; verify before you act.

### Use with schedules / webhooks / API / MCP

**Schedules** — run the audit weekly from the Console (Schedules tab → fixed book input). Each real run bills $0.30; keep a $0 demo run alongside as the free proof it still works.

**Webhooks** — alert-only-when-rows-leak pattern on your own endpoint: fire on run SUCCEEDED, read KV `OUTPUT`, and page only when `rowsEmitted > 0`:

```json
{ "watch": "OUTPUT.rowsEmitted", "alert": "rowsEmitted > 0", "quiet": "0 rows means clean book, no alert" }
```

**API** — start a run and poll it (runs finish in seconds; never block a `call-actor` wait longer than ~45s — poll `get-actor-run` instead):

```bash
curl -X POST "https://api.apify.com/v2/acts/steadyworks~seo-retainer-overservice-audit/runs?token=<APIFY_TOKEN>" -H "Content-Type: application/json" -d "@your-book.json"
```

```javascript
// Node.js (apify-client)
await client.actor("steadyworks/seo-retainer-overservice-audit").call({ quoteCsv, actualCsv, runId, scopeBook, checkedAt });
```

```python
## Python (apify-client)
client.actor("steadyworks/seo-retainer-overservice-audit").call({"quoteCsv": quote_csv, "actualCsv": actual_csv, "runId": run_id, "scopeBook": scope_book, "checkedAt": checked_at})
```

**MCP** — agents reach this Actor through the hosted Apify MCP server (`search-actors` → `fetch-actor-details` → `call-actor`):

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com"
    }
  }
}
```

Connect with your Apify account, search `seo-retainer-overservice-audit`, and call it with the Input JSON above. No standby server, no extra permissions — runs only.

### Troubleshooting

| symptom | cause | fix |
|---|---|---|
| 0 rows on a real book | all pairs at/inside scope — quiet audit by design (still $0.30) | read KV `OUTPUT` `report.leakingCount`; add one over-scope pair to verify the join |
| `HARD-FAIL`, zero rows | over-cap (>5 rows a side), malformed, or login-shaped input | trim to 5 + 5 rows with the required keys; never send credentials |
| $0 billed with counts only, no rows | charge limit below the $0.31 floor (`PIN_BELOW_PRICE` skip) | raise max total charge to ≥ $0.31 and re-run |
| demo input billed $0.30 | input differs ≥1 byte from the frozen demo envelope | re-paste the prefill exactly; any edit makes it a real audit |
| `person` column missing in rows | by design — dropped at ingest | nothing to fix; per-person analysis stays in your time tool |

### FAQ + legality

**Does this change my data?** No — read-only. It joins the rows you paste and writes proof rows to your own dataset; your quote and time tool are untouched.

**How much does one audit cost?** $0.30 per completed audit (rows or zero-leak quiet). The frozen demo is a $0 trial; rejections and cap-trips are $0.

**What counts as a completed audit?** Any run that joins your book — leaking rows or a quiet zero-row result. Only rejections (bad shape), over-cap trips, and floor-skips are not completed and never bill.

**Do empty results really bill?** A quiet zero-leak book is a completed audit and bills $0.30 — the value is the verified-clean answer, not the row count.

**Does it handle logins or JavaScript pages?** There is nothing to log into — it never fetches. It reads only the rows you supply.

**Personal data / GDPR?** The `person` field is dropped at ingest and never emitted. Process only books you own or have the right to process; each row carries a check notice — verify before you act on it.

**Terms?** Run audits on your own client books. Suggested repricing figures are arithmetic, not legal or pricing advice.

### Other Actors you might need

| need | where to go |
|---|---|
| repricing CSV export | Not in this Actor — one-run audit only; proof rows stay in the dataset |
| weekly history + benchmark drift | Not in this Actor — no weekly tracking in this Actor |
| books above 5 + 5 rows | Not in this Actor — over-cap books are rejected at $0 |

Nothing else is needed for the one-run audit itself — two small lists in, proof rows out.

### Changelog + support

[CHANGELOG](./CHANGELOG.md) — 0.2 TEST-RUN $0.30 cohort (2026-10-02) · 0.1 adoption baseline (2026-10-02). Issues tab on the Store listing, or the GitHub repo (`lukegor/13-agency-overservice-ledger`).

# Changelog

This Actor's version history is a separate document: https://apify.com/steadyworks/seo-retainer-overservice-audit/changelog.md

# Actor input Schema

## `actualCsv` (type: `array`):

Actual-hours rows from the owner's own time-tool export: {client, service, date, actualHrs}. Max 5 rows in this Actor. A person column, if present, is ignored and never appears in results.

## `checkedAt` (type: `string`):

ISO-8601 timestamp shown on every result row alongside its source reference.

## `quoteCsv` (type: `array`):

Owner-assembled quote rows: {client, service, quotedHrs, rate}. Max 5 rows in this Actor.

## `runId` (type: `string`):

Caller-chosen run label, echoed in the report.

## `scopeBook` (type: `string`):

Caller-chosen book label, shown on every result row.

## Actor input object example

```json
{
  "actualCsv": [
    {
      "actualHrs": 52,
      "client": "Acme",
      "date": "2026-09-01",
      "service": "SEO-retainer"
    },
    {
      "actualHrs": 20,
      "client": "Acme",
      "date": "2026-09-02",
      "service": "PPC"
    },
    {
      "actualHrs": 18,
      "client": "Beta",
      "date": "2026-09-03",
      "service": "Web-care"
    },
    {
      "actualHrs": 35,
      "client": "Gamma",
      "date": "2026-09-04",
      "service": "SEO Monthly"
    },
    {
      "actualHrs": 12,
      "client": "Delta",
      "date": "2026-09-05",
      "service": "Audit"
    }
  ],
  "checkedAt": "2026-09-28T12:00:00Z",
  "quoteCsv": [
    {
      "client": "Acme",
      "quotedHrs": 40,
      "rate": 90,
      "service": "SEO-retainer"
    },
    {
      "client": "Acme",
      "quotedHrs": 20,
      "rate": 120,
      "service": "PPC"
    },
    {
      "client": "Beta",
      "quotedHrs": 10,
      "rate": 100,
      "service": "Web-care"
    },
    {
      "client": "Gamma",
      "quotedHrs": 30,
      "rate": 80,
      "service": "SEO Monthly"
    },
    {
      "client": "Delta",
      "quotedHrs": 15,
      "rate": 150,
      "service": "Audit"
    }
  ],
  "runId": "demo-audit-001",
  "scopeBook": "demo-book-001"
}
```

# Actor output Schema

## `overserviceRows` (type: `string`):

One item per overservice client+service (default dataset). Empty on quiet audits and rejections.

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

Run summary with counts, quiet flag, and billing keys (billed, chargeUsd, chargeEvent, trial, skip). Rejection details on invalid books.

# 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 = {
    "actualCsv": [
        {
            "actualHrs": 52,
            "client": "Acme",
            "date": "2026-09-01",
            "service": "SEO-retainer"
        },
        {
            "actualHrs": 20,
            "client": "Acme",
            "date": "2026-09-02",
            "service": "PPC"
        },
        {
            "actualHrs": 18,
            "client": "Beta",
            "date": "2026-09-03",
            "service": "Web-care"
        },
        {
            "actualHrs": 35,
            "client": "Gamma",
            "date": "2026-09-04",
            "service": "SEO Monthly"
        },
        {
            "actualHrs": 12,
            "client": "Delta",
            "date": "2026-09-05",
            "service": "Audit"
        }
    ],
    "checkedAt": "2026-09-28T12:00:00Z",
    "quoteCsv": [
        {
            "client": "Acme",
            "quotedHrs": 40,
            "rate": 90,
            "service": "SEO-retainer"
        },
        {
            "client": "Acme",
            "quotedHrs": 20,
            "rate": 120,
            "service": "PPC"
        },
        {
            "client": "Beta",
            "quotedHrs": 10,
            "rate": 100,
            "service": "Web-care"
        },
        {
            "client": "Gamma",
            "quotedHrs": 30,
            "rate": 80,
            "service": "SEO Monthly"
        },
        {
            "client": "Delta",
            "quotedHrs": 15,
            "rate": 150,
            "service": "Audit"
        }
    ],
    "runId": "demo-audit-001",
    "scopeBook": "demo-book-001"
};

// Run the Actor and wait for it to finish
const run = await client.actor("steadyworks/seo-retainer-overservice-audit").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 = {
    "actualCsv": [
        {
            "actualHrs": 52,
            "client": "Acme",
            "date": "2026-09-01",
            "service": "SEO-retainer",
        },
        {
            "actualHrs": 20,
            "client": "Acme",
            "date": "2026-09-02",
            "service": "PPC",
        },
        {
            "actualHrs": 18,
            "client": "Beta",
            "date": "2026-09-03",
            "service": "Web-care",
        },
        {
            "actualHrs": 35,
            "client": "Gamma",
            "date": "2026-09-04",
            "service": "SEO Monthly",
        },
        {
            "actualHrs": 12,
            "client": "Delta",
            "date": "2026-09-05",
            "service": "Audit",
        },
    ],
    "checkedAt": "2026-09-28T12:00:00Z",
    "quoteCsv": [
        {
            "client": "Acme",
            "quotedHrs": 40,
            "rate": 90,
            "service": "SEO-retainer",
        },
        {
            "client": "Acme",
            "quotedHrs": 20,
            "rate": 120,
            "service": "PPC",
        },
        {
            "client": "Beta",
            "quotedHrs": 10,
            "rate": 100,
            "service": "Web-care",
        },
        {
            "client": "Gamma",
            "quotedHrs": 30,
            "rate": 80,
            "service": "SEO Monthly",
        },
        {
            "client": "Delta",
            "quotedHrs": 15,
            "rate": 150,
            "service": "Audit",
        },
    ],
    "runId": "demo-audit-001",
    "scopeBook": "demo-book-001",
}

# Run the Actor and wait for it to finish
run = client.actor("steadyworks/seo-retainer-overservice-audit").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 '{
  "actualCsv": [
    {
      "actualHrs": 52,
      "client": "Acme",
      "date": "2026-09-01",
      "service": "SEO-retainer"
    },
    {
      "actualHrs": 20,
      "client": "Acme",
      "date": "2026-09-02",
      "service": "PPC"
    },
    {
      "actualHrs": 18,
      "client": "Beta",
      "date": "2026-09-03",
      "service": "Web-care"
    },
    {
      "actualHrs": 35,
      "client": "Gamma",
      "date": "2026-09-04",
      "service": "SEO Monthly"
    },
    {
      "actualHrs": 12,
      "client": "Delta",
      "date": "2026-09-05",
      "service": "Audit"
    }
  ],
  "checkedAt": "2026-09-28T12:00:00Z",
  "quoteCsv": [
    {
      "client": "Acme",
      "quotedHrs": 40,
      "rate": 90,
      "service": "SEO-retainer"
    },
    {
      "client": "Acme",
      "quotedHrs": 20,
      "rate": 120,
      "service": "PPC"
    },
    {
      "client": "Beta",
      "quotedHrs": 10,
      "rate": 100,
      "service": "Web-care"
    },
    {
      "client": "Gamma",
      "quotedHrs": 30,
      "rate": 80,
      "service": "SEO Monthly"
    },
    {
      "client": "Delta",
      "quotedHrs": 15,
      "rate": 150,
      "service": "Audit"
    }
  ],
  "runId": "demo-audit-001",
  "scopeBook": "demo-book-001"
}' |
apify call steadyworks/seo-retainer-overservice-audit --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,steadyworks/seo-retainer-overservice-audit"
        }
    }
}
```

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/efLaxMafcvkflbGS5/builds/Yj0AyAzYcoD0vlpmI/openapi.json
