> ## 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 Ownership Transfer

> Post-acquisition workflow for trademark ownership transfers. Map the acquired portfolio, assess each mark's transfer readiness, plan the recording sequence, and track progress through completion.

You have just closed the acquisition of **Helios Consumer Brands Inc.** (see [M\&A Due Diligence](/guides/use-cases/mna-due-diligence)). Now you need to execute the ownership transfer -- recording the assignment of 312 trademarks across 14 jurisdictions from the old owner to your corporate entity. This is a multi-month project with office-specific requirements and strict sequencing.

This guide shows how to use the Signa API to plan, track, and verify the transfer.

## Prerequisites

* A Signa API key with `trademarks:read` scope
* Completed due diligence with a known list of marks to transfer
* The acquiring entity's owner ID in Signa

***

<Steps>
  <Step title="Collect every acquired mark ID">
    Paginate through each seller owner (and any subsidiary owners that came with the deal) to build the master list of marks you need to transfer. Persist this list -- you'll reuse it for every downstream step.

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

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

      const sellerOwnerIds = ["own_helios01", "own_hel_eu01", "own_hel_asia01"];
      const allMarkIds: string[] = [];

      for (const ownerId of sellerOwnerIds) {
        let cursor: string | null = null;
        do {
          const page = await signa.owners.trademarks(ownerId, { limit: 100, cursor });
          allMarkIds.push(...page.data.map((tm) => tm.id));
          cursor = page.has_more ? page.pagination.cursor : null;
        } while (cursor);
      }

      console.log(`Total marks to transfer: ${allMarkIds.length}`);
      ```

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

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

      seller_ids = ["own_helios01", "own_hel_eu01", "own_hel_asia01"]
      all_mark_ids = []

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

      print(f"Total marks to transfer: {len(all_mark_ids)}")
      ```
    </CodeGroup>

    <Tip>
      Store `allMarkIds`, the deal reference, and key dates (closing, target completion) in your own deal tracker or spreadsheet. Every step below reads from this list.
    </Tip>
  </Step>

  <Step title="Assess transfer readiness for each mark">
    Not every mark can be transferred immediately. Check for blocking conditions: pending proceedings, marks in opposition, grace period deadlines, and marks held by subsidiaries that may need separate assignment documents.

    <CodeGroup>
      ```typescript TypeScript theme={null}
      interface TransferAssessment {
        trademarkId: string;
        markText: string;
        office: string;
        jurisdiction: string;
        status: string;
        currentOwner: string;
        blockers: string[];
        urgentDeadlines: any[];
        readiness: "ready" | "blocked" | "needs_attention";
      }

      const assessments: TransferAssessment[] = [];

      // Fetch full details for all marks
      for (let i = 0; i < allMarkIds.length; i += 100) {
        const batch = allMarkIds.slice(i, i + 100);
        const details = await signa.trademarks.batch({ ids: batch });

        for (const tm of details.data) {
          const blockers: string[] = [];

          // Check status blockers
          if (["abandoned", "cancelled", "expired", "refused"].includes(tm.status.stage)) {
            blockers.push(`Status is ${tm.status.stage} - cannot transfer`);
          }

          // Check for pending proceedings
          if (tm.proceedings_count > 0) {
            const procs = await signa.trademarks.proceedings(tm.id, { limit: 5 });
            const pending = procs.data.filter((p) => p.status === "pending");
            if (pending.length > 0) {
              blockers.push(`${pending.length} pending proceeding(s)`);
            }
          }

          // Check for imminent deadlines
          const urgentDeadlines = tm.deadlines.filter((d) => {
            const daysUntil = Math.ceil(
              (new Date(d.due_date).getTime() - Date.now()) / (1000 * 60 * 60 * 24),
            );
            return daysUntil <= 90 && daysUntil > 0;
          });

          if (urgentDeadlines.length > 0) {
            blockers.push(`${urgentDeadlines.length} deadline(s) within 90 days`);
          }

          assessments.push({
            trademarkId: tm.id,
            markText: tm.mark_text,
            office: tm.office_code,
            jurisdiction: tm.jurisdiction_code,
            status: tm.status.stage,
            currentOwner: tm.owners[0]?.name || "unknown",
            blockers,
            urgentDeadlines,
            readiness:
              blockers.length === 0
                ? "ready"
                : blockers.some((b) => b.includes("cannot transfer"))
                  ? "blocked"
                  : "needs_attention",
          });
        }
      }

      // Summary
      const ready = assessments.filter((a) => a.readiness === "ready");
      const blocked = assessments.filter((a) => a.readiness === "blocked");
      const needsAttention = assessments.filter((a) => a.readiness === "needs_attention");

      console.log("\n=== Transfer Readiness ===");
      console.log(`Ready to transfer: ${ready.length}`);
      console.log(`Needs attention: ${needsAttention.length}`);
      console.log(`Blocked: ${blocked.length}`);

      if (needsAttention.length > 0) {
        console.log("\n--- Marks needing attention ---");
        for (const a of needsAttention) {
          console.log(`  ${a.markText} (${a.office} / ${a.jurisdiction})`);
          for (const b of a.blockers) {
            console.log(`    - ${b}`);
          }
        }
      }
      ```

      ```python Python theme={null}
      assessments = []

      for i in range(0, len(all_mark_ids), 100):
          batch = all_mark_ids[i : i + 100]
          details = requests.post(
              "https://api.signa.so/v1/trademarks/batch",
              headers={**headers, "Idempotency-Key": f"assess-batch-{i // 100}"},
              json={"ids": batch},
          ).json()

          for tm in details["data"]:
              blockers = []

              if tm["status"]["stage"] in ["abandoned", "cancelled", "expired", "refused"]:
                  blockers.append(f"Status is {tm['status']['stage']}")

              if tm.get("proceedings_count", 0) > 0:
                  blockers.append("Has proceedings - check status")

              urgent = [d for d in tm.get("deadlines", []) if 0 < d.get("days_until_due", 999) <= 90]
              if urgent:
                  blockers.append(f"{len(urgent)} deadline(s) within 90 days")

              readiness = "ready" if not blockers else "blocked" if any("cannot" in b for b in blockers) else "needs_attention"
              assessments.append({
                  "id": tm["id"],
                  "mark_text": tm["mark_text"],
                  "office": tm["office_code"],
                  "blockers": blockers,
                  "readiness": readiness,
              })

      ready = [a for a in assessments if a["readiness"] == "ready"]
      blocked = [a for a in assessments if a["readiness"] == "blocked"]
      attention = [a for a in assessments if a["readiness"] == "needs_attention"]

      print(f"Ready: {len(ready)}, Needs attention: {len(attention)}, Blocked: {len(blocked)}")
      ```
    </CodeGroup>

    **Expected output:**

    ```
    === Transfer Readiness ===
    Ready to transfer: 278
    Needs attention: 19
    Blocked: 15

    --- Marks needing attention ---
      HELIOS GLOW (euipo / EU)
        - 1 pending proceeding(s)
        - 1 deadline(s) within 90 days
      HELIOS PURE (uspto / US)
        - 1 deadline(s) within 90 days
    ```
  </Step>

  <Step title="Plan the recording sequence by jurisdiction">
    Each office has different requirements and timelines for recording assignments. Group marks by office and plan the sequence.

    <CodeGroup>
      ```typescript TypeScript theme={null}
      // Group ready marks by office
      const byOffice: Record<string, TransferAssessment[]> = {};
      for (const a of assessments.filter((a) => a.readiness === "ready")) {
        if (!byOffice[a.office]) byOffice[a.office] = [];
        byOffice[a.office].push(a);
      }

      console.log("\n=== Recording Plan ===");
      for (const [office, marks] of Object.entries(byOffice).sort((a, b) => b[1].length - a[1].length)) {
        console.log(`\n${office.toUpperCase()} (${marks.length} marks)`);

        // Count unique current owners (some may be subsidiaries)
        const owners = [...new Set(marks.map((m) => m.currentOwner))];
        console.log(`  Current owners: ${owners.join(", ")}`);
        console.log(`  Assignment documents needed: ${owners.length}`);
      }
      ```

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

      by_office = defaultdict(list)
      for a in assessments:
          if a["readiness"] == "ready":
              by_office[a["office"]].append(a)

      print("\n=== Recording Plan ===")
      for office, marks in sorted(by_office.items(), key=lambda x: -len(x[1])):
          print(f"\n{office.upper()} ({len(marks)} marks)")
      ```
    </CodeGroup>

    **Office-specific transfer requirements:**

    | Office        | Recording Method                      | Typical Timeline | Notes                                                   |
    | ------------- | ------------------------------------- | ---------------- | ------------------------------------------------------- |
    | USPTO         | File assignment via ETAS (electronic) | 2-4 weeks        | One document can cover multiple marks                   |
    | EUIPO         | Record transfer via eService          | 4-8 weeks        | Each mark needs separate request                        |
    | WIPO (Madrid) | File MM5 form via Madrid eRenewal     | 6-12 weeks       | Recorded at IB, then notified to each designated office |
    | CIPO          | File via CIPO Online                  | 4-6 weeks        |                                                         |
    | UKIPO         | File TM16 form                        | 2-4 weeks        |                                                         |
    | DPMA          | File via DPMAregister                 | 4-8 weeks        | German language required                                |
  </Step>

  <Step title="Monitor transfer progress">
    Re-run a batch fetch over `allMarkIds` weekly and count how many marks now carry the acquiring entity as their recorded owner. Every `GET /v1/trademarks/{id}` response includes the current `owners`, so no change-stream is required -- the batch endpoint comfortably handles 100 IDs per call.

    <CodeGroup>
      ```typescript TypeScript theme={null}
      const buyerOwnerId = "own_apex01";
      let transfersRecorded = 0;

      for (let i = 0; i < allMarkIds.length; i += 100) {
        const page = await signa.trademarks.batch({ ids: allMarkIds.slice(i, i + 100) });
        for (const entry of page.data) {
          if (entry.status !== "success") continue;
          if (entry.data.owners.some((o: any) => o.id === buyerOwnerId)) {
            transfersRecorded++;
          }
        }
      }

      const totalToTransfer = allMarkIds.length;
      const readyCount = ready.length;

      console.log("\n=== Transfer Progress ===");
      console.log(`Total marks: ${totalToTransfer}`);
      console.log(`Ready to transfer: ${readyCount}`);
      console.log(`Transfers detected: ${transfersRecorded}`);
      console.log(`Progress: ${((transfersRecorded / readyCount) * 100).toFixed(0)}%`);
      ```

      ```python Python theme={null}
      buyer_owner_id = "own_apex01"
      transfers_detected = 0

      for i in range(0, len(all_mark_ids), 100):
          page = requests.post(
              "https://api.signa.so/v1/trademarks/batch",
              headers={**headers, "Content-Type": "application/json", "Idempotency-Key": f"transfer-progress-{i // 100}"},
              json={"ids": all_mark_ids[i : i + 100]},
          ).json()

          for entry in page["data"]:
              if entry["status"] != "success":
                  continue
              if any(o["id"] == buyer_owner_id for o in entry["data"]["owners"]):
                  transfers_detected += 1

      total = len(all_mark_ids)
      ready_count = len(ready)

      print("\n=== Transfer Progress ===")
      print(f"Total marks: {total}")
      print(f"Ready to transfer: {ready_count}")
      print(f"Transfers detected: {transfers_detected}")
      print(f"Progress: {transfers_detected / ready_count * 100:.0f}%")
      ```
    </CodeGroup>

    <Tip>
      Run this progress check weekly and share the results with the deal team. Pair it with the [Trademark Changes](/api-reference/trademarks/trademark-changes) endpoint on individual marks to pinpoint exactly when an office recorded the assignment.
    </Tip>
  </Step>

  <Step title="Verify completed transfers">
    Once a transfer is recorded, verify that the mark's owner record has been updated correctly by pulling the trademark detail.

    <CodeGroup>
      ```bash cURL theme={null}
      curl https://api.signa.so/v1/trademarks/tm_hel001 \
        -H "Authorization: Bearer $SIGNA_API_KEY"
      ```

      ```typescript TypeScript theme={null}
      // Spot-check a few transferred marks
      const sampleIds = allMarkIds.slice(0, 5);
      const samples = await signa.trademarks.batch({ ids: sampleIds });

      for (const tm of samples.data) {
        const currentOwner = tm.owners[0];
        const isTransferred = currentOwner?.id === "own_apex01";

        console.log(`${tm.mark_text} (${tm.office_code})`);
        console.log(`  Current owner: ${currentOwner?.name}`);
        console.log(`  Transfer status: ${isTransferred ? "COMPLETE" : "PENDING"}`);
      }
      ```

      ```python Python theme={null}
      sample_ids = all_mark_ids[:5]
      samples = requests.post(
          "https://api.signa.so/v1/trademarks/batch",
          headers={**headers, "Idempotency-Key": "verify-transfers"},
          json={"ids": sample_ids},
      ).json()

      for tm in samples["data"]:
          owner = tm["owners"][0] if tm["owners"] else None
          transferred = owner and owner["id"] == "own_apex01"
          print(f"{tm['mark_text']} ({tm['office_code']}): {'COMPLETE' if transferred else 'PENDING'}")
      ```
    </CodeGroup>

    You can also review the change history to see exactly when the ownership changed:

    <CodeGroup>
      ```bash cURL theme={null}
      curl "https://api.signa.so/v1/trademarks/tm_hel001/changes?limit=5&sort=-created_at" \
        -H "Authorization: Bearer $SIGNA_API_KEY"
      ```

      ```typescript TypeScript theme={null}
      const changes = await signa.trademarks.changes("tm_hel001", {
        limit: 5,
        sort: "-created_at",
      });

      for (const change of changes.data) {
        if (change.changed_fields.some((f) => f.includes("owner"))) {
          console.log(`  Ownership change at version ${change.version}`);
          console.log(`  Source data date: ${change.source_data_date}`);
          console.log(`  Changed fields: ${change.changed_fields.join(", ")}`);
        }
      }
      ```

      ```python Python theme={null}
      changes = requests.get(
          "https://api.signa.so/v1/trademarks/tm_hel001/changes",
          params={"limit": 5, "sort": "-created_at"},
          headers={"Authorization": f"Bearer {os.environ['SIGNA_API_KEY']}"},
      ).json()

      for change in changes["data"]:
          print(f"Version {change['version']}: {', '.join(change['changed_fields'])}")
          print(f"  Date: {change['source_data_date']}")
      ```
    </CodeGroup>
  </Step>
</Steps>

***

## Transfer timeline tracker

Build a summary view for your deal team:

| Phase                         | Status      | Count                     | Target Date |
| ----------------------------- | ----------- | ------------------------- | ----------- |
| Due diligence complete        | Done        | 312 marks inventoried     | 2026-03-01  |
| Assignment documents executed | Done        | 4 documents (3 entities)  | 2026-03-15  |
| USPTO recordings filed        | In progress | 124 marks                 | 2026-04-30  |
| EUIPO recordings filed        | In progress | 68 marks                  | 2026-05-31  |
| WIPO/Madrid recordings filed  | Pending     | 42 marks                  | 2026-06-30  |
| Other offices filed           | Pending     | 44 marks                  | 2026-07-31  |
| All recordings confirmed      | Pending     | 278 marks (excl. blocked) | 2026-09-30  |

***

## What's next

<Card title="Renewal Management" href="/guides/use-cases/renewal-management">
  Ensure no deadlines are missed during the transfer process.
</Card>

<Card title="Class Coverage Audits" href="/guides/use-cases/class-coverage-audits">
  Audit the combined portfolio for coverage gaps after the acquisition.
</Card>
