> ## Documentation Index
> Fetch the complete documentation index at: https://docs.signa.so/llms.txt
> Use this file to discover all available pages before exploring further.

# Trademark Clearance & Screening

> Run a comprehensive availability check before launching a new brand. Search phonetically across jurisdictions, analyze conflicts by status and class, review owner profiles, and generate a clearance report.

You are preparing to launch a new brand called **"Vyntra"** for a line of cloud security software. Before investing in branding and legal filings, you need to determine whether the name is available across your target markets (US, EU, and Canada) in Nice classes 9 and 42.

This guide walks through a full clearance workflow using the Signa API -- from initial search to conflict analysis.

<Note>
  **Coming soon: Automated Clearance Intelligence.** We are building a dedicated clearance agent and scoring endpoint that will automate conflict analysis, risk scoring, and report generation. Instead of manually triaging results, you will be able to call a single endpoint that returns a structured clearance opinion with per-conflict risk scores, similarity breakdowns, and recommended actions. Stay tuned -- this is actively in development. [Contact us](mailto:support@signa.so) if you would like early access.
</Note>

## Prerequisites

* A Signa API key with `trademarks:read` scope
* Your target brand name, jurisdictions, and Nice classes

***

<Steps>
  <Step title="Run a phonetic search across jurisdictions">
    Start with a broad search using multiple strategies. Phonetic matching catches near-misses that exact search would miss -- for example, "Ventra", "Vintra", or "Wyntra".

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST https://api.signa.so/v1/trademarks \
        -H "Authorization: Bearer $SIGNA_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "query": "Vyntra",
          "strategies": ["exact", "phonetic", "fuzzy", "prefix"],
          "filters": {
            "offices": ["uspto", "euipo", "cipo"],
            "nice_classes": [9, 42],
            "status_stage": ["filed", "examining", "published", "registered", "opposition_period"]
          },
          "options": {
            "aggregations": ["status_stage", "office_code", "nice_classes"],
            "include_total": true
          },
          "limit": 50
        }'
      ```

      ```typescript TypeScript theme={null}
      import Signa from "@signa-so/sdk";

      const signa = new Signa({ api_key: process.env.SIGNA_API_KEY });

      const results = await signa.trademarks.list({
        query: "Vyntra",
        strategies: ["exact", "phonetic", "fuzzy", "prefix"],
        filters: {
          offices: ["uspto", "euipo", "cipo"],
          nice_classes: [9, 42],
          status_stage: ["filed", "examining", "published", "registered", "opposition_period"],
        },
        options: {
          aggregations: ["status_stage", "office_code", "nice_classes"],
          include_total: true,
        },
        limit: 50,
      });

      console.log(`Total results: ${results.search_meta.total_results}`);
      console.log("Aggregations:", results.aggregations);
      ```

      ```python Python theme={null}
      import os
      import requests

      resp = requests.post(
          "https://api.signa.so/v1/trademarks",
          headers={
              "Authorization": f"Bearer {os.environ['SIGNA_API_KEY']}",
              "Content-Type": "application/json",
          },
          json={
              "query": "Vyntra",
              "strategies": ["exact", "phonetic", "fuzzy", "prefix"],
              "filters": {
                  "offices": ["uspto", "euipo", "cipo"],
                  "nice_classes": [9, 42],
                  "status_stage": ["filed", "examining", "published", "registered", "opposition_period"],
              },
              "options": {
                  "aggregations": ["status_stage", "office_code", "nice_classes"],
                  "include_total": True,
              },
              "limit": 50,
          },
      )
      data = resp.json()
      print(f"Total results: {data['search_meta']['total_results']}")
      ```
    </CodeGroup>

    **Expected output:**

    ```json theme={null}
    {
      "search_meta": {
        "total_results": 14,
        "took_ms": 87,
        "timed_out": false
      },
      "aggregations": {
        "status_stage": { "registered": 6, "examining": 4, "abandoned": 3, "expired": 1 },
        "office_code": { "uspto": 8, "euipo": 4, "cipo": 2 },
        "nice_classes": { "9": 10, "42": 7, "35": 3 }
      },
      "object": "list",
      "data": [
        {
          "id": "tm_a1b2c3d4",
          "mark_text": "VENTRA",
          "status": { "primary": "active", "stage": "registered" },
          "office_code": "uspto",
          "classifications": [
            { "nice_class": 9, "goods_services_text": "Computer software for payment processing and transit fare collection" },
            { "nice_class": 42, "goods_services_text": "Software as a service (SaaS) featuring payment processing software" }
          ],
          "relevance_score": 88,
          "match_explanation": {
            "phonetic": { "score": 94, "algorithm": "double_metaphone" },
            "text": { "score": 72, "edit_distance": 2 }
          }
        }
      ]
    }
    ```

    <Tip>
      The `match_explanation` field tells you **why** each result matched. A phonetic score above 90 means the names sound nearly identical -- a serious conflict risk even if the spelling differs.
    </Tip>
  </Step>

  <Step title="Triage results by risk level">
    Use the aggregations and relevance scores to categorize matches:

    | Risk Level | Criteria                                                                                   |
    | ---------- | ------------------------------------------------------------------------------------------ |
    | **High**   | Phonetic score > 85 AND same Nice class AND status is `registered` or `examining`          |
    | **Medium** | Phonetic score 70-85 OR adjacent Nice class OR status is `published` / `opposition_period` |
    | **Low**    | Fuzzy-only match OR status is `abandoned` / `expired`                                      |

    Filter the search results to isolate high-risk conflicts:

    <CodeGroup>
      ```bash cURL theme={null}
      # Filter to registered marks with high relevance in the same classes
      curl -X POST https://api.signa.so/v1/trademarks \
        -H "Authorization: Bearer $SIGNA_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "query": "Vyntra",
          "strategies": ["exact", "phonetic"],
          "filters": {
            "offices": ["uspto", "euipo", "cipo"],
            "nice_classes": [9, 42],
            "status_stage": ["registered", "examining"]
          },
          "limit": 20
        }'
      ```

      ```typescript TypeScript theme={null}
      const highRisk = await signa.trademarks.list({
        query: "Vyntra",
        strategies: ["exact", "phonetic"],
        filters: {
          offices: ["uspto", "euipo", "cipo"],
          nice_classes: [9, 42],
          status_stage: ["registered", "examining"],
        },
        limit: 20,
      });

      const conflicts = highRisk.data.filter((tm) => tm.relevance_score >= 85);
      console.log(`High-risk conflicts: ${conflicts.length}`);
      ```

      ```python Python theme={null}
      resp = requests.post(
          "https://api.signa.so/v1/trademarks",
          headers={
              "Authorization": f"Bearer {os.environ['SIGNA_API_KEY']}",
              "Content-Type": "application/json",
          },
          json={
              "query": "Vyntra",
              "strategies": ["exact", "phonetic"],
              "filters": {
                  "offices": ["uspto", "euipo", "cipo"],
                  "nice_classes": [9, 42],
                  "status_stage": ["registered", "examining"],
              },
              "limit": 20,
          },
      )
      conflicts = [tm for tm in resp.json()["data"] if tm["relevance_score"] >= 85]
      print(f"High-risk conflicts: {len(conflicts)}")
      ```
    </CodeGroup>
  </Step>

  <Step title="Pull full details on each conflict">
    For every high-risk match, fetch the detail tier to see classifications, owners, attorneys, and prosecution history.

    <CodeGroup>
      ```bash cURL theme={null}
      # Batch fetch all conflict marks at once (max 100)
      curl -X POST https://api.signa.so/v1/trademarks/batch \
        -H "Authorization: Bearer $SIGNA_API_KEY" \
        -H "Content-Type: application/json" \
        -H "Idempotency-Key: clearance-vyntra-batch-001" \
        -d '{
          "ids": ["tm_a1b2c3d4", "tm_e5f6a7b8", "tm_c9d0e1f2"]
        }'
      ```

      ```typescript TypeScript theme={null}
      const details = await signa.trademarks.batch({
        ids: conflicts.map((c) => c.id),
      });

      for (const tm of details.data) {
        console.log(`${tm.mark_text} (${tm.office_code})`);
        console.log(`  Status: ${tm.status.stage}`);
        console.log(`  Classes: ${tm.classifications.map((c) => c.nice_class).join(", ")}`);
        console.log(`  Owner: ${tm.owners[0]?.name}`);
        console.log(`  G&S: ${tm.classifications[0]?.goods_services_text}`);
      }
      ```

      ```python Python theme={null}
      resp = requests.post(
          "https://api.signa.so/v1/trademarks/batch",
          headers={
              "Authorization": f"Bearer {os.environ['SIGNA_API_KEY']}",
              "Content-Type": "application/json",
              "Idempotency-Key": "clearance-vyntra-batch-001",
          },
          json={
              "ids": [c["id"] for c in conflicts],
          },
      )
      for tm in resp.json()["data"]:
          print(f"{tm['mark_text']} ({tm['office_code']})")
          print(f"  Status: {tm['status']['stage']}")
          print(f"  Owner: {tm['owners'][0]['name']}")
      ```
    </CodeGroup>

    **Expected output (per mark):**

    ```json theme={null}
    {
      "id": "tm_a1b2c3d4",
      "mark_text": "VENTRA",
      "status": { "primary": "active", "stage": "registered" },
      "office_code": "uspto",
      "classifications": [
        {
          "nice_class": 9,
          "goods_services_text": "Computer software for payment processing and transit fare collection"
        },
        {
          "nice_class": 42,
          "goods_services_text": "Cloud computing services for payment platforms"
        }
      ],
      "owners": [
        { "id": "own_xyz789", "name": "Cubic Transportation Systems Inc.", "country_code": "US" }
      ],
      "filing_date": "2019-04-12",
      "registration_date": "2020-01-14"
    }
    ```

    <Note>
      Pay close attention to the `goods_services_text` in each classification. Two marks in the same Nice class can coexist if their goods and services descriptions do not overlap. "Payment processing software" and "cybersecurity software" are both Class 9 but serve different markets.
    </Note>
  </Step>

  <Step title="Review the owner's full portfolio">
    Understanding the conflicting owner's portfolio reveals how aggressively they protect their brand and whether they operate in adjacent spaces.

    <CodeGroup>
      ```bash cURL theme={null}
      # Get owner profile with stats
      curl https://api.signa.so/v1/owners/own_xyz789 \
        -H "Authorization: Bearer $SIGNA_API_KEY"

      # List their marks in classes 9 and 42
      curl "https://api.signa.so/v1/owners/own_xyz789/trademarks?nice_classes=9,42&limit=50" \
        -H "Authorization: Bearer $SIGNA_API_KEY"
      ```

      ```typescript TypeScript theme={null}
      const owner = await signa.owners.retrieve("own_xyz789");

      console.log(`Portfolio size: ${owner.stats.trademark_count}`);
      console.log(`Registration rate: ${(owner.stats.registration_rate * 100).toFixed(0)}%`);
      console.log(`Jurisdictions: ${owner.stats.jurisdiction_count}`);

      const ownerMarks = await signa.owners.trademarks("own_xyz789", {
        nice_classes: [9, 42],
        limit: 50,
      });
      console.log(`Marks in Class 9/42: ${ownerMarks.data.length}`);
      ```

      ```python Python theme={null}
      owner = requests.get(
          "https://api.signa.so/v1/owners/own_xyz789",
          headers={"Authorization": f"Bearer {os.environ['SIGNA_API_KEY']}"},
      ).json()

      print(f"Portfolio size: {owner['stats']['trademark_count']}")
      print(f"Registration rate: {owner['stats']['registration_rate'] * 100:.0f}%")
      print(f"Jurisdictions: {owner['stats']['jurisdiction_count']}")
      ```
    </CodeGroup>

    **Expected output:**

    ```json theme={null}
    {
      "stats": {
        "trademark_count": 142,
        "registered_count": 118,
        "jurisdiction_count": 12,
        "registration_rate": 0.83
      }
    }
    ```

    <Tip>
      A high `registration_rate` (above 80%) and broad jurisdiction coverage suggest an owner with an active legal team. They are more likely to oppose a confusingly similar filing.
    </Tip>
  </Step>

  <Step title="Check for proceedings history">
    See whether the conflicting mark has been involved in oppositions or cancellations. This tells you how actively the owner enforces their rights.

    <CodeGroup>
      ```bash cURL theme={null}
      # Check proceedings on the conflicting mark
      curl "https://api.signa.so/v1/trademarks/tm_a1b2c3d4/proceedings" \
        -H "Authorization: Bearer $SIGNA_API_KEY"

      # Search for opposition proceedings involving the owner
      curl "https://api.signa.so/v1/proceedings?q=Cubic+Transportation+Systems&type=opposition&limit=20" \
        -H "Authorization: Bearer $SIGNA_API_KEY"
      ```

      ```typescript TypeScript theme={null}
      // Check proceedings on the conflicting mark
      const proceedings = await signa.trademarks.proceedings("tm_a1b2c3d4");

      // Search for opposition proceedings involving the owner
      const ownerOppositions = await signa.proceedings.list({
        q: "Cubic Transportation Systems",
        type: "opposition",
        limit: 20,
      });

      console.log(`Mark proceedings: ${proceedings.data.length}`);
      console.log(`Owner oppositions filed: ${ownerOppositions.data.length}`);

      for (const p of ownerOppositions.data) {
        console.log(`  ${p.proceeding_type} (${p.status}) - filed ${p.filed_date}`);
      }
      ```

      ```python Python theme={null}
      proceedings = requests.get(
          "https://api.signa.so/v1/trademarks/tm_a1b2c3d4/proceedings",
          headers={"Authorization": f"Bearer {os.environ['SIGNA_API_KEY']}"},
      ).json()

      oppositions = requests.get(
          "https://api.signa.so/v1/proceedings",
          params={"q": "Cubic Transportation Systems", "type": "opposition", "limit": 20},
          headers={"Authorization": f"Bearer {os.environ['SIGNA_API_KEY']}"},
      ).json()

      print(f"Mark proceedings: {len(proceedings['data'])}")
      print(f"Owner oppositions filed: {len(oppositions['data'])}")
      ```
    </CodeGroup>

    **Expected output:**

    ```json theme={null}
    {
      "object": "list",
      "data": [
        {
          "id": "prc_op001",
          "proceeding_type": "opposition",
          "status": "decided_granted",
          "parties": [
            { "owner_id": "own_xyz789", "name": "Cubic Transportation Systems Inc.", "role": "opponent" },
            { "owner_id": "own_other", "name": "Ventra Labs LLC", "role": "respondent" }
          ],
          "filed_date": "2023-06-15",
          "decision_date": "2024-02-20"
        }
      ]
    }
    ```

    <Note>
      An owner who has successfully opposed similar marks in the past poses a higher risk. In this example, Cubic already won an opposition against another "Ventra"-variant mark -- strong evidence they would oppose "Vyntra" too.
    </Note>
  </Step>

  <Step title="Compile a clearance summary">
    Bring together all findings into a structured report. Here is a helper that assembles the data:

    <CodeGroup>
      ```typescript TypeScript theme={null}
      interface ClearanceConflict {
        trademarkId: string;
        markText: string;
        office: string;
        status: string;
        niceClasses: number[];
        phoneticScore: number;
        ownerName: string;
        ownerPortfolioSize: number;
        ownerOppositionHistory: number;
        riskLevel: "high" | "medium" | "low";
      }

      function assessRisk(conflict: {
        phoneticScore: number;
        status: string;
        ownerOppositions: number;
      }): "high" | "medium" | "low" {
        if (conflict.phoneticScore >= 85 && conflict.status === "registered") {
          return "high";
        }
        if (conflict.phoneticScore >= 70 || conflict.ownerOppositions > 0) {
          return "medium";
        }
        return "low";
      }

      // Build the report
      const report = {
        candidateName: "Vyntra",
        targetJurisdictions: ["us", "eu", "ca"],
        targetClasses: [9, 42],
        searchDate: new Date().toISOString(),
        totalMatches: results.search_meta.total_results,
        conflicts: conflicts.map((tm) => ({
          trademarkId: tm.id,
          markText: tm.mark_text,
          office: tm.office_code,
          status: tm.status.stage,
          niceClasses: tm.classifications.map((c) => c.nice_class),
          phoneticScore: tm.match_explanation.phonetic?.score ?? 0,
          ownerName: tm.owner_name,
          riskLevel: assessRisk({
            phoneticScore: tm.match_explanation.phonetic?.score ?? 0,
            status: tm.status.stage,
            ownerOppositions: 1, // from step 5
          }),
        })),
        recommendation:
          conflicts.some((c) => c.relevance_score >= 90)
            ? "HIGH RISK - Consider alternative names"
            : "MODERATE RISK - Proceed with legal counsel review",
      };

      console.log(JSON.stringify(report, null, 2));
      ```

      ```python Python theme={null}
      import json
      from datetime import datetime

      def assess_risk(phonetic_score, status, owner_oppositions):
          if phonetic_score >= 85 and status == "registered":
              return "high"
          if phonetic_score >= 70 or owner_oppositions > 0:
              return "medium"
          return "low"

      report = {
          "candidate_name": "Vyntra",
          "target_jurisdictions": ["us", "eu", "ca"],
          "target_classes": [9, 42],
          "search_date": datetime.now().isoformat(),
          "total_matches": data["search_meta"]["total_results"],
          "conflicts": [
              {
                  "trademark_id": tm["id"],
                  "mark_text": tm["mark_text"],
                  "office": tm["office_code"],
                  "status": tm["status"]["stage"],
                  "nice_classes": [c["nice_class"] for c in tm["classifications"]],
                  "phonetic_score": tm.get("match_explanation", {}).get("phonetic", {}).get("score", 0),
                  "owner_name": tm["owner_name"],
                  "risk_level": assess_risk(
                      tm.get("match_explanation", {}).get("phonetic", {}).get("score", 0),
                      tm["status"]["stage"],
                      1,
                  ),
              }
              for tm in conflicts
          ],
      }

      print(json.dumps(report, indent=2))
      ```
    </CodeGroup>
  </Step>
</Steps>

***

## Automating recurring clearance checks

If you run clearance searches regularly (for example, a naming agency evaluating candidates for clients), keep the `POST /v1/trademarks` body in version control and re-execute it from your job scheduler. Diff each run's result set against the previous one to surface only newly filed conflicts -- the `filing_date_gte` filter keeps each poll cheap.

```typescript TypeScript theme={null}
const clearanceQuery = {
  query: "Vyntra",
  strategies: ["exact", "phonetic", "fuzzy"],
  filters: {
    offices: ["uspto", "euipo", "cipo"],
    nice_classes: [9, 42],
    status_stage: ["filed", "examining", "published", "registered", "opposition_period"],
    filing_date: { gte: lastRunIso },
  },
  limit: 100,
};

const fresh = await signa.trademarks.list(clearanceQuery);
console.log(`New conflicts since ${lastRunIso}: ${fresh.data.length}`);
```

<Tip>
  Persist the timestamp of your last successful run. On the next invocation, pass it as `filing_date_gte` so the API only returns marks filed since then.
</Tip>

***

## What's next

<Card title="Opposition Tracking" href="/guides/use-cases/opposition-tracking">
  Monitor TTAB proceedings if a conflict owner files an opposition against your application.
</Card>

<Card title="Competitor Intelligence" href="/guides/use-cases/competitor-intelligence">
  Track competing owners to catch new filings in your space before they publish.
</Card>
