# Actor Generator - Customer Actor (`dtrungtin/customer-actor`) Actor

Submits an Actor generation request to the private generator Actor, waits for completion, and copies the generated ZIP into this run's KVS.

- **URL**: https://apify.com/dtrungtin/customer-actor.md
- **Developed by:** [Tin](https://apify.com/dtrungtin) (community)
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $49.00 / standard actor

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/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 #1 - Customer Actor

Customers run this Actor in their own Apify account. It sends their request to the private generator
Actor (Actor #2) in your account, waits for the generated Actor, and copies the resulting ZIP into the
customer's run storage.

### Required environment variables

- `TOKEN`: your private Apify token (secret). It must be able to run Actor #2, read its storage, and write to
  the `generated-actors` key-value store in your account.
- `GENERATOR_ACTOR_ID`: Actor #2 ID, for example `dtrungtin/generator-actor`.
- `INBOX_STORE_NAME` (optional): named store in your account used to hand previous ZIPs to Actor #2. Default
  `generated-actors`, the same store Local Codex archives to.

### Input

| Field | Required | Description |
| --- | --- | --- |
| `actorName` | yes | Name of the Actor to generate. Reusing the name of an earlier successful run turns the request into a revision. |
| `requirements` | yes | What the Actor should do. For a revision, only the change. |
| `language` | no | Preferred runtime hint. |
| `notes` | no | Extra information for the generator. |
| `errorLog` | no | Problem report: error message or tail of the failed run's log (secrets removed). |
| `failedRunInput` | no | Problem report: the exact input that failed, as JSON. |
| `failedRunId` | no | Problem report: run ID or Console URL of the failed run, for reference. |

### Flow

1. The customer starts this Actor with the generation requirements.
2. The Actor looks at the customer's own earlier runs of this Actor (see Revisions below).
3. It creates a separate `ApifyClient` using `process.env.TOKEN` and calls Actor #2 in your account.
4. Actor #2 stores the request and waits for Local Codex to upload `GENERATED_ACTOR_ZIP` into its default
   key-value store.
5. When Actor #2 succeeds, this Actor reads the ZIP with your token and stores it as `GENERATED_ACTOR_ZIP`
   in its own default key-value store, plus an `OUTPUT` record with the generator run ID, Actor name and the
   ZIP's record URL (`zipUrl`). The log and the final status message show that URL, for example
   `https://api.apify.com/v2/key-value-stores/<storeId>/records/GENERATED_ACTOR_ZIP`.
6. The customer downloads `GENERATED_ACTOR_ZIP` from that URL (key-value store record URLs are readable without a
   token) or from the run's Storage tab, and imports it into Apify.
7. The same result is pushed as one item into the run's default dataset (`status`, `actorName`, `requestType`,
   `zipUrl`, size, hash, version, billing tier and label, amount charged, `requestId`, timestamps, `message`), so
   it appears as a table in the Dataset tab (`.actor/dataset_schema.json`) and can be exported or read through the
   API. A run that fails writes a `FAILED` item with the error message; a run stopped by the spending-cap pre-check
   writes `NOT_STARTED`. The item never mentions how the Actor is produced.

### Revisions

Revisions are detected automatically; there is no extra input. A request whose `actorName` matches an Actor
already delivered to the same customer (compared case-insensitively, ignoring punctuation) is a revision of it.
Two lookups exist:

1. **From the customer's runs (needs full permissions).** Using the run's own token, the Actor lists the
   customer's `SUCCEEDED` runs of this Actor, picks the newest one with a matching `INPUT.actorName` and a
   delivered ZIP, downloads that ZIP, uploads it into the `generated-actors` store in **your** account as
   `inbox-<runId>.zip` (Actor #2 cannot read the customer's private storage) and passes the record URL to
   Actor #2 as `previousZipUrl` with its SHA-256 and the previous run IDs. Apify runs new Actors with
   **limited permissions**, whose token cannot list the user's runs, so this lookup fails with "Insufficient
   permissions" unless you switch the Actor to full permissions in Console (Settings > Actor permissions).
   Customers then have to approve that access explicitly. The failure is logged and is not fatal.
2. **From your delivery records (default, no customer permissions needed).** Actor #2 checks the per-customer
   delivery index that Local Codex writes on every upload (`index-<customerUserId>.json` in the
   `generated-actors` store, keyed by normalised Actor name). The customer's user ID comes from the
   `APIFY_USER_ID` environment variable of this run. A match makes Actor #2 stage the original delivery from
   your own storage, which is trusted by construction.

`OUTPUT.revision` reflects Actor #2's decision. To generate a brand-new Actor instead, use a different
`actorName`.

### Reporting a problem with a generated Actor

When an Actor the customer received fails in their account, that run's log and input live in the customer's
account and cannot be read from here (limited permissions). The customer therefore attaches the evidence in the
"Report a problem" section of the input: `errorLog`, `failedRunInput` and optionally `failedRunId`, keeping the
same `actorName` so the request becomes a revision. The Actor bundles them as `problemReport` (the log is capped at
200,000 characters, keeping the tail where errors appear), forwards it to Actor #2 and logs only metadata about it,
never its content. Local Codex saves the evidence next to the request, reproduces the failure with the reported
input, and the fix is delivered as a new version. The input description asks customers to remove secrets first.

### Pricing

Built for pay per event (`src/pricing.js` holds the rules). When monetisation is enabled in Console with the events
`actor-generated-standard`, `actor-generated-advanced` and `actor-revision`:

1. At start the run must be able to pay for `actor-generated-standard`; otherwise it exits with a status message
   asking the customer to raise the run's maximum total charge, before the generator is contacted.
2. The customer's cap and the prices are forwarded in `customerContext.billing`; Local Codex decides the tier
   automatically from the delivered code (complexity), the size of the change against the previous version and
   the 7-day warranty for problem reports (counted from the last billable delivery of that Actor, so free fixes do
   not extend it), and records it with a label in `GENERATED_ACTOR_META`.
3. After the ZIP is copied, the event for that tier is charged: `actor-revision` for updates,
   `actor-generated-standard` or `actor-generated-advanced` for new Actors and major reworks (advanced falls back to
   standard if the cap is too low); free deliveries charge nothing. The customer sees the amount and the label,
   e.g. "Charged $19.00 for this delivery (update of an existing Actor)". `OUTPUT.charge` records the result.

Without monetisation the Actor charges nothing and runs as pay per usage.

### Failure reporting

Errors go through `Actor.fail()`, so a failed run is marked `FAILED` and the reason is shown as its status
message. Calling `Actor.exit()` in a `finally` block would exit with code 0 and hide the failure.

# Actor input Schema

## `actorName` (type: `string`):

Requested name of the generated Actor. If one of your earlier successful runs of this Actor used the same name, this run is treated as a revision of that Actor: describe only the change in Requirements.

## `requirements` (type: `string`):

Describe what the generated Actor should do. For a revision (same Actor name as an earlier run), describe only the change you want, or the problem to fix.

## `language` (type: `string`):

Optional implementation preference, e.g. JavaScript, TypeScript, Python.

## `notes` (type: `string`):

Optional additional information for the generator.

## `errorLog` (type: `string`):

The error message or the last part of the failed run's log. The failed run's status message is a good start.

## `failedRunInput` (type: `object`):

The exact input you used when the Actor failed, so the problem can be reproduced. Copy it from the failed run's Input tab (JSON view).

## `failedRunId` (type: `string`):

Optional reference to the failed run in your account (run ID or Console URL).

## Actor input object example

```json
{
  "language": "JavaScript"
}
```

# Actor output Schema

## `generatedActorZip` (type: `string`):

No description

## `output` (type: `string`):

No description

## `result` (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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("dtrungtin/customer-actor").call(input);

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

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

```

## Python example

```python
from apify_client import ApifyClient

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

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("dtrungtin/customer-actor").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 '{}' |
apify call dtrungtin/customer-actor --silent --output-dataset

```

## MCP server setup

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

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/z6i440k0JmCwFhUT3/builds/8I1M8qsdyykThEWx0/openapi.json
