Zid Product Export Intelligence
Pricing
from $2.55 / 1,000 authorized zid product intelligence rows
Zid Product Export Intelligence
Turn merchant-owned, merchant-authorized, or otherwise licensed Zid product exports into stable evidence, freshness, source-rights context, gaps, review priority, and human actions—without storefront scraping, login, API calls, URL fetching, or automatic merchandising decisions.
Pricing
from $2.55 / 1,000 authorized zid product intelligence rows
Rating
0.0
(0)
Developer
Tim Zinin
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
1
Monthly active users
8 days ago
Last modified
Categories
Share
Zid Product Export Intelligence — authorized catalog evidence for human review
Turn a merchant-owned, merchant-authorized, or otherwise licensed Zid product export into stable, evidence-backed catalog review rows. The Actor validates a closed product contract, removes duplicate merchant identities, preserves legacy product fields, adds decision and provenance context, delivers one row per accepted product, and reconciles every paid/free/unknown outcome in the current run's KVS OUTPUT record.
It does not scrape a Zid storefront, sign in to a merchant account, call a Zid endpoint, fetch a supplied URL, verify the buyer's licence, or make an automatic merchandising decision. Legacy shop-name input remains compatible only as a free migration diagnostic and never triggers a storefront request.

What you get
Each accepted product becomes one authorized Zid product intelligence row in the default Dataset. The row keeps the familiar product fields and adds explicit source, evidence, confidence, gaps, human-review action, failure, stable identity, and settlement-neutral billing metadata.
- One stable identity for each unique
sourceName + shop + productIdcombination. - Buyer-supplied product name, price, currency, optional sale price, category, and recorded HTTPS links.
- A source label and rights statement carried with the product instead of hidden in run configuration.
- A SHA-256 digest for the normalized input record and the exact request.
- Freshness based only on the optional buyer-supplied
sourceRetrievedAttimestamp. - Evidence-completeness confidence with explicit gaps; never a claim that the product or merchant was independently verified.
- A fixed human-review action, review priority, summary, and
safeToAutomate:falseboundary. - Settlement-neutral Dataset billing intent plus authoritative paid/free/unknown reconciliation in KVS
OUTPUT. - Free advisory rows for legacy input and malformed supplied records, with no intentional
result-foundcharge. - Current-run counts for requested, unique, duplicate, invalid, attempted, successful, failed, delivered, paid, free, withheld, unknown-delivery, and unknown-settlement work.
The Actor does not tell you whether a product should be listed, repriced, promoted, purchased, removed, or approved. It does not prove stock, tax treatment, shipping coverage, variant availability, merchant ownership, marketplace eligibility, licence validity, conversion, demand, margin, or product quality.
Who uses it
This Actor is designed for merchants, merchant-authorized agencies, catalog operations teams, ecommerce implementation partners, data migration teams, feed QA teams, and portfolio operators who already possess product records they are allowed to process.
Good uses include:
- validating a merchant export before a catalog migration;
- producing a human QA queue from an authorized Zid export;
- deduplicating merchant product identities across export fragments;
- adding source and rights context before records enter a warehouse;
- preserving a reviewable evidence trail for a catalog integration;
- routing incomplete records to an operations ticket;
- reconciling delivered rows and named billing events for one Apify run;
- generating an audit-friendly snapshot without opening any product URL.
Do not use it to crawl third-party shops, copy a competitor's catalog, bypass Zid authorization, infer confidential merchant information, obtain seller contact details, scrape images, validate brand ownership, republish user content without permission, or make autonomous pricing and inventory decisions.
The buyer is responsible for determining whether the submitted export may be processed and delivered. The authorization sentence is an attestation recorded by the run, not a legal opinion or independent permission check.
How to run
- Export product records from a merchant-controlled or merchant-authorized source.
- Remove secrets, customer data, personal data, signed URLs, internal notes, and fields outside the public input contract.
- Give every product a stable
productId, ashoplabel, a nonblankname, a nonnegativeprice, a three-letter currency,sourceName, andsourceLicensestatement. - Add optional HTTPS product/image links only if you are allowed to store them. The Actor records but never opens them.
- Set
sourceRetrievedAtwhen you have a trustworthy UTC extraction timestamp; omit it when you do not. - Submit the exact authorization sentence shown in the Input UI.
- Start with one or two records and a maximum total charge that covers the automatic start event plus the intended product rows.
- Wait for the exact run to finish. Read default KVS key
OUTPUTand require itsrunIdto match the platform run. - Reconcile Dataset length, paid/free/unknown counters, the named
result-foundcounter, and terminal state before downstream use. - Send every product row to a human reviewer.
safeToAutomateis always false.
Minimal accepted input:
{"schemaVersion": "2.0","authorization": "I confirm I am authorized to process and deliver these product records","sourceContext": "zid_merchant_export","products": [{"productId": "merchant-sku-1001","shop": "demo-merchant","name": "Arabic coffee gift set","price": 149,"currency": "SAR","salePrice": 129,"productUrl": "https://merchant.example/products/merchant-sku-1001","imageUrl": null,"category": "Gifts","sourceName": "Merchant-owned Zid export","sourceLicense": "Merchant confirms ownership and downstream processing rights for this export.","sourceRetrievedAt": "2026-08-13T00:00:00Z"}]}
The checked-in examples/input.json contains the same closed fixture. It uses merchant.example, a reserved documentation domain, so the example does not imply a real customer, product, licence, store, or commercial result.

