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

# Reconcile

> Diff your trademark records against Signa's register data

## Overview

Compare the trademark records you already hold against Signa's register data and get a field-by-field diff back — nothing is stored.

Records drift from the register over time: statuses change, owners change, registration numbers get assigned, and renewal dates move. Send the fields you have and Signa tells you, per record and per field, exactly where you still match the register and where you've fallen out of sync. Use it to surface exceptions, run scheduled drift checks, or audit a book of matters during onboarding.

Records that aren't found — or that match more than one register entry — come back as per-item outcomes in the response, never a request-level error.

## Request Body

<ParamField body="items" type="object[]" required>
  Records to reconcile, max 100 items. Results are returned in the same order, with one `reconciliation` per input item.

  <Expandable title="Item object">
    <ParamField body="office" type="string" required>
      Trademark office code, e.g. `uspto`, `euipo`, or `cipo`. Values are normalized to lowercase.
    </ParamField>

    <ParamField body="application_number" type="string">
      Office-native application number. Provide at least one of `application_number` or `registration_number`.
    </ParamField>

    <ParamField body="registration_number" type="string">
      Office-native registration number. Provide at least one of `application_number` or `registration_number`.
    </ParamField>

    <ParamField body="your_fields" type="object" required>
      Fields from your system to compare. Must include at least one key and rejects unknown keys.

      <Expandable title="your_fields">
        <ParamField body="status" type="string">Caller status value. Primary statuses compare against `status_primary`; stage statuses compare against `status_stage`; unknown values are reported as mismatches.</ParamField>
        <ParamField body="owner_name" type="string">Owner name from your system. Compared with normalized legal suffix, punctuation, case, and diacritic folding.</ParamField>
        <ParamField body="mark_text" type="string">Mark text from your system. Compared case-insensitively with collapsed whitespace.</ParamField>
        <ParamField body="filing_date" type="string">Filing date as `YYYY-MM-DD`.</ParamField>
        <ParamField body="registration_date" type="string">Registration date as `YYYY-MM-DD`.</ParamField>
        <ParamField body="expiry_date" type="string">Expiry date as `YYYY-MM-DD`.</ParamField>
        <ParamField body="renewal_due_date" type="string">Renewal due date as `YYYY-MM-DD`.</ParamField>
        <ParamField body="registration_number" type="string">Registration number to compare against the register value.</ParamField>
        <ParamField body="nice_classes" type="integer[]">Nice class numbers. Compared as a set.</ParamField>
      </Expandable>
    </ParamField>
  </Expandable>
</ParamField>

## Response

A standard list response with `data: Reconciliation[]`. Pagination is not used; `data[i]` corresponds to `items[i]`.

<ResponseField name="object" type="string">Always `list`.</ResponseField>

<ResponseField name="data" type="object[]">
  <Expandable title="Reconciliation">
    <ResponseField name="object" type="string">Always `reconciliation`.</ResponseField>
    <ResponseField name="office" type="string">Office used for lookup.</ResponseField>
    <ResponseField name="application_number" type="string | null">Application number supplied on the input item, or `null`.</ResponseField>
    <ResponseField name="registration_number" type="string | null">Registration number supplied on the input item, or `null`.</ResponseField>
    <ResponseField name="result" type="string">One of `match`, `mismatch`, `not_found`, or `ambiguous`.</ResponseField>
    <ResponseField name="trademark_id" type="string | null">Signa trademark ID (`tm_*`) when exactly one register record resolved.</ResponseField>
    <ResponseField name="register_last_updated_at" type="string | null">Register record update timestamp as ISO 8601, or `null` when unresolved.</ResponseField>

    <ResponseField name="fields" type="object[]">
      <Expandable title="ReconcileFieldDiff">
        <ResponseField name="field" type="string">Compared field: `status`, `owner_name`, `mark_text`, `filing_date`, `registration_date`, `expiry_date`, `renewal_due_date`, `registration_number`, or `nice_classes`.</ResponseField>
        <ResponseField name="your_value" type="string | integer[]">Value supplied in `your_fields`.</ResponseField>
        <ResponseField name="register_value" type="string | integer[] | null">Normalized register value compared against your value.</ResponseField>
        <ResponseField name="match" type="boolean">Whether the field matched after field-specific normalization.</ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="mismatch_count" type="integer">Number of `fields[]` entries where `match` is `false`.</ResponseField>
    <ResponseField name="match_count" type="integer">Present only for ambiguous identifier lookups; capped at `2+`.</ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="has_more" type="boolean">Always `false`.</ResponseField>
