My Actor
Pricing
Pay per usage
My Actor
Pricing
Pay per usage
Rating
0.0
(0)
Developer
NICHOLAS SAVAGE
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
2 days ago
Last modified
Categories
Share
AgentShelf — OpenAI product feed conformance validator
Give it your product feed. It tells you, row by row, which items OpenAI's agentic-commerce ingest would reject and exactly why — before you ever upload anything.
It runs entirely offline. It does not upload your feed, it does not call an OpenAI API, and it does not need a merchant account. It reads bytes you hand it and applies the rules from the published feed specification.
What it does
| You give it | You get back |
|---|---|
| a CSV, TSV, JSON or NDJSON feed | a conformance report: accepted vs. rejected counts, an acceptance rate, duplicate item ids, unknown and missing columns |
the same, normalize: true | the above plus every accepted row projected into OpenAI native field names, exported as a CSV you can ship |
Both dialects are understood. Point it at an existing Google Merchant Center feed and it maps the Google field names onto the OpenAI ones before checking, so you can find out what an existing catalogue would cost you without rebuilding it first.
Every finding carries a rule id, the field it fired on, the offending value and the source line number, so a rejection is something you can fix rather than something you have to guess at.
Set failOn to decide which findings make the run exit non-zero. The report is
stored either way, so a "failed" run is still a readable report.
Input
Full contract in input_schema.json. Unknown fields are rejected, not
ignored — including anything that looks like a URL, because this Actor performs
no network requests of its own. Supply the feed exactly once, either inline as
feedText or as a record in this run's own key-value store named by feedKey.
| Field | Type | Default | Notes |
|---|---|---|---|
feedText | string | – | the feed itself, inline |
feedKey | string | – | a record name in this run's own key-value store holding the feed; a plain name, not a path |
format | auto | csv | tsv | json | ndjson | auto | force a parser instead of sniffing the bytes |
dialect | auto | openai | google | auto | which field-name and rule set to apply |
merchantName | string | – | your registered display name, checked against the seller_name rule; taken on trust, not a credential |
adsFeed | boolean | false | also apply the rules that only bind for Ads feeds |
checkRecommended | boolean | true | also report recommended-field gaps as warnings |
normalize | boolean | false | map to native field names and emit the accepted rows |
emitCsv | boolean | true | write the CSV exports as key-value records |
failOn | error | warning | never | error | which findings make the run exit 1 |
maxRows | integer | 50000 | refuse a larger feed rather than validate a prefix of it (ceiling 500000) |
tenantId | string | – | free-text label echoed into the result for your own attribution |
Output
One agentshelf/actor-result/1 object per run, written identically to the
default dataset and to the OUTPUT key-value record, on success and on failure
alike. The shape is described in dataset_schema.json and output_schema.json;
a real local run's output is in ./sample-output.json,
produced by
npm ci && npm run buildmkdir -p storage/key_value_stores/default# the bundled Google-dialect fixture as the `feedText` fieldnode products/agentshelf/dist/actor/main.js
so you can reproduce it apart from the timestamp and the duration.
The CSV exports are not inlined into that JSON. They are stored as their own key-value records, so you can download them as spreadsheets:
| Record | Written when |
|---|---|
rejections.csv | a report was produced and emitCsv was left on — one row per finding |
accepted-rows.csv | normalize and emitCsv were both on — the passing rows in native fields |
A very large feed can produce a per-row array too big for one dataset item. In
that case the summary, the rule tally and the digest are kept, the per-row array
is set to null, and data.truncated says how many rows were dropped. The full
per-row detail is still in rejections.csv. Nothing is silently trimmed.
Exit codes:
| Code | Meaning |
|---|---|
0 | ran, report stored, failOn policy not tripped |
1 | findings at or above the failOn threshold (the report is still stored) |
2 | input missing, invalid, oversized, or containing an unknown field |
3 | runtime or storage failure |
Pricing
Pay per event, two events, charged once per run:
| Event | Price | Charged when |
|---|---|---|
feed-normalization | $0.10 | once, after a report and the normalized native rows have been written to both the dataset and OUTPUT |
feed-report | $0.05 | once, after a report alone has been written to both the dataset and OUTPUT |
Pricing is per run, not per row: a 200-row feed and a 200,000-row feed cost the same. You can price a validation into your own pipeline without knowing the catalogue size in advance.
Nothing else is billable. In particular you are not charged for:
- a rejected, invalid or oversized input (exit
2), - a runtime failure (exit
3), - a run whose
failOngate tripped (exit1) — findings are news you asked for, and that run is a failed run, - a run whose result could not be stored,
- a start, a retry or a resurrect.
The charge is issued once per run, with an idempotency key, only after the result is durably stored, and the run's exit code never depends on whether the billing call succeeded. Your maximum cost per run is respected before any charge is sent.
Those two prices are what this repository's code, tests and ledger agree on. Whether they are what a published listing charges depends on the Apify Console configuration, which is not part of this repository.
Security
- No network egress. The run performs no outbound requests except to the
Apify platform API that stores the result and issues the charge. There is no
input field naming a URL, host or proxy, and unknown fields are rejected, so
there is no user-influenced destination and no SSRF surface.
feedKeyis validated as a plain record name, so it cannot be pointed at a path. - No credentials. No input field is a secret, because the Actor has nothing
to authenticate to.
merchantNameis a public display name you choose to supply and is echoed back deliberately. The platform token the run receives is used only for storage and charging, and never appears in the dataset, theOUTPUTrecord, a CSV export or a log line. - Your feed is not retained. It is read, validated and discarded with the run's own storage. The result carries a digest of the feed, never the feed.
- Row counts, feed size and result size are all capped, and the run executes as an unprivileged user in the container.
Boundaries
- Not an upload path. It transmits nothing to OpenAI and holds no merchant account. Passing here is not submitting.
- Not the ingest authority. A clean report reduces rejection risk. It is not a guarantee of acceptance: OpenAI is the authority on its own ingest, and the specification can change ahead of this rule set.
- Operator-side configuration cannot be checked. Your registered merchant
name, your configured market currencies and your Ads settings live in an
account this tool cannot see. What it assumed is reported in every result as
assumptionsrather than presented as verified. - Links are checked for syntax only. It does not fetch product or image URLs, so "must resolve with HTTP 200" is not something it can confirm.
- Not affiliated with or endorsed by OpenAI or Google.
Licence
Apache-2.0.