> ## 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.

# M&A Due Diligence

> Evaluate a target company's trademark portfolio during an acquisition. Map the owner hierarchy via GLEIF, enumerate all marks across subsidiaries, check proceedings and litigation risk, assess portfolio health, and build a diligence report.

You are an IP counsel advising on the acquisition of **Helios Consumer Brands Inc.**, a mid-market consumer goods company. Before the deal closes, you need a complete picture of their trademark portfolio -- how many marks they hold, where, in what condition, and what risks exist (pending oppositions, upcoming deadlines, lapsed registrations).

This guide shows how to perform trademark due diligence using the Signa API.

## Prerequisites

* A Signa API key with `trademarks:read` scope
* The target company name or known identifiers (ticker symbol, LEI, owner ID)

***

<Steps>
  <Step title="Identify the target's owner record">
    Search for the target by name, ticker symbol, or LEI (Legal Entity Identifier). The ticker and LEI filters join through Signa's public companies data (SEC + GLEIF).

    <CodeGroup>
      ```bash cURL theme={null}
      # Search by name
      curl "https://api.signa.so/v1/owners?q=Helios+Consumer+Brands&limit=5" \
        -H "Authorization: Bearer $SIGNA_API_KEY"

      # Or search by ticker if publicly traded
      curl "https://api.signa.so/v1/owners?ticker=HLCS&limit=5" \
        -H "Authorization: Bearer $SIGNA_API_KEY"

      # Or search by LEI
      curl "https://api.signa.so/v1/owners?lei=5493001KJTIIGC8Y1R12&limit=5" \
        -H "Authorization: Bearer $SIGNA_API_KEY"
      ```

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

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

      // Try by name first
      const results = await signa.owners.list({ q: "Helios Consumer Brands", limit: 5 });

      // Or by ticker
      // const results = await signa.owners.list({ ticker: "HLCS", limit: 5 });

      const target = results.data[0];
      console.log(`Target: ${target.name} (${target.id})`);
      console.log(`Trademark count: ${target.trademark_count}`);
      ```

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

      headers = {"Authorization": f"Bearer {os.environ['SIGNA_API_KEY']}"}

      resp = requests.get(
          "https://api.signa.so/v1/owners",
          params={"q": "Helios Consumer Brands", "limit": 5},
          headers=headers,
      ).json()

      target = resp["data"][0]
      print(f"Target: {target['name']} ({target['id']})")
      print(f"Trademark count: {target['trademark_count']}")
      ```
    </CodeGroup>

    **Expected output:**

    ```json theme={null}
    {
      "id": "own_helios01",
      "name": "Helios Consumer Brands Inc.",
      "canonical_name": "HELIOS CONSUMER BRANDS INC",
      "country_code": "US",
      "entity_type": "corporation",
      "trademark_count": 234
    }
    ```
  </Step>

  <Step title="Map the corporate hierarchy via GLEIF">
    Acquisition targets often hold trademarks through subsidiaries. Use the GLEIF corporate relationship data to identify the full ownership tree.

    <CodeGroup>
      ```bash cURL theme={null}
      # Get the target's full profile including public company data
      curl https://api.signa.so/v1/owners/own_helios01 \
        -H "Authorization: Bearer $SIGNA_API_KEY"

      # Get corporate relationships (parent/child companies)
      curl https://api.signa.so/v1/owners/own_helios01/related \
        -H "Authorization: Bearer $SIGNA_API_KEY"
      ```

      ```typescript TypeScript theme={null}
      // Get full owner detail including public company matches
      const ownerDetail = await signa.owners.retrieve("own_helios01");

      if (ownerDetail.companies) {
        for (const pc of ownerDetail.companies) {
          console.log(`Public company: ${pc.legal_name} (${pc.source}: ${pc.source_id})`);
          if (pc.ticker) console.log(`  Ticker: ${pc.ticker} (${pc.exchange})`);
        }
      }

      // Get corporate hierarchy
      const related = await signa.owners.related("own_helios01");

      console.log(`\nCorporate relationships: ${related.data.length}`);
      for (const rel of related.data) {
        console.log(
          `  ${rel.direction === "child" ? "Subsidiary" : "Parent"}: ${rel.name} (${rel.country_code})`,
        );
        console.log(`    Relationship: ${rel.relationship_type}`);
        console.log(`    Ownership: ${rel.ownership_pct ? rel.ownership_pct + "%" : "unknown"}`);
        console.log(`    Owner ID: ${rel.related_owner_id}`);
      }
      ```

      ```python Python theme={null}
      owner = requests.get(
          "https://api.signa.so/v1/owners/own_helios01",
          headers=headers,
      ).json()

      if owner.get("companies"):
          for pc in owner["companies"]:
              print(f"Public company: {pc['legal_name']} ({pc['source']}: {pc['source_id']})")

      related = requests.get(
          "https://api.signa.so/v1/owners/own_helios01/related",
          headers=headers,
      ).json()

      print(f"\nCorporate relationships: {len(related['data'])}")
      for rel in related["data"]:
          direction = "Subsidiary" if rel["direction"] == "child" else "Parent"
          print(f"  {direction}: {rel['name']} ({rel['country_code']})")
          print(f"    Relationship: {rel['relationship_type']}")
      ```
    </CodeGroup>

    **Expected output:**

    ```json theme={null}
    {
      "object": "list",
      "data": [
        {
          "related_owner_id": "own_hel_eu01",
          "name": "Helios Brands Europe GmbH",
          "country_code": "DE",
          "relationship_type": "IS_DIRECTLY_CONSOLIDATED_BY",
          "direction": "child",
          "ownership_pct": 100.0,
          "period_start": "2018-03-01",
          "source": "gleif_level2"
        },
        {
          "related_owner_id": "own_hel_asia01",
          "name": "Helios Asia Pacific Pte Ltd",
          "country_code": "SG",
          "relationship_type": "IS_DIRECTLY_CONSOLIDATED_BY",
          "direction": "child",
          "ownership_pct": 100.0,
          "source": "gleif_level2"
        }
      ]
    }
    ```

    <Note>
      GLEIF relationships use standardized vocabulary. `IS_DIRECTLY_CONSOLIDATED_BY` means the child entity is directly owned by the parent. Use `direction` to determine which side of the relationship the target sits on.
    </Note>
  </Step>

  <Step title="Enumerate all marks across the corporate family">
    Collect trademarks from the target and all subsidiaries. This gives you the full scope of what is being acquired.

    <CodeGroup>
      ```bash cURL theme={null}
      # Get marks from the parent
      curl "https://api.signa.so/v1/owners/own_helios01/trademarks?limit=100&sort=-filing_date" \
        -H "Authorization: Bearer $SIGNA_API_KEY"

      # Get marks from each subsidiary
      curl "https://api.signa.so/v1/owners/own_hel_eu01/trademarks?limit=100&sort=-filing_date" \
        -H "Authorization: Bearer $SIGNA_API_KEY"
      ```

      ```typescript TypeScript theme={null}
      // Collect all owner IDs (parent + subsidiaries)
      const familyOwnerIds = [
        "own_helios01",
        ...related.data
          .filter((r) => r.direction === "child" && r.related_owner_id)
          .map((r) => r.related_owner_id),
      ];

      console.log(`Corporate family: ${familyOwnerIds.length} entities`);

      // Enumerate marks across the family
      let totalMarks = 0;
      const allMarks: any[] = [];

      for (const ownerId of familyOwnerIds) {
        let cursor: string | null = null;
        do {
          const page = await signa.owners.trademarks(ownerId, {
            limit: 100,
            sort: "-filing_date",
            cursor,
          });
          allMarks.push(...page.data);
          totalMarks += page.data.length;
          cursor = page.has_more ? page.pagination.cursor : null;
        } while (cursor);
      }

      console.log(`Total marks across family: ${totalMarks}`);
      ```

      ```python Python theme={null}
      family_ids = ["own_helios01"] + [
          r["related_owner_id"]
          for r in related["data"]
          if r["direction"] == "child" and r.get("related_owner_id")
      ]

      all_marks = []
      for owner_id in family_ids:
          cursor = None
          while True:
              params = {"limit": 100, "sort": "-filing_date"}
              if cursor:
                  params["cursor"] = cursor
              page = requests.get(
                  f"https://api.signa.so/v1/owners/{owner_id}/trademarks",
                  params=params,
                  headers=headers,
              ).json()
              all_marks.extend(page["data"])
              if not page["has_more"]:
                  break
              cursor = page["pagination"]["cursor"]

      print(f"Total marks across family: {len(all_marks)}")
      ```
    </CodeGroup>
  </Step>

  <Step title="Assess portfolio health">
    Analyze the collected marks to build a health scorecard: status distribution, jurisdiction coverage, upcoming deadlines, and risk indicators.

    <CodeGroup>
      ```typescript TypeScript theme={null}
      // Status distribution
      const statusDist: Record<string, number> = {};
      const jurisdictionDist: Record<string, number> = {};
      const classDist: Record<number, number> = {};

      for (const tm of allMarks) {
        statusDist[tm.status.stage] = (statusDist[tm.status.stage] || 0) + 1;
        jurisdictionDist[tm.jurisdiction_code] = (jurisdictionDist[tm.jurisdiction_code] || 0) + 1;
        for (const c of tm.classifications) {
          classDist[c.nice_class] = (classDist[c.nice_class] || 0) + 1;
        }
      }

      const registered = statusDist["registered"] || 0;
      const abandoned = statusDist["abandoned"] || 0;
      const expired = statusDist["expired"] || 0;
      const pending = (statusDist["filed"] || 0) + (statusDist["examining"] || 0);

      console.log("\n=== Portfolio Health Scorecard ===");
      console.log(`Total marks: ${allMarks.length}`);
      console.log(`Registered: ${registered} (${((registered / allMarks.length) * 100).toFixed(0)}%)`);
      console.log(`Pending: ${pending}`);
      console.log(`Abandoned/Expired: ${abandoned + expired}`);
      console.log(`Jurisdictions: ${Object.keys(jurisdictionDist).length}`);
      console.log(`Nice classes covered: ${Object.keys(classDist).length}`);
      console.log("\nStatus breakdown:", statusDist);
      console.log("Top jurisdictions:", Object.entries(jurisdictionDist).sort((a, b) => b[1] - a[1]).slice(0, 5));
      console.log("Top classes:", Object.entries(classDist).sort((a, b) => b[1] - a[1]).slice(0, 10));
      ```

      ```python Python theme={null}
      from collections import Counter

      status_dist = Counter(tm["status"]["stage"] for tm in all_marks)
      jurisdiction_dist = Counter(tm["jurisdiction_code"] for tm in all_marks)
      class_dist = Counter(c["nice_class"] for tm in all_marks for c in tm["classifications"])

      registered = status_dist.get("registered", 0)
      abandoned = status_dist.get("abandoned", 0)
      expired = status_dist.get("expired", 0)

      print("\n=== Portfolio Health Scorecard ===")
      print(f"Total marks: {len(all_marks)}")
      print(f"Registered: {registered} ({registered / len(all_marks) * 100:.0f}%)")
      print(f"Abandoned/Expired: {abandoned + expired}")
      print(f"Jurisdictions: {len(jurisdiction_dist)}")
      print(f"Nice classes: {len(class_dist)}")
      print(f"Top jurisdictions: {jurisdiction_dist.most_common(5)}")
      print(f"Top classes: {class_dist.most_common(10)}")
      ```
    </CodeGroup>

    **Expected output:**

    ```
    === Portfolio Health Scorecard ===
    Total marks: 312
    Registered: 241 (77%)
    Pending: 38
    Abandoned/Expired: 33
    Jurisdictions: 14
    Nice classes covered: 18

    Status breakdown: { registered: 241, examining: 28, filed: 10, abandoned: 18, expired: 15 }
    Top jurisdictions: [["us", 124], ["eu", 68], ["cn", 34], ["gb", 28], ["de", 22]]
    Top classes: [["3", 89], ["5", 72], ["35", 56], ["21", 45], ["29", 38]]
    ```
  </Step>

  <Step title="Check for active proceedings and litigation risk">
    Identify any pending oppositions, cancellations, or other proceedings that could affect the portfolio's value.

    <CodeGroup>
      ```bash cURL theme={null}
      # Check proceedings where the target is a party (as respondent or opponent)
      curl "https://api.signa.so/v1/proceedings?party_owner_id=own_helios01&limit=50" \
        -H "Authorization: Bearer $SIGNA_API_KEY"
      ```

      ```typescript TypeScript theme={null}
      // Check proceedings for each entity in the family
      const allProceedings: any[] = [];

      for (const ownerId of familyOwnerIds) {
        const proceedings = await signa.proceedings.list({
          party_owner_id: ownerId,
          limit: 50,
        });
        allProceedings.push(...proceedings.data);
      }

      const pending = allProceedings.filter((p) => p.status === "pending");
      const decided = allProceedings.filter((p) => p.status.startsWith("decided"));

      console.log(`\n=== Proceedings ===`);
      console.log(`Total: ${allProceedings.length}`);
      console.log(`Pending (active risk): ${pending.length}`);
      console.log(`Decided: ${decided.length}`);

      for (const p of pending) {
        console.log(`\n  [PENDING] ${p.proceeding_type} - ${p.proceeding_number}`);
        console.log(`  Filed: ${p.filed_date}`);
        console.log(`  Contested classes: ${p.contested_classes.join(", ")}`);
        for (const party of p.parties) {
          console.log(`    ${party.role}: ${party.name}`);
        }
      }
      ```

      ```python Python theme={null}
      all_proceedings = []
      for owner_id in family_ids:
          procs = requests.get(
              "https://api.signa.so/v1/proceedings",
              params={"party_owner_id": owner_id, "limit": 50},
              headers=headers,
          ).json()
          all_proceedings.extend(procs["data"])

      pending = [p for p in all_proceedings if p["status"] == "pending"]
      print(f"\nTotal proceedings: {len(all_proceedings)}")
      print(f"Pending (active risk): {len(pending)}")

      for p in pending:
          print(f"\n  [{p['proceeding_type']}] {p['proceeding_number']} - Filed {p['filed_date']}")
          for party in p["parties"]:
              print(f"    {party['role']}: {party['name']}")
      ```
    </CodeGroup>

    **Expected output:**

    ```json theme={null}
    {
      "object": "list",
      "data": [
        {
          "id": "prc_hel001",
          "proceeding_type": "opposition",
          "proceeding_number": "91278456",
          "status": "pending",
          "filed_date": "2026-01-10",
          "parties": [
            { "owner_id": "own_other99", "name": "GreenGlow Naturals LLC", "role": "opponent" },
            { "owner_id": "own_helios01", "name": "Helios Consumer Brands Inc.", "role": "respondent" }
          ],
          "contested_classes": [3, 5]
        }
      ]
    }
    ```

    <Note>
      Pending proceedings are a material risk factor in M\&A. An ongoing opposition could result in loss of rights to a key brand. Make sure to flag these for the deal team and factor potential outcomes into the valuation.
    </Note>
  </Step>

  <Step title="Generate a diligence summary">
    Compile all findings into a structured report suitable for the deal team.

    <CodeGroup>
      ```typescript TypeScript theme={null}
      const diligenceReport = {
        target: {
          name: ownerDetail.name,
          ownerId: ownerDetail.id,
          country: ownerDetail.country_code,
          publicCompanies: ownerDetail.companies ?? [],
        },
        corporateFamily: {
          entityCount: familyOwnerIds.length,
          subsidiaries: related.data
            .filter((r) => r.direction === "child")
            .map((r) => ({
              name: r.name,
              country: r.country_code,
              ownerId: r.related_owner_id,
              ownershipPct: r.ownership_pct,
            })),
        },
        portfolio: {
          totalMarks: allMarks.length,
          registered,
          pending,
          abandonedOrExpired: abandoned + expired,
          registrationRate: registered / allMarks.length,
          jurisdictions: Object.keys(jurisdictionDist).length,
          niceClasses: Object.keys(classDist).length,
          statusBreakdown: statusDist,
          topJurisdictions: Object.entries(jurisdictionDist)
            .sort((a, b) => b[1] - a[1])
            .slice(0, 10),
          topClasses: Object.entries(classDist)
            .sort((a, b) => b[1] - a[1])
            .slice(0, 10),
        },
        proceedings: {
          total: allProceedings.length,
          pending: pending.length,
          pendingDetails: pending.map((p) => ({
            type: p.proceeding_type,
            number: p.proceeding_number,
            filedDate: p.filed_date,
            contestedClasses: p.contested_classes,
            opponent: p.parties.find((party: any) => party.role === "opponent")?.name,
          })),
        },
        riskAssessment: {
          overallRisk: pending.length > 3 ? "HIGH" : pending.length > 0 ? "MEDIUM" : "LOW",
          flags: [
            ...(pending.length > 0 ? [`${pending.length} pending proceedings`] : []),
            ...(abandoned + expired > allMarks.length * 0.15
              ? ["High abandonment/expiry rate (>15%)"]
              : []),
          ],
        },
        generatedAt: new Date().toISOString(),
      };

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

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

      report = {
          "target": {
              "name": owner["name"],
              "owner_id": owner["id"],
              "country": owner["country_code"],
          },
          "corporate_family": {
              "entity_count": len(family_ids),
          },
          "portfolio": {
              "trademark_count": len(all_marks),
              "registered": registered,
              "abandoned_or_expired": abandoned + expired,
              "jurisdictions": len(jurisdiction_dist),
              "nice_classes": len(class_dist),
          },
          "proceedings": {
              "total": len(all_proceedings),
              "pending": len(pending),
          },
          "risk_assessment": {
              "overall_risk": "HIGH" if len(pending) > 3 else "MEDIUM" if pending else "LOW",
          },
          "generated_at": datetime.now().isoformat(),
      }

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

***

## Key risk indicators to flag

| Risk Factor                                | How to detect                                                          | Severity |
| ------------------------------------------ | ---------------------------------------------------------------------- | -------- |
| Pending oppositions/cancellations          | `GET /v1/proceedings?party_owner_id=...&status=pending`                | High     |
| High abandonment rate (>15%)               | Owner stats `abandonment_rate`                                         | Medium   |
| Marks approaching expiry without renewal   | `deadlines[]` on `GET /v1/trademarks/{id}` across the target portfolio | High     |
| Thin jurisdiction coverage                 | Owner stats `jurisdiction_count` vs business footprint                 | Medium   |
| No Madrid filings for international brands | Filter `filing_route=direct_national` only                             | Low      |
| Missing use declarations (US)              | Deadline type `declaration_of_use` past window                         | High     |

***

## What's next

<Card title="Ownership Transfer" href="/guides/use-cases/ownership-transfer">
  After the deal closes, plan and execute the trademark ownership transfer.
</Card>

<Card title="Class Coverage Audits" href="/guides/use-cases/class-coverage-audits">
  Identify gaps in the acquired portfolio's Nice class coverage.
</Card>