<ResponseField name="pagination" type="object">Always `{ "cursor": null }`.</ResponseField>
<ResponseField name="request_id" type="string">Unique request identifier for support and debugging.</ResponseField>

`not_found` is soft: the request still returns HTTP `200`, with `result: "not_found"` for that item and an empty `fields` array. `ambiguous` means the identifier lookup resolved to more than one register record, such as an `(office, application_number)` pair that is not unique; Signa does not silently choose one.

<ResponseExample>
  ```json theme={null}
  {
    "object": "list",
    "data": [
      {
        "object": "reconciliation",
        "office": "uspto",
        "application_number": "88123456",
        "registration_number": null,
        "result": "mismatch",
        "trademark_id": "tm_018f2f1b-2f15-7d4b-9e3c-b8b5a5c9b012",
        "register_last_updated_at": "2026-07-05T12:00:00.000Z",
        "fields": [
          {
            "field": "status",
            "your_value": "active",
            "register_value": "active",
            "match": true
          },
          {
            "field": "owner_name",
            "your_value": "Nike, Inc.",
            "register_value": "Nike Innovate C.V.",
            "match": false
          }
        ],
        "mismatch_count": 1
      }
    ],
    "has_more": false,
    "pagination": { "cursor": null },
    "request_id": "req_bT9kM3nP"
  }
  ```
</ResponseExample>

## Code Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.signa.so/v1/reconcile" \
    -H "Authorization: Bearer sig_xxxxxxxxxxxx" \
    -H "Content-Type: application/json" \
    -d '{
      "items": [
        {
          "office": "uspto",
          "application_number": "88123456",
          "your_fields": {
            "status": "active",
            "owner_name": "Nike, Inc."
          }
        }
      ]
    }'
  ```

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

  const signa = new Signa({ api_key: "sig_xxxxxxxxxxxx" });

  const results = await signa.reconcile.run({
    items: [{ office: 'uspto', application_number: '88123456', your_fields: { status: 'active', owner_name: 'Nike, Inc.' } }]
  });

  for (const result of results.data) {
    console.log(result.result, result.mismatch_count);
  }
  ```

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

  resp = requests.post(
      "https://api.signa.so/v1/reconcile",
      headers={
          "Authorization": "Bearer sig_xxxxxxxxxxxx",
          "Content-Type": "application/json",
      },
      json={
          "items": [
              {
                  "office": "uspto",
                  "application_number": "88123456",
                  "your_fields": {
                      "status": "active",
                      "owner_name": "Nike, Inc.",
                  },
              }
          ]
      },
  )
  for result in resp.json()["data"]:
      print(result["result"], result["mismatch_count"])
  ```
</CodeGroup>

## Errors

| Status | Type               | Description                                                                                         |
| ------ | ------------------ | --------------------------------------------------------------------------------------------------- |
| 400    | `validation_error` | Malformed body, missing identifier, empty `your_fields`, invalid date format, or unknown body field |
| 401    | `unauthorized`     | Missing or invalid API key                                                                          |
| 403    | `forbidden`        | API key missing the `trademarks:read` scope                                                         |
| 422    | `batch_too_large`  | More than 100 items. The error carries `item_count` and `item_count_limit`                          |
| 429    | `rate_limited`     | Too many requests                                                                                   |

## Related Endpoints

* [Batch Get Trademarks](/api-reference/trademarks/batch-trademarks) -- hydrate known IDs or office-native identifiers
* [List Trademarks](/api-reference/trademarks/list-trademarks) -- search the normalized register