Pricing
The primary pricing noun is one authorized Zid product intelligence row. The Actor uses pay per event. A run can incur the automatic apify-actor-start event. Each confirmed linked delivery of one unique accepted product can incur one result-found event.
| Tier | Actor start | One authorized Zid product intelligence row |
|---|---|---|
| FREE | $0.00500 | $0.00300 |
| BRONZE | $0.00475 | $0.00285 |
| SILVER | $0.00450 | $0.00270 |
| GOLD | $0.00425 | $0.00255 |
| PLATINUM | $0.00410 | $0.00246 |
| DIAMOND | $0.00400 | $0.00240 |
At FREE-tier event prices, one accepted product plus the automatic start event is $0.008 before compute and storage. Ten accepted products plus start are $0.035. At DIAMOND event prices, one accepted product plus start is $0.0064 and ten accepted products plus start are $0.028. The live Apify pricing panel is authoritative for the buyer's current tier and any future approved pricing change.
Legacy diagnostics, malformed-record diagnostics, duplicates, and withheld records do not intentionally emit result-found. A returned linked push can still represent a free delivery if the platform charge cap prevents the event; OUTPUT records that as free and stops. A thrown push is unknown Dataset delivery. A returned push followed by an unreadable or contradictory named counter is known Dataset delivery with unknown settlement. Neither uncertain state is automatically retried.
Before the first paid delivery, the runtime requires:
- a current hosted Apify run ID;
- exact pay-per-event mode;
- exactly two numeric pricing events:
apify-actor-startandresult-found; - one of the six approved price pairs above;
- a readable run cap and current spend;
- current spend that already includes the exact start price;
- an initial named
result-foundcounter of zero; - enough remaining cap for the next product row.
For every paid row, it reads the named counter before the push, requires it to equal the number of already confirmed product charges, performs one linked Dataset push, reads the counter again, and requires an exact +1 delta plus a bounded aggregate receipt. It never treats a nonzero aggregate count alone as proof of the named product unit.
Input contract
The public input contract is closed. Unknown top-level fields and unknown product fields are rejected. The runtime never string-coerces arbitrary objects.
| Field | Required | Boundary |
|---|---|---|
schemaVersion | No | When present, exactly 2.0. |
authorization | With products | Exact sentence: I confirm I am authorized to process and deliver these product records. |
sourceContext | No | zid_merchant_export, merchant_owned_export, merchant_authorized_integration, or other_licensed_catalog_export; default zid_merchant_export. |
products | Modern path | 1–100 closed product objects. Cannot be combined with legacy items. |
items | Legacy path | 1–20 nonblank shop-name strings. Migration diagnostic only; no fetch and no paid product. |
maxConcurrency | Legacy only | 1–20, ignored because version 0.2 performs no network requests. |
Product object fields:
| Field | Required | Boundary |
|---|---|---|
productId | Yes | 1–180 characters; stable merchant/source product identity. |
shop | Yes | 1–240 characters; merchant/shop label, not independently verified. |
name | Yes | 1–300 characters. |
price | Yes | Finite number from 0 through 1,000,000,000. |
currency | Yes | Three ASCII letters, normalized to uppercase. No exchange-rate conversion. |
salePrice | No | Null or a finite nonnegative number not greater than price. |
productUrl | No | Null or HTTPS URL up to 800 characters, with no embedded credentials. Recorded only; never fetched. |
imageUrl | No | Null or HTTPS URL up to 800 characters, with no embedded credentials. Recorded only; never fetched. |
category | No | Null or 1–240 characters. |
sourceName | Yes | 1–200 characters identifying the authorized export or integration. |
sourceLicense | Yes | 1–500 characters stating the buyer's processing/redistribution basis. Recorded, not verified. |
sourceRetrievedAt | No | Null or real UTC ISO timestamp. Used only for evidence freshness. |
The runtime trims text, normalizes currency, validates real UTC dates, rejects credential-bearing or non-HTTPS links, and removes duplicate product identities using case-insensitive sourceName + shop + productId. The first valid occurrence wins. Conflicting duplicate content is not merged and is not billed twice.
The public Input schema normally rejects malformed objects before a hosted run starts. If a Task, legacy caller, or other runtime path bypasses platform prevalidation, the defensive runtime counts malformed objects as invalid and can create one free run diagnostic while valid objects from the same input continue. An input containing only runtime-received malformed objects creates a free diagnostic and a partial result; it never manufactures product fields. Missing or incorrect authorization on any valid product fails before a Dataset push.
Do not submit API keys, OAuth tokens, cookies, signed URLs, private object-store links, passwords, personal contact data, customer orders, customer addresses, payment details, unpublished pricing, internal notes, employee information, or confidential supplier terms. Apify persists Actor input in run storage; a secret UI field would hide display, not eliminate storage. This Actor intentionally has no secret input.
Happy, partial, and failure output
The following wrappers are deterministic local contract fixtures. They are clearly not production/canary evidence: their buildId identifies a local fixture, and the campaign's final evidence receipt replaces this role with the real immutable build/run/Dataset/KVS identifiers before PUBLIC_ACCEPTED.
Accepted local fixture:
{"runId": "local-test-zid-product-run","buildId": "local-contract-fixture-v2","status": "SUCCEEDED","evidenceAccepted": true,"dataset": {"recordType": "product_intelligence","stableId": "sha256:82ce23aa91cf44d9b07cc16ca2e1af2dbb6e2ddb00278dafc0812f2378dc840d","productId": "merchant-sku-1001","found": true,"safeToAutomate": false,"recommendedAction": "REVIEW_PRODUCT_RECORD","billing": {"billingEligible": true,"billingIntent": "linked_push_result_found","eventName": "result-found","settlementSource": "current_run_kvs_output"}},"output": {"status": "COMPLETE","runId": "local-test-zid-product-run","input": {"requestedCount": 1, "uniqueCount": 1, "duplicateCount": 0, "invalidCount": 0, "legacyInputCount": 0},"run": {"attemptedCount": 1, "successfulCount": 1, "failedCount": 0, "deliveredRowCount": 1, "paidRowCount": 1, "freeRowCount": 0, "withheldRowCount": 0, "unknownDeliveryCount": 0, "unknownSettlementCount": 0, "partial": false, "budgetStopped": false, "fatalError": null, "replaySafe": false, "safeToAutomate": false},"delivery": {"eventName": "result-found", "attemptedPushCount": 1, "resultChargeCountBefore": 0, "resultChargeCountAfter": 1, "confirmedEventDelta": 1, "confirmedDatasetWrites": 1, "lastAttempt": {"state": "confirmed_paid", "resultChargeCountBefore": 0, "resultChargeCountAfter": 1, "delta": 1, "aggregateChargedCount": 2, "eventChargeLimitReached": false}},"terminal": {"outcome": "COMPLETE", "failureStage": null, "primaryKvsWrite": "confirmed", "recoveryKvsWrite": "not_attempted", "exit": "requested"}}}
Legacy migration fixture:
{"runId": "local-test-zid-legacy-run","buildId": "local-contract-fixture-v2","status": "SUCCEEDED","evidenceAccepted": true,"dataset": {"recordType": "run_advisory","failureType": "legacy_store_input","found": false,"safeToAutomate": false,"billing": {"billingEligible": false, "billingIntent": "free_diagnostic_dataset_write", "eventName": null, "settlementSource": "current_run_kvs_output"}},"output": {"status": "PARTIAL","runId": "local-test-zid-legacy-run","input": {"requestedCount": 0, "uniqueCount": 0, "duplicateCount": 0, "invalidCount": 0, "legacyInputCount": 1},"run": {"attemptedCount": 0, "successfulCount": 0, "failedCount": 0, "deliveredRowCount": 1, "paidRowCount": 0, "freeRowCount": 1, "withheldRowCount": 0, "unknownDeliveryCount": 0, "unknownSettlementCount": 0, "partial": true, "budgetStopped": false, "fatalError": null, "replaySafe": false, "safeToAutomate": false},"delivery": {"eventName": "result-found", "attemptedPushCount": 1, "resultChargeCountBefore": 0, "resultChargeCountAfter": 0, "confirmedEventDelta": 0, "confirmedDatasetWrites": 1, "lastAttempt": {"state": "confirmed_free_diagnostic", "resultChargeCountBefore": null, "resultChargeCountAfter": null, "delta": null, "aggregateChargedCount": null, "eventChargeLimitReached": null}},"terminal": {"outcome": "PARTIAL", "failureStage": null, "primaryKvsWrite": "confirmed", "recoveryKvsWrite": "not_attempted", "exit": "requested"}}}
Output states:
| State | Meaning | Retry boundary |
|---|---|---|
COMPLETE | Every unique accepted product was confirmed delivered and paid. | A new run can create a new start and product charge; do not use as idempotent replay. |
PARTIAL | Diagnostic, invalid, duplicate-adjacent, budget, free-delivery, or other bounded incompleteness occurred without a fatal terminal error. | Read OUTPUT and decide intentionally. |
FAILED before any push | Input, identity, pricing, pre-push counter, or KVS/exit failure prevented safe completion. | Correct the named failure; a later intentional run may be safe, but the start event is separate. |
unknown_delivery | The linked push threw; Dataset delivery and settlement are unknown. | Never blind-retry. Reconcile the original run. |
settlement_unknown | The push returned, so Dataset delivery is known, but named settlement could not be proved. | Never blind-retry. Reconcile Dataset and platform counters. |
settlement_anomaly | Named/aggregate settlement facts contradicted the allowed paid/free lattice. | Stop and investigate; no automatic retry. |
confirmed_free | Dataset write returned and named counter did not advance under a zero-charge receipt. | The row is delivered free; remaining products are withheld to prevent cap ambiguity. |
Field dictionary
Legacy-compatible fields:
| Field | Meaning and boundary |
|---|---|
input | Merchant/shop label supplied by the buyer; null on a general diagnostic. |
found | True for a validated product candidate, false for a free advisory. It is not external verification. |
productId | Buyer/source product identity, stable only within the declared source and shop. |
name | Buyer-supplied product name after trimming. |
price | Buyer-supplied base price; no tax, shipping, variant, locale, or exchange-rate verification. |
currency | Uppercase three-letter input code; syntax is validated, economic meaning is not. |
salePrice | Optional supplied sale price, required not to exceed base price. No promotion validation. |
url | Recorded HTTPS product URL or null. It is never fetched or asserted canonical. |
image | Recorded HTTPS image URL or null. It is never fetched, rendered, licensed, or scanned. |
category | Optional buyer-supplied category label. No taxonomy mapping. |
catalogComplete | Preserved legacy field, always null because a supplied batch cannot prove full catalog coverage. |
catalogTruncatedReason | Preserved legacy field, always null; request counts and data gaps carry current truth. |
scrapedAt | Preserved legacy timestamp name containing current processing time. No scraping occurs in version 0.2. |
Decision and evidence fields:
| Field | Meaning and boundary |
|---|---|
schemaVersion | Legacy row schema marker 1.0.0. |
contractVersion | Additive intelligence contract 2.0.0. |
recordType | product_intelligence or run_advisory. |
intelligenceType | authorized_zid_catalog_intelligence or product_processing_diagnostic. |
stableId | SHA-256 of sourceName, shop, and productId. Integrity/join aid, not anonymization or legal identity. |
entityId | Namespaced stable product identity derived from stableId. |
observedAt | Time the Actor processed the supplied record. |
firstSeenAt / lastSeenAt | Both equal the current observation in a stateless single snapshot. They do not imply persisted history. |
freshness.status | fresh, recent, older, or unknown from supplied sourceRetrievedAt. |
freshness.ageSeconds | Nonnegative age from supplied retrieval time to run observation, or null. |
freshness.basis | Explicitly names buyer-supplied timestamp or missing/future timestamp boundary. |
change.status | Always not_measured; this Actor does not compare earlier snapshots. |
confidence.level | HIGH, MEDIUM, or LOW evidence completeness, not correctness, demand, quality, or legal confidence. |
confidence.basis | Closed shape, stable identity, and buyer authorization attestation. |
confidence.gaps | Material facts not demonstrated by this row. |
evidence | Digests of the normalized supplied record and rights statement. No source body or secret is copied. |
confidenceScore / confidenceBand | Queryable completeness projection. Not a probability or accuracy measure. |
dataGaps | Missing URL/image/category/time plus fixed non-verification gaps. |
recommendedAction | REVIEW_PRODUCT_RECORD for products or REVIEW_RUN for diagnostics. |
priority | Review routing from supplied freshness; not business value. |
safeToAutomate | Always false. |
summary | Short evidence-bound review sentence. |
failureDiagnostics | Null for products; typed details for advisories. |
failureType / retryable | Explicit diagnostic type and conservative retry flag. |
billing | Eligibility and intent only; KVS OUTPUT decides paid/free/unknown settlement. |
sourceName | Buyer-declared authorized export/integration label. |
sourceLicense | Buyer-declared rights basis. Recorded and hashed, never independently validated. |
sourceRetrievedAt | Optional buyer-declared source extraction time. |
requestDigest / inputDigest | SHA-256 integrity digests of canonical request and normalized product. |
KVS OUTPUT fields:
| Field | Meaning and invariant |
|---|---|
schemaVersion / kind | Exact receipt contract and product identity. |
status | RUNNING during construction, then COMPLETE, PARTIAL, or FAILED. |
runId | Current hosted platform run identity. Hosted execution fails before delivery if unavailable. |
requestDigest | Canonical authorized request digest, or null for a pre-input failure. |
input.requestedCount | Modern product objects submitted, excluding legacy strings. |
input.uniqueCount | Valid deduplicated modern products. |
input.duplicateCount | Valid duplicates removed before delivery. |
input.invalidCount | Malformed modern product objects. |
input.legacyInputCount | Nonblank legacy shop-name strings accepted only for migration diagnostics. |
run.attemptedCount | Unique product work units whose paid delivery phase began. Diagnostics are counted in delivery, not product work. |
run.successfulCount / failedCount | Exact partition of attempted product work. |
run.deliveredRowCount | Dataset pushes known to have returned, including paid, free, and unknown-settlement rows. |
run.paidRowCount | Named result events confirmed by exact counter delta. |
run.freeRowCount | Free diagnostic or result-uncharged rows known delivered. |
run.withheldRowCount | Unique products intentionally not pushed. |
run.unknownDeliveryCount | Push attempts whose Dataset outcome is unknown. Maximum one because the run stops. |
run.unknownSettlementCount | Known Dataset delivery with unproved or anomalous settlement. Maximum one because the run stops. |
run.partial | True for any failed/withheld/unknown/budget/fatal work or diagnostic path. |
run.budgetStopped | True when the next result cannot fit or the platform returns a confirmed free product under the cap. |
run.fatalError | Closed current terminal failure code or null. |
run.replaySafe | True only before any Dataset push attempt. |
run.safeToAutomate | Always false. |
delivery.attemptedPushCount | All Dataset attempts, paid or diagnostic. |
delivery.resultChargeCountBefore / After | Named result counter boundaries. |
delivery.confirmedEventDelta | Exact sum of confirmed named +1 product deltas; equals paidRowCount. |
delivery.confirmedDatasetWrites | Dataset writes known to have returned; equals deliveredRowCount. |
delivery.lastAttempt | Stable row ID, settlement state, named counters, delta, and bounded aggregate receipt facts. |
errors | Empty without fatal error; exactly one code/message matching fatalError otherwise. |
resultsUrl | Current default Dataset API link when the platform supplies its ID. |
startedAt / completedAt | UTC current-run processing boundaries. |
terminal | Outcome, failure stage, primary/recovery KVS write state, and exit state. |
Evidence and boundaries
Version 0.2 has no external source client. It performs no fetch, browser navigation, DNS lookup, redirect, proxy request, Zid API call, storefront request, image download, product-page request, or link validation beyond local URL syntax. Therefore source availability, robots rules, remote authentication, source rate limits, and merchant endpoint behavior cannot silently change the current run.
The Actor's evidence is deliberately narrower:
- The input matched the closed local product contract.
- The buyer supplied the exact authorization sentence.
- The product has a stable normalized identity within the declared source and shop.
- The normalized record and rights statement have deterministic SHA-256 digests.
- Optional freshness comes from the buyer-supplied source timestamp.
- The current-run receipt explains which rows were attempted, delivered, paid, free, withheld, or uncertain.
None of those points proves that the source record is factually correct, current, complete, authorized by Zid, authorized by a merchant, free of third-party intellectual property, compatible with a destination marketplace, or suitable for automatic action. sourceLicense is a buyer attestation. authorization is a buyer attestation. SHA-256 demonstrates integrity of canonical text, not truth, consent, ownership, or anonymity.
The Actor intentionally preserves no historical state across runs. change.status is always not_measured. Running the same product later can create another Dataset row and result charge. If change detection is required, store accepted snapshots in an authorized system and compare stable IDs and normalized fields under a separate reviewed contract.
The Actor does not calculate inventory, variants, tax, shipping, discounts, product availability, feed completeness, catalog totals, merchant status, exchange rates, conversion, revenue, margin, attribution, or regulatory eligibility. It never interprets product text as halal, health, safety, legal, customs, trademark, or consumer-protection compliance.
Decision routing
| Evidence state | Human route | Do not infer |
|---|---|---|
| Product row, fresh timestamp, few gaps | Review source statement, links, prices, and destination requirements. | Not automatic approval or current stock. |
| Product row, missing source timestamp | Ask the export owner when and how it was obtained. | Not fresh merely because the Actor ran now. |
| Missing product/image/category link | Decide whether the destination workflow requires that field. | Not a failed product by default. |
| Older supplied timestamp | Request a new authorized export before operational use. | Not proof the product is discontinued. |
| Duplicate removed | Inspect the winning first record and conflicting source fragments. | Not proof the duplicate content was identical. |
| Invalid-record advisory | Correct fields against the closed input contract. | Do not invent missing product facts. |
| Legacy-input advisory | Migrate from shop strings to authorized product objects. | Never interpret it as a storefront no-match. |
| Budget stop | Increase the intentional cap or reduce the batch after reading OUTPUT. | Do not assume withheld products were invalid. |
| Confirmed free product delivery | Treat the row as delivered but uncharged, inspect the run cap, and resubmit only withheld records intentionally. | Do not repay or redeliver the already written row blindly. |
| Unknown delivery | Reconcile original Dataset and run counters manually. | Never blind-retry. |
| Unknown/anomalous settlement | Treat Dataset delivery as known when the push returned, but payment as unresolved. | Never classify paid or free without platform evidence. |
| Fatal pre-delivery error | Correct the explicit error and start a new intentional run. | Do not assume the automatic start event was reversed. |
Every route ends with a human decision. Downstream automation may create tickets, copy evidence to a warehouse, or notify an owner. It must not automatically publish, reject, reprice, purchase, advertise, or remove a product.
Commercial playbooks
1. Authorized export QA
Submit a small merchant-authorized export. Route data gaps to the merchant or implementation owner. Accept a product only after a human checks the rights statement, identity, required destination fields, and source age.
2. Migration readiness
Run the export before moving products between systems. Use duplicate/invalid counts to size cleanup. Treat catalogComplete:null as an explicit warning: a supplied batch cannot prove it contains every source product.
3. Agency handoff
Require the merchant to provide the export and rights statement. Store accepted OUTPUT beside the project ticket. Do not let an agency employee replace merchant authorization with a guessed storefront slug.
4. Feed normalization
Normalize price/currency/identity into stable rows, then map to the destination feed in a separate reviewed step. This Actor does not validate destination-specific required fields or publish a feed.
5. Duplicate investigation
Group upstream records by sourceName + shop + productId. The Actor keeps the first valid occurrence. If duplicates disagree, review and correct the export; do not assume first means authoritative.
6. Source-age queue
Use freshness only when sourceRetrievedAt came from a trustworthy export process. Route older or unknown records for refresh. The Actor's observedAt is processing time, not source update time.
7. Rights review queue
Filter by sourceName and store the exact sourceLicense digest with the project. Counsel or the merchant may still require the underlying agreement. The Actor does not decide whether the statement is legally sufficient.
8. Catalog warehouse ingestion
Write Dataset product rows to a product snapshot table and OUTPUT to a run-fact table. Join with runId, requestDigest, stableId, observedAt, and the source labels. Do not use inputDigest as anonymization.
9. Human merchandising review
Show name, price, salePrice, category, recorded links, freshness, gaps, and source statement in a review UI. Keep automatic actions disabled. Record the reviewer and decision outside this Actor.
10. Budget-controlled batch
Estimate maximum result units, set an intentional cap, and read withheldRowCount. A cap is a delivery boundary, not a paging mechanism. Resubmit only known withheld products after reconciling already delivered rows.
11. Legacy migration
Existing callers using items:[shop] receive a free diagnostic instead of silent external retrieval. Use that row to identify and migrate callers. It is not a product no-match and must not satisfy an old scraping workflow.
12. Failure investigation
Start with platform status, then KVS OUTPUT, Dataset length, named event count, and logs for the exact run. Unknown delivery/settlement requires manual reconciliation. A new run is a new commercial operation.
For every playbook, define the data owner, merchant authorization, intended destination, reviewer, required fields, allowed retention, deletion date, charge cap, and failure escalation before processing a large batch.
Integration recipes
Apify API
Start one bounded run with a JSON body and explicit maximum total charge. Use the actual Actor/task URL and authentication mechanism configured by your organization; do not put an Apify token inside Actor input.
curl -X POST \'https://api.apify.com/v2/acts/zinin~zid-store-products/runs?token=$APIFY_TOKEN&maxTotalChargeUsd=0.02' \-H 'content-type: application/json' \--data-binary @examples/input.json
After terminal status, read both stores for the exact run:
curl 'https://api.apify.com/v2/key-value-stores/<KVS_ID>/records/OUTPUT?token=$APIFY_TOKEN'curl 'https://api.apify.com/v2/datasets/<DATASET_ID>/items?clean=true&token=$APIFY_TOKEN'
Keep tokens in your secret manager or request environment. The shell examples use placeholders; never commit or paste live tokens into run input, Dataset rows, documentation, evidence, or logs.
JavaScript client
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const input = JSON.parse(await fs.promises.readFile('examples/input.json', 'utf8'));const run = await client.actor('zinin/zid-store-products').call(input, {maxTotalChargeUsd: 0.02,});const output = await client.keyValueStore(run.defaultKeyValueStoreId).getRecord('OUTPUT');if (output?.value?.runId !== run.id) throw new Error('current_run_receipt_mismatch');const { items } = await client.dataset(run.defaultDatasetId).listItems({ clean: true });if (items.length !== output.value.run.deliveredRowCount) {throw new Error('dataset_output_count_mismatch');}
Production code should additionally compare platform chargedEventCounts['result-found'], the receipt's named counter boundaries, paidRowCount, and the exact candidate build ID. Never retry an uncertain push automatically.
Python client
import osfrom apify_client import ApifyClientclient = ApifyClient(os.environ['APIFY_TOKEN'])input_data = {'schemaVersion': '2.0','authorization': 'I confirm I am authorized to process and deliver these product records','sourceContext': 'merchant_owned_export','products': [{'productId': 'merchant-sku-1001','shop': 'demo-merchant','name': 'Arabic coffee gift set','price': 149,'currency': 'SAR','salePrice': 129,'productUrl': 'https://merchant.example/products/merchant-sku-1001','imageUrl': None,'category': 'Gifts','sourceName': 'Merchant-owned Zid export','sourceLicense': 'Merchant confirms ownership and downstream processing rights for this export.','sourceRetrievedAt': '2026-08-13T00:00:00Z',}],}run = client.actor('zinin/zid-store-products').call(run_input=input_data,max_total_charge_usd=0.02,)receipt = client.key_value_store(run['defaultKeyValueStoreId']).get_record('OUTPUT')['value']assert receipt['runId'] == run['id']
Warehouse model
Store two related tables:
zid_product_snapshotrun_id, request_digest, stable_id, entity_id, observed_at,source_name, source_license_digest, product_id, shop, name,price, currency, sale_price, category, product_url, image_url,freshness_status, confidence_band, data_gaps, recommended_actionzid_product_runrun_id, build_id, status, requested_count, unique_count,duplicate_count, invalid_count, delivered_count, paid_count,free_count, withheld_count, unknown_delivery_count,unknown_settlement_count, result_counter_before,result_counter_after, confirmed_event_delta, replay_safe,failure_stage, completed_at
Keep the actual rights agreement or merchant instruction in an access-controlled system; do not overload sourceLicense with confidential contract text.
Ticket routing
Create a human review ticket only after current-run reconciliation. Include stableId, sourceName, freshness, gaps, recommendedAction, Dataset link, KVS link, and run ID. Exclude tokens, raw KVS input, private agreements, customer data, and image bytes.
MCP and automation boundary
The Actor is a regular bounded batch Actor, not a persistent MCP server and not a CRM/catalog write connector. An orchestration agent may start it and read results, but it must preserve safeToAutomate:false and require a human approval before any business-system mutation.
Operating guide
Before the first run
- Confirm the export owner and merchant authorization.
- Confirm downstream processing and redistribution rights for the exact fields.
- Remove secrets and personal data.
- Verify that sourceName/sourceLicense are useful but contain no confidential agreement text.
- Decide the retention and deletion date.
- Start with one record and a small explicit charge cap.
- Record who will review the product row.
Before a larger batch
- Inspect the one-record Dataset view and KVS OUTPUT.
- Verify the run ID, build ID, Dataset/KVS IDs, named event delta, and platform counters.
- Confirm the first record's stable identity and digests.
- Check invalid and duplicate behavior with synthetic fixtures.
- Estimate maximum start/result cost using the live tier.
- Decide how to handle withheld and uncertain records.
After every run
- Check platform terminal status.
- Read the current run's
OUTPUT. - Confirm OUTPUT.runId equals the platform run ID.
- Confirm Dataset length equals deliveredRowCount for the exact run.
- Confirm paid + free + unknown settlement equals delivered rows.
- Confirm attempted pushes equal delivered rows + unknown delivery.
- Confirm named event delta equals paidRowCount.
- Inspect errors, partial, budgetStopped, fatalError, and replaySafe.
- Route product rows to a human reviewer.
- Apply the retention/deletion policy.
Monitoring
Monitor terminal failures, unknown delivery, unknown settlement, free product delivery, budget stops, invalid-record rate, duplicate rate, source age, missing URLs/images/categories, and review queue latency. Do not monitor or store customer data because it should not be present.
Logging
Runtime logs contain bounded operational counts and error messages. They must not contain tokens, source bodies, signed URLs, personal data, confidential source terms, or full product batches. Evidence receipts should retain IDs, hashes, counters, and projections rather than full API responses.
Capacity
The public input accepts at most 100 product objects. Processing is deliberately sequential so budget and named-event settlement remain exact. maxConcurrency is legacy-only and ignored. If you need a larger catalog, divide it into intentional authorized batches and reconcile each run before starting the next.
Replay and retry
replaySafe:true means no Dataset push was attempted in this run. It does not mean repeating the run is free: a new run can incur a new automatic start event. Once any Dataset push is attempted, replaySafe is false. Unknown delivery or settlement is never blindly retried. Reconcile the original run first and resubmit only records proven not delivered.
Regional notes / ملاحظات إقليمية
This product is positioned for teams working with Saudi and regional ecommerce catalogs, but it does not infer jurisdiction, language, tax, customs, consumer-law, halal, trademark, or marketplace compliance.
English: The Actor records the supplied merchant/shop label, currency, product text, and rights statement. It does not translate Arabic, normalize Arabic names, resolve Hijri dates, convert currencies, validate VAT, inspect Saudi business registration, or confirm Zid merchant status. Keep Arabic product text in UTF-8 and review it with a qualified human who understands the destination market.
العربية: يعالج هذا الممثل سجلات منتجات يقدّمها التاجر أو طرف مخوّل منه. لا يقوم بتسجيل الدخول إلى منصة زد، ولا يجمع بيانات المتاجر آلياً، ولا يتحقق من ملكية المنتج أو الترخيص أو الضريبة أو المخزون أو الشحن. يجب مراجعة كل سجل بشرياً، والتأكد من صلاحية استخدام البيانات والروابط والصور قبل النشر أو النقل إلى نظام آخر. لا تضع مفاتيح API أو بيانات عملاء أو روابط موقعة داخل المدخلات.
SAR is accepted as a syntactically valid three-letter code, but no exchange-rate or VAT logic is applied. Arabic and English names remain buyer-supplied text. A human reviewer remains responsible for meaning, spelling, compliance, and destination suitability.
FAQ
Does this Actor scrape Zid stores?
No. Version 0.2 performs zero storefront, API, product-page, image, browser, DNS, redirect, or proxy requests. It processes product objects supplied by the buyer.
Why is the product still named Zid Product Export Intelligence?
It is designed around authorized Zid merchant exports and preserves the prior Zid product fields. The name does not imply Zid sponsorship, official integration, API access, or permission.
Is this an official Zid app?
No claim of official app status, partnership, certification, or endorsement is made. Use an official merchant-authorized integration to obtain the export, then submit only data you are allowed to process.
Can I enter a shop slug like before?
Yes, only for compatibility. Legacy items:[shop] creates one free legacy_store_input advisory and performs no retrieval. Migrate the caller to products plus authorization.
Does the Actor verify the sourceLicense statement?
No. It records and hashes the statement. The buyer must retain the underlying permission or licence and decide whether it covers the intended processing and delivery.
Are product URLs or image URLs checked?
Only local syntax is checked: HTTPS, bounded length, and no embedded credentials. The Actor never opens the URL, follows redirects, downloads content, checks ownership, or confirms availability.
Does found=true mean the product exists online?
No. It means the supplied object passed the closed local contract and became a result candidate. It is not an external existence check.
Does confidenceScore mean accuracy?
No. It is a deterministic evidence-completeness score. It is not probability, accuracy, merchant trust, product quality, conversion, demand, or legal confidence.
Why is safeToAutomate always false?
The Actor has no independent source verification, destination schema, business policy, rights validation, or historical comparison. Human review is required before a business action.
How are duplicates handled?
Valid records are deduplicated case-insensitively by sourceName + shop + productId. The first occurrence is retained. Conflicting duplicates are not merged.
Is zero price accepted?
Yes, because some authorized exports can legitimately encode a zero price. A human must decide whether it represents a free item, placeholder, quote-only product, or source error.
Is salePrice required?
No. When provided it must be nonnegative and not greater than price. The Actor does not verify promotion dates or destination pricing rules.
Does the Actor prove full catalog coverage?
No. catalogComplete remains null. The Actor sees only the supplied batch and cannot prove source totals or missing products.
Does it detect changes between runs?
No. change.status is not_measured. Store accepted snapshots in your own authorized system if you need reviewed change detection.
What happens to invalid records?
They are excluded from paid product delivery, counted, and represented by one free run advisory when possible. Valid records in the same input can continue.
What happens when the budget is too small?
The Actor stops before the next paid push, marks budgetStopped/partial, and counts remaining unique products as withheld. It does not label them invalid.
What if pushData throws?
The Dataset outcome is unknown. The Actor stops, writes a failed no-retry receipt when possible, sets replaySafe false, and requires manual reconciliation.
What if pushData returns but the charge counter cannot be read?
The Dataset write is known to have returned, but settlement is unknown. The row is counted as delivered/unknown settlement, not as paid or free. Do not blind-retry.
Can a product be delivered free?
Yes, if the linked push returns and the named result counter remains unchanged under a valid zero-charge receipt. OUTPUT records the row as free and stops before later products.
Why is the automatic start event separate?
Apify charges the configured Actor-start event independently of product-result delivery. A no-result or failed run can still incur the start event.
Can I put API keys in sourceLicense or URLs?
No. Credential-bearing URLs are rejected, but secrets can appear in arbitrary text. Never put secrets, signed URLs, tokens, cookies, or passwords in input.
Is the input private?
Apify run storage retains input according to platform and buyer settings. Control access, choose a retention period, and delete records when the purpose ends.
Does SHA-256 anonymize a product or merchant?
No. It is an integrity and joining aid. Low-entropy identifiers can be guessed, and the row still contains supplied labels and product data.
Can this Actor publish to Zid or another marketplace?
No. It performs no catalog write. Use a separate merchant-authorized connector and require human approval.
Can I process competitor products?
Only if you have a lawful, authorized, contract-compatible right to process and deliver the exact data. Public visibility alone is not permission, and this Actor does not obtain data for you.
Is this legal advice?
No. The Actor records an attestation and technical evidence. Obtain qualified advice for licensing, privacy, consumer protection, IP, and destination obligations where needed.
What proves a successful paid run?
The exact candidate build must finish successfully; Dataset/KVS must bind the same run; delivered/paid/free/unknown partitions must reconcile; named result-found must advance exactly once per paid row; platform event counts must match; logs must be clean; and the campaign must store the IDs and hashes. README prose alone proves nothing.
Should I rerun after an uncertain result?
No. First reconcile the original run's Dataset, KVS, platform counters, and logs. Resubmit only records proven not delivered.
Sources and rights
The Actor's current source is the buyer-supplied product object. No third-party page or endpoint is queried. The permitted product contexts are:
- a merchant-owned export;
- an export the merchant explicitly authorized the buyer to process;
- a merchant-authorized integration output;
- another licensed catalog export whose terms cover the intended processing and downstream delivery.
The buyer must preserve evidence of that right outside the public Dataset. The authorization sentence and sourceLicense field make the claim visible and auditable, but they do not replace a contract, app authorization, merchant instruction, platform approval, privacy notice, or legal review.
For teams obtaining records through the Zid ecosystem, consult current official Zid developer and authorization documentation for the actual integration route and obtain the merchant's authorization before exporting. The Actor does not bundle a Zid credential, impersonate a merchant, use an anonymous internal storefront feed, or represent robots/public visibility as a redistribution licence.
Product names, descriptions, categories, images, URLs, brands, and merchant labels can involve copyright, trademark, database, confidentiality, contract, consumer-protection, and privacy obligations. Supplying a URL does not transfer rights. Supplying an image URL does not authorize copying or display. Keep only fields necessary for the declared purpose, minimize personal data, disclose the processing where required, honor correction/deletion requests, and delete retained run data when the purpose ends.
The Actor is not affiliated with, endorsed by, or sponsored by Zid. Zid identifies the intended authorized export context. If your authorization is withdrawn or the source terms no longer permit processing, stop submitting records and delete retained copies as appropriate.
Before public or production use, complete this checklist:
- Identify the merchant/data owner.
- Identify the export/integration mechanism.
- Retain written authorization or applicable licence.
- Confirm the right covers the submitted fields and downstream delivery.
- Remove secrets, customers, orders, contacts, and unnecessary personal data.
- Confirm URLs contain no credentials or expiring signatures.
- Set retention and deletion dates.
- Assign a human reviewer.
- Set a bounded maximum charge.
- Reconcile the exact run before any downstream action.
If those conditions cannot be met, do not run the Actor on the data. Use a merchant-controlled export, an approved official integration, or another source with explicit commercial processing rights.