Trademark Class Overlap Review
Pricing
from $17.50 / 1,000 mark assessments
Trademark Class Overlap Review
Group observed USPTO wordmarks and review class overlap across distinct serial records. Preserve reported status and date conflicts in source-linked assessments without a clearance verdict.
Pricing
from $17.50 / 1,000 mark assessments
Rating
0.0
(0)
Developer
Tim Zinin
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
Turn a batch of USPTO trademark-search rows into a per-wordmark review worksheet: identity-clean registration groups, exact class intersection/union across records, and every status or field disagreement kept visible — never a clearance verdict.
A USPTO trademark search can return the same wordmark under many different serial_number records — separate applications, separate registrations, separate classes filed at different times. This Actor turns that scattered result set into one row per distinct wordmark, with the class coverage, status agreement, and record-level conflicts already reconciled and disclosed, so a reviewer opens one worksheet row instead of re-reading every raw search hit by hand.

What you get
Point this Actor at a dataset of USPTO trademark-search rows — the shape produced by dev00/uspto-trademark-api — and it delivers one mark assessment row per distinct normalized wordmark, after two passes of honesty checks most naive dedup scripts skip:
- Global identity reconciliation, before any grouping. Every accepted row's
serial_numberis collected across the whole batch first. If the sameserial_numberwas ever observed with two different wordmarks, that is reported as one freeserial_identity_conflictdiagnostic listing every wordmark seen for it, and the serial is excluded from every wordmark group — it can never land in two billable groups, and the conflict is never silently resolved by picking one value. - Exact wordmark grouping, applied only after identity reconciliation: Unicode NFKC normalization,
toLowerCase()case-folding, whitespace collapse — a disclosed, documented text comparison, never phonetic similarity, confusion, or a legal-clearance judgment."acme"and"akme"are always separate groups. - Class intersection and union across the group's distinct, identity-clean records, parsed only from documented explicit numeric tokens (1–45) in the source
classesstring — every invalid or out-of-range token counted exactly, never truncated by any display cap, and a record contributing zero parsed classes is counted separately rather than silently treated as zero classes registered. - Status disagreements across the group's distinct records (one registration LIVE, another DEAD is normal and disclosed, not an error) and record conflicts — cases where duplicate rows for the same
serial_numberdisagreed on status, filing date, registration date, or classes, with an exact total and an exact display-omitted count. - Confidence that reflects real class-evidence gaps. A group can only reach
confidence: 'high'when it has neither an invalid class token nor a record with zero parsed classes anywhere in it — a group whose intersection was quietly built from only the successfully-parsed slice of a messyclassesstring never reads as complete, high-confidence coverage.
You do not get an availability, infringement, confusion-likelihood, or legal-clearance opinion, a phonetic or fuzzy-similarity match, or a claim that a registration is currently valid beyond what the batch literally contained. See Evidence and boundaries for the full list.
Who uses it
- Trademark paralegals and IP counsel doing a first-pass triage of a USPTO search-report export before a clearance opinion — this Actor collapses duplicate search hits into one row per mark with the class coverage already computed, so the attorney's own review starts from a worksheet, not a raw hit list.
- Brand and IP portfolio managers auditing their own company's registered marks across classes, using
hasStatusDisagreementandrecordConflictsto catch stale or inconsistent portfolio-tracking data before a renewal cycle. - M&A and licensing due-diligence teams reviewing a target's or licensor's trademark estate, where the class-intersection view answers "which classes does every registration of this mark actually cover" in one pass across a batch of search results.
- Competitive-intelligence and brand-monitoring researchers tracking a competitor's filing activity across classes over time, using the record-level evidence (filing/registration dates, per-record classes) as a citation trail back to the individual USPTO serial numbers.
- Data teams building a downstream trademark-portfolio dataset who want a pure, deterministic, non-LLM transform they can re-run identically against a refreshed USPTO pull and diff against the previous run's output.
This Actor is not a substitute for a formal USPTO clearance search, a likelihood-of-confusion legal opinion, or an attorney's own review of the primary record — it is a reconciliation and triage layer in front of that review.
How to run
- Get source rows. Run
dev00/uspto-trademark-api(or an equivalent USPTO search producing the same row shape —success,serial_number,trademark_wordmark,status,filing_date,registration_date,classes,query_phrase) for the wordmarks you want reviewed. One row per registration/application record is expected; duplicate rows for the sameserial_numberare expected and reconciled, not an error condition. - Point this Actor at that dataset. Paste the source
datasetIdinto Source Dataset (aresourcePickerfield — Apify resolves it with your own run's READ permission, never an elevated grant), or supply arunId. An Apify Integration "Actor/task run" template can populatepayload.resourceautomatically. - Leave
itemsas the inline example, or override it. Source Dataset/runId, when set, overrides the inlineitemsarray entirely. The shipped inline example is a real, curated USPTO snapshot (see Sources and rights), so you can press Start immediately. - Set
maxResultsandmaxInputRowsto fit your batch and budget.maxResults(default 2) caps how many paid mark-assessment rows are delivered; free diagnostics are never capped.maxInputRows(default 100, ceiling 1000) caps how many source rows are read at all. - Set the platform's own Max total charge run option for a hard USD ceiling — the preflight budget check (see Pricing) already refuses to start a paid pass if even one result cannot be afforded, giving a clean
budget_stoppeddiagnostic instead of a partially-billed run. - Read the dataset. Every delivered row carries
product,schemaVersion,found,status,partial,sourceCoverage,sourceDatasetId/sourceRunId, andprocessedAtin addition to its own fields — see Field dictionary and Output examples.
There are no product-specific input fields beyond the shared source-selection fields — no asOf, no domain toggle. Every row in the batch is treated identically by the same class-parsing and identity rules.
Pricing
One pricing noun, one billing event: mark assessment (result-found). Diagnostics, budget-stop notices, source-partial notices, and empty-batch notices are always free — they never carry the result-found event, and are never billed even when they are the only output of a run.
| Apify tier | Price per mark assessment |
|---|---|
| Free | $0.0250 |
| Bronze | $0.0225 (10% off) |
| Silver | $0.0200 (20% off) |
| Gold | $0.0175 (30% off) |
| Platinum | $0.0175 (30% off) |
| Diamond | $0.0175 (30% off) |
There is no separate start fee or per-run flat fee — you are charged only for delivered, useful mark-assessment rows, one result-found event per distinct normalized wordmark actually delivered. A run producing zero useful results (an empty batch, a fully invalid batch, or a run stopped by your own budget before any result could be afforded) has no result-found event charge; owner validation and platform resource expenses are separate.
Billing is write-then-charge, non-transactional, and fails closed on ambiguity: the runtime writes a result row first, then requests the charge; if the charge cannot be confirmed, it does not silently retry (a retry risking a double charge is refused), and the run is marked failed rather than a clean success it cannot verify. An already-delivered result can, in a rare failure case, remain in the Dataset without a confirmed matching charge — chargedEventCounts.result-found (see each scenario's own settled.json reconciliation below) is the authoritative confirmed count, not guaranteed to equal the visible useful-row count on every failure path. A new run against the same input is new processing and may bill again — no deduplication against a prior run's delivered wordmark groups.
Before reading any source, the runtime preflights affordability: if your charge ceiling (platform Max total charge) cannot cover even one result at your account's tier, the run stops immediately with a free budget_stopped diagnostic and reads no source rows — see below-price-r2 in Output examples.
Input contract
This Actor consumes the shared PPE (pay-per-event) source contract used across this batch of downstream Actors — a single JSON input object, read once at Actor start:
| Field | Type | Required | Notes |
|---|---|---|---|
items | array | No | Inline source rows (max 1000 by schema; bounded to 1000 rows / 4 MiB total / 64 KiB per row by the runtime). Ships pre-filled with a real, curated USPTO snapshot (3 rows). Ignored once datasetId/runId resolves a source. |
datasetId | string (resourcePicker, dataset, READ) | No | Existing Dataset ID, resolved with your own run's permission. Overrides inline items. Configure your integration to map {{resource.defaultDatasetId}} explicitly; the Actor does not populate this field itself. |
runId | string | No | Actor run ID whose default Dataset is read instead, resolved with your own permission — this Actor never starts the upstream run itself. |
payload | object | No | An explicitly supplied resource envelope; default empty. Malformed or conflicting same-kind IDs are rejected. Dataset selection never grants private read permission by itself. |
maxInputRows | integer, 1–1000 | No (default 100) | Caps source rows read. Rows beyond this are reported via sourcePartial/sourcePartialReason: 'max_input_rows_reached', never silently truncated. |
maxResults | integer, 1–1000 | No (default 2) | Caps paid rows delivered. Free diagnostics are never capped. A free max_results_reached diagnostic states exact delivered/totalUseful. |
Recognized row shape: success (must be true — and is overridden by any contradictory failure evidence, see below), serial_number (required — accepted as a positive integer or an all-digit string), trademark_wordmark (required — the grouping key after normalization), status, filing_date/registration_date (strict YYYY-MM-DD event dates, never a capture timestamp), classes (source string; only 1–45 numeric tokens split on comma/semicolon/slash/whitespace are parsed), query_phrase (ignored entirely — it is the search query used to find the record, never the mark's own identity).
Contradictory failure evidence always overrides success: true. A row carrying found: false, failed: true, a failure-status word (failed/error/timed-out/aborted), or a nonempty error/errors field is rejected as a free source_row_failed diagnostic regardless of its own success flag — a self-contradicting row is never trustworthy identity evidence. A row missing a usable serial_number or trademark_wordmark is a separate free diagnostic (missing_serial_number/missing_wordmark); neither ever produces a fabricated paid result.
Output examples
Every scenario below is the complete, unedited JSON array written to this Actor's Dataset by a real cloud run of this Actor's current code (build 0.1.2, buildId fESgb3d7NfJDjFmvR), captured under ops/value-add-next-20260923/evidence/actors/trademark-class-overlap-review/<scenario>/items.json, cross-checked against each run's own settled.json. Nothing below is paraphrased, trimmed, or re-ordered.
final-prefill-r2 — the shipped inline example
Real public "star wars" USPTO search snapshot (see Sources and rights): three distinct, identity-clean serial numbers, all normalizing to the same wordmark. settled.json confirms chargedEventCounts.result-found: 1, "delivered: 1 paid, 0 free.".
[{"entityId": "wordmark:star wars","found": true,"status": "class_group_reviewed","action": "review_class_group","confidence": "high","normalizedWordmark": "star wars","wordmark": "star wars","distinctRecordCount": 3,"classIntersection": [25],"classUnion": [25],"recordsWithNoParsedClasses": 0,"invalidClassTokenCount": 0,"statusValues": ["LIVE"],"hasStatusDisagreement": false,"evidenceOmitted": 0,"recordConflicts": [],"recordConflictCount": 0,"recordConflictsOmitted": 0,"observedAt": null,"evidence": [{"field": "serial_number","serialNumber": "73149856","status": "LIVE","filingDate": "1977-11-25","registrationDate": "1979-10-30","classes": [25],"sourceRowIndex": 0},{"field": "serial_number","serialNumber": "73487823","status": "LIVE","filingDate": "1984-06-29","registrationDate": "1985-11-19","classes": [25],"sourceRowIndex": 1},{"field": "serial_number","serialNumber": "75306994","status": "LIVE","filingDate": "1997-06-11","registrationDate": "2002-01-29","classes": [25],"sourceRowIndex": 2}],"businessPartial": false,"sourceRowIndexes": [0,1,2],"partial": false,"sourceCoverage": {"complete": true,"reason": null,"droppedOversized": 0},"product": "trademark-class-overlap-review","schemaVersion": "1.0","sourceDatasetId": null,"sourceRunId": null,"suppliedSourceRunId": null,"sourceRunIdVerified": null,"processedAt": "2026-09-23T08:32:25.670Z"}]
Three genuinely distinct serial numbers — filed 1977, 1984, and 1997, all LIVE, all Class 25 — reconcile into one distinctRecordCount: 3 group with classIntersection: [25] and no disagreement anywhere, which is exactly why this row reaches confidence: 'high': zero invalid class tokens and zero records with no parsed classes.
partial-columns-r2 — bounded source (maxInputRows: 1)
This scenario name is a legacy label from the shared naming convention: it means the run was bounded by maxInputRows: 1, not that any column/field was deleted — every field of the one row actually read is unchanged. settled.json confirms "delivered: 1 paid, 1 free.".
[{"status": "partial_source","reason": "max_input_rows_reached","processedAt": "2026-09-23T08:33:42.003Z","partial": true,"sourceCoverage": {"complete": false,"reason": "max_input_rows_reached","droppedOversized": 0},"product": "trademark-class-overlap-review","schemaVersion": "1.0","sourceDatasetId": null,"sourceRunId": null,"suppliedSourceRunId": null,"sourceRunIdVerified": null,"found": false},{"entityId": "wordmark:star wars","found": true,"status": "class_group_reviewed","action": "review_class_group","confidence": "high","normalizedWordmark": "star wars","wordmark": "star wars","distinctRecordCount": 1,"classIntersection": [25],"classUnion": [25],"recordsWithNoParsedClasses": 0,"invalidClassTokenCount": 0,"statusValues": ["LIVE"],"hasStatusDisagreement": false,"evidenceOmitted": 0,"recordConflicts": [],"recordConflictCount": 0,"recordConflictsOmitted": 0,"observedAt": null,"evidence": [{"field": "serial_number","serialNumber": "73149856","status": "LIVE","filingDate": "1977-11-25","registrationDate": "1979-10-30","classes": [25],"sourceRowIndex": 0}],"businessPartial": false,"sourceRowIndexes": [0],"partial": true,"sourceCoverage": {"complete": false,"reason": "max_input_rows_reached","droppedOversized": 0},"product": "trademark-class-overlap-review","schemaVersion": "1.0","sourceDatasetId": null,"sourceRunId": null,"suppliedSourceRunId": null,"sourceRunIdVerified": null,"processedAt": "2026-09-23T08:33:42.066Z"}]
Note confidence: 'high' here despite partial: true — the two are independent. This particular one-record group has zero invalid class tokens and zero unparsed-class records (the class evidence itself is complete), so confidence stays high; partial: true is driven entirely by sourceCoverage.complete: false propagating from the run-level maxInputRows bound, not by any class-parsing gap. A batch that instead triggered an invalid Nice class token or a record with zero parsed classes would additionally force confidence to 'medium' (or 'low' if a record conflict was also present) — see Evidence and boundaries for the exact confidence rule and Decision routing for how to read the two signals together.
below-price-r2 — preflight budget refusal, source never read
maxTotalChargeUsd: 0.005 set below the cost of one result. settled.json confirms chargedEventCounts.result-found: 0, "budget_stopped: 0 paid, 1 free." — the preflight guard refuses the source read once it determines the charge ceiling cannot cover one result.
[{"product": "trademark-class-overlap-review","schemaVersion": "1.0","status": "budget_stopped","reason": "Run charge limit cannot cover any result; no source was read.","found": false,"processedAt": "2026-09-23T08:33:19.904Z"}]
empty-source-r2 — a batch with no usable rows
[{"product": "trademark-class-overlap-review","schemaVersion": "1.0","status": "no_results","found": false,"reason": "no_usable_rows_in_batch","sourceCoverage": {"complete": true,"reason": null,"droppedOversized": 0},"processedAt": "2026-09-23T08:33:10.741Z"}]
This is the runtime's explicit floor: a run that would otherwise write nothing (no paid result, no diagnostic) writes this one free row instead, so a buyer's Dataset reads as "the batch genuinely had nothing usable" rather than an empty, unexplained silence. Like every dataset write in this runtime, that floor write is not unconditional: if the write itself fails, the run is reported failed (never a false empty success) rather than silently skipping the row — see Evidence and boundaries for the write-then-charge honesty rules that apply to every row this Actor writes.
Field dictionary
Every field delivered on a found:true row, beyond the shared runtime envelope (product, schemaVersion, found, status, action, confidence, partial, businessPartial, evidence, sourceRowIndexes, sourceCoverage, sourceDatasetId, sourceRunId, suppliedSourceRunId, sourceRunIdVerified, processedAt):
| Field | Meaning |
|---|---|
normalizedWordmark / wordmark | The grouping key (raw.normalize('NFKC').trim().replace(/\s+/g,' ').toLowerCase()) and a display copy of the raw text — computed only after global serial_number identity reconciliation (see Identity and grouping rules below). |
distinctRecordCount | Unique, identity-clean serial_number values in this group. Each is a fully distinct registration/application record, even when the wordmark text is identical. A serial_number observed with more than one distinct wordmark is excluded from every group entirely — see identityConflictedSerialCount in the run summary. |
classIntersection | Sorted array of numeric classes (1–45) present on every record in the group that had at least one parsed class. Records with zero parsed classes are excluded from this intersection and counted separately in recordsWithNoParsedClasses. Empty when no record had a parsed class, or when the parsed classes share nothing in common. |
classUnion | Sorted array of every distinct class parsed across any record in the group. |
recordsWithNoParsedClasses | Count of distinct records whose classes field yielded zero valid 1–45 tokens (missing field, wrong type, or every token invalid) — an explicit gap, never treated as zero classes registered. |
invalidClassTokenCount | The exact total count, across every record in the group, of classes-string tokens that failed the documented 1–45 numeric parse — every token counted, never truncated by any display cap. |
statusValues / hasStatusDisagreement | Sorted distinct status strings across the group's distinct records, and whether more than one value was observed (e.g. one registration LIVE, another DEAD — genuinely normal, disclosed rather than hidden). |
recordConflicts / recordConflictCount / recordConflictsOmitted | Bounded list (cap 10) of { serialNumber, field, values, sourceRowIndexes } where the same serial_number was observed with more than one distinct value for status, filing date, registration date, or classes across duplicate rows, the exact total found, and the exact count not displayed. |
evidence / evidenceOmitted | Bounded list (cap 12) of per-record { serialNumber, status, filingDate, registrationDate, classes, sourceRowIndex }, and the exact count of this group's records not shown. |
observedAt | Always null — this Actor's documented USPTO source rows carry only event dates (filing_date/registration_date), never a capture timestamp, so an observation time is never fabricated. |
Evidence and boundaries
Source correspondence is checked when run metadata is accessible: a proven run/Dataset mismatch is rejected. If metadata is inaccessible but an explicit Dataset is readable, processing can continue with sourceRunIdVerified false. Only source requests use GET; SDK output and billing perform writes. Diagnostic delivery is bounded to200 rows and64KiB per row; the summary records truncation/oversized omissions. Storage failure can prevent OUTPUT/SUMMARY persistence, and ambiguous writes may leave raw rows above confirmed counters. A run cap below one result stops before source reading; a cap covering part of the batch can deliver that part.
What this Actor deliberately does not claim, matching the source contract in SPEC.md exactly:
- Not a clearance, availability, or infringement opinion.
confidenceandactiondescribe evidence coverage and a suggested next step, never a legal verdict. This Actor never asserts a mark is available to register, clear to use, non-infringing, or currently valid beyond what the supplied batch literally contained. - Not similarity or confusion matching. Grouping is exact Unicode NFKC normalization, case-folding, and whitespace collapse only — a disclosed, documented text comparison, never a phonetic, confusion, or legal-similarity judgment. Two marks that a trademark examiner might treat as confusingly similar (different spelling, same sound) are always separate groups here.
- A record with zero parsed classes is never treated as zero classes registered. It is counted in
recordsWithNoParsedClasses, an explicit, disclosed gap in the evidence, distinct from a genuine finding of no overlapping classes. - An invalid
classestoken is never silently dropped or coerced into a nearby valid class. It is counted exactly ininvalidClassTokenCount, with no display cap ever truncating that count, even when the group'sclassIntersectionitself is derived only from the tokens that did parse. - A
success: trueflag never overrides contradictory failure evidence on the same row.found: false,failed: true, a failure-status word, or a nonemptyerror/errorsfield is checked unconditionally, before thesuccessgate — a self-contradicting row is rejected outright, never trusted as identity evidence just because one field claimed success. - A conflicted
serial_numberis never split across two billable groups, and never silently assigned to one. Identity reconciliation runs globally across the whole batch, before any grouping exists — see Identity and grouping rules below. - Confidence reflects real class-evidence gaps, precisely.
confidencereserves'high'only when bothinvalidClassTokenTotal === 0andrecordsWithNoParsedClasses === 0across every record in the group (otherwise'medium', or'low'ifrecordConflictsTotal > 0also holds);partialis also forcedtruewhenever either condition holds — a group whoseclassIntersectioncame from only the successfully-parsed portion of a messyclassesvalue (e.g."9 bad") never reads as complete, high-confidence coverage with no visible signal that part of the evidence was unusable. - No DOB, address, nationality, or any personal-identity field anywhere — this Actor's entire source contract is USPTO wordmark/registration records, which carry no personal-identity fields to begin with; nothing here processes or outputs one.
- Replay and billing honesty.
EXISTING_RESULT/EXISTING_CLAIMguard against re-processing an already-claimed run; achargedEventCounts.result-foundmismatch halts further billing rather than risk a duplicate charge. Delivery is write-then-charge and non-transactional, so a Dataset write can succeed while charge confirmation cannot — the run is then reported failed, with the honest delivered count in the message, never a false "succeeded". Summary/OUTPUT persistence is itself best-effort: a failure there also fails the run (FINALIZATION_FAILED); dataset rows/logs remain the source of truth.
Identity and grouping rules
Before any wordmark grouping exists, every accepted row's serial_number is collected across the whole batch. A serial_number observed with more than one distinct normalized trademark_wordmark is an explicit identity conflict — reported as one free serial_identity_conflict diagnostic listing every wordmark seen for it, and excluded from every wordmark group entirely. Only after this global pass do the remaining, identity-clean records get grouped by their exact normalized wordmark text. This ordering matters: it is what prevents a single messy serial number from contaminating two separate billable groups, or from being silently and arbitrarily assigned to just one of them.
Decision routing
A suggested triage order for a batch of delivered rows, not an automated verdict:
confidence: high,recordConflictCount: 0— the cleanest signal: every record in the group contributed at least one parsed class, no invalid tokens anywhere, no duplicate-row disagreement.classIntersectionis a trustworthy summary of shared class coverage across every clean record.confidence: medium— at least one record had an invalid class token or contributed zero parsed classes.classIntersection/classUnionare still exact for the evidence that did parse, but checkinvalidClassTokenCount/recordsWithNoParsedClassesbefore treating the class picture as complete — a class genuinely registered but recorded as an unparseable token in the source is not visible in the intersection.confidence: low(recordConflictCount > 0) — at least oneserial_numberin the group carries an unresolved field disagreement across duplicate source rows. Resolve the conflict (or re-query) before relying on that record's status, dates, or classes.hasStatusDisagreement: true— normal and expected when a mark has multiple registrations with different lifecycle states; not itself a data-quality signal, but worth surfacing to a reviewer deciding which specific registration matters for their question.- Free diagnostic rows (
serial_identity_conflict,max_results_reached,budget_stopped,partial_source,no_results) — run- or identity-level signals, not wordmark-group results.serial_identity_conflictin particular is worth a manual look: it means the source data itself disagreed on what a specific application/registration is called.
Commercial playbooks
- Pre-filing clearance triage. Run a USPTO search across your candidate wordmark and close variants, then use this Actor's grouped output as the first-pass worksheet an attorney reviews before commissioning a full clearance search — this Actor narrows "which existing registrations share my exact normalized wordmark and what classes do they cover," leaving similarity/confusion judgment to counsel.
- Portfolio renewal audit. Batch your own company's full registered-mark list, and treat any
hasStatusDisagreement: trueorrecordConflictCount > 0group as a flag to reconcile against your internal portfolio tracker before a renewal deadline — a status disagreement in the source data is often the first sign an internal record has drifted from the USPTO record of truth. - Licensing and franchise due diligence. For a licensor's mark portfolio, the class-intersection view answers "which classes does every registration of this mark actually, currently cover" in one batch pass, giving a licensing team a citation-backed starting point before the formal IP due-diligence review.
- M&A trademark-estate review. Batch a target company's known marks alongside your own, and use
classUnion/classIntersectionside by side to spot class-coverage gaps or overlaps worth a specific line item in the diligence memo. - Competitive filing-activity monitoring. Re-run periodically (see Integration recipes) against a competitor's known brand names, diffing delivered
distinctRecordCount/classUnionbetween runs to catch newly-filed classes since the last check — each scheduled run is new processing and bills again per the no-dedup replay policy.
Integration recipes
Apify Integration setup. Map {{resource.defaultDatasetId}} into Source Dataset and configure the destination run’s Dataset READ grant. Optionally supply a matching resource envelope in payload; the envelope grants no access by itself.
A bounded, explicit Apify API call (using your own API token, never embedded in this README):
POST https://api.apify.com/v2/acts/zinin~trademark-class-overlap-review/runs?maxTotalChargeUsd=0.50Authorization: Bearer <YOUR_API_TOKEN>Content-Type: application/json{"datasetId": "<upstream USPTO search Dataset ID you already control READ access to>","maxInputRows": 200,"maxResults": 20}
datasetId is a resourcePicker-backed field — the platform enforces that your API token's own READ permission on that Dataset is what is checked, never an elevated grant carried by this Actor. A payload envelope with no resolving datasetId/runId inside it is never sufficient permission on its own — see Input contract.
A clearly-labelled webhook registration TEMPLATE — an illustrative registration against Apify's own webhook API to be notified when a run finishes, not a captured execution, and it deliberately omits any real token:
{"eventTypes": ["ACTOR.RUN.SUCCEEDED", "ACTOR.RUN.FAILED"],"condition": { "actorId": "<your-actor-id>" },"requestUrl": "https://your-own-endpoint.example.com/webhooks/trademark-class-overlap","headersTemplate": "{\"Authorization\":\"Bearer <YOUR_OWN_ENDPOINT_SECRET>\"}","payloadTemplate": "{\"runId\":\"{{resource.id}}\",\"datasetId\":\"{{resource.defaultDatasetId}}\",\"status\":\"{{resource.status}}\"}","doNotRetry": true}
condition is what scopes this webhook to this Actor's own runs only, never a global listener. headersTemplate, like payloadTemplate, is a JSON-encoded string in Apify's webhook API, not a nested object — the placeholder Authorization value shown here is illustrative only, never a real token, and is never placed in the requestUrl itself. doNotRetry: true is deliberate: because delivery is write-then-charge and non-transactional (see Pricing), an automatic webhook retry on your receiving endpoint could re-process an already-delivered run's notification as a new one. Treat a missed webhook as a signal to poll run status via the API, not a reason to auto-retry.

n8n / Make: use the native Apify node (or a generic HTTP node against the API call above) to trigger a run on a schedule or the upstream search's completion webhook, then branch on each delivered row's confidence/hasStatusDisagreement field to route low-confidence or disagreeing groups into a review queue separate from clean, high-confidence rows.
MCP / agent tooling: plain JSON input/output with no product-specific authentication beyond the shared Dataset resourcePicker model, so it composes directly into an agent tool-call chain that already holds a USPTO search Dataset reference.
Operating guide
- Start small, then widen. Run with a low
maxInputRows/maxResultsagainst a known batch first (the shipped input is visible before launch; running it incurs the configured useful-result charge), confirm the field shapes match your downstream system, then raise the caps for production. - Read
confidencetogether with the two gap counts, not instead of them.invalidClassTokenCountandrecordsWithNoParsedClassesare always exact even atconfidence: 'medium'; a nonzero value on a group you care about is worth opening the rawclassesstring in your own upstream data to see exactly what failed to parse. - A capped display list does not mean capped truth.
recordConflictCountandevidenceOmittedare always exact, independent of the 10/12-item display caps. A nonzero omitted count is signal enough to escalate, or partition that wordmark’s source rows into smaller batches and check omissions on each. One-wordmark filtering alone does not remove per-group caps; deduplicate overlapping partitions before combining counts. serial_identity_conflictdiagnostics are worth reading individually, not just counting — each one names the exact conflicting wordmarks observed for one serial number, which is often enough to tell you whether the source data has a genuine data-entry problem or a legitimate historical name-change on the same registration.- Budget your run before you run it. Set the platform's Max total charge to comfortably cover your intended
maxResultsat your tier; the preflight guard (see Pricing) fails an under-budgeted run cleanly and for free before reading any source. - Re-runs are not deduplicated. For "only new registrations since last time," diff delivered
normalizedWordmark/distinctRecordCountsets between runs downstream — replay safety only refuses double-billing of the same run's own already-confirmed results. - Treat every source value as untrusted text —
status,wordmark, and every string field are bounded and never interpreted as anything beyond display text on your side either.
FAQ
Does a high-confidence result mean this mark is clear to register?
No. confidence: 'high' means the class evidence in this group is internally complete and consistent (no invalid tokens, no unparsed-class records, no record conflicts) — it says nothing about availability, infringement, or confusion with any other mark. See Evidence and boundaries.
Does classIntersection being empty mean the mark has no registered classes?
Not necessarily. Check recordsWithNoParsedClasses first — an empty intersection can mean the group's records genuinely share no common class, or that some records contributed no parseable class data at all. The two cases are distinguished explicitly, never conflated.
Why did two search hits for what looks like the same mark end up in different groups? Grouping is exact NFKC-normalized, case-folded, whitespace-collapsed text — not phonetic or fuzzy matching. Any character-level difference (including one a human might read as "the same mark") produces a separate group. This is deliberate: see Evidence and boundaries.
What does a serial_identity_conflict diagnostic mean?
The same serial_number was observed with more than one distinct wordmark across your batch — a genuine data disagreement in the source. That serial is excluded from every wordmark group rather than guessed into one; see Decision routing.
Why did my run deliver fewer paid rows than expected?
Check the free diagnostics: max_results_reached states exact delivered/totalUseful (raise maxResults and re-run — bills again for the additional rows only); budget_stopped means your charge ceiling was reached; partial_source means the source batch was bounded.
What happens if a classes string has an invalid token mixed with valid ones, like "9 bad 25"?
The valid tokens (9, 25) still contribute to classIntersection/classUnion; the invalid token (bad) is counted in invalidClassTokenCount. This also forces confidence down from 'high' and partial: true on the affected group.
Is this Actor's result a trademark clearance opinion? No. It is a reconciliation and triage worksheet for a human reviewer or attorney — never a legal-clearance, availability, or infringement determination. Pair it with a formal clearance search and counsel's own review for an actual legal opinion.
Sources and rights
Source data originates from the USPTO's public trademark records, via the dev00/uspto-trademark-api Actor's documented output shape. This Actor never calls the USPTO API or website directly — it only transforms rows you already collected through your own upstream source.
The inline example shipped with this Actor's input schema is a real, curated projection of an actual dev00/uspto-trademark-api run (actorId nhSY7qeLJUsvkXQTH, runId 1UQYwy4rLd96omF0V, datasetId bV1vfVZVsUCA3PT1R, captured 2026-09-23) — public trademark-record fields only, values unchanged, with an added __source object disclosing provenance. It is a snapshot, not a live query on every run of this Actor; re-run the upstream search yourself for current data.
USPTO trademark records are US federal public records. This README makes no revenue, accuracy, or legal-compliance guarantee beyond the documented, testable behavior of the transform, and nothing here constitutes legal, trademark-clearance, or investment advice — a formal clearance opinion requires a licensed attorney's own review of the primary USPTO record.
Related Zinin/ Actors you may already have in your account* (each independently public and priced — adjacent workflow context, not a claim their rows are directly compatible input to this Actor):
- zinin/patent-monitor — a separate, independently-sourced patent-filing watch for the same company or inventor names; useful alongside a trademark portfolio review for a broader IP picture, no shared data model.
- zinin/company-registry-enricher — company-registry lookups to confirm the legal entity actually behind a trademark applicant/registrant name before a licensing or M&A review.
- zinin/litigation-check — litigation-evidence Actor you can run against the same named companies or mark owners for a broader due-diligence picture; run as its own separate pass.
- zinin/sec-edgar-watcher — for a US-listed licensor or licensee, a complementary SEC-filing watch; no shared input format, point it at its own source.