Search Citations
curl --request GET \
--url https://api.signa.so/v1/citations \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.signa.so/v1/citations"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.signa.so/v1/citations', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.signa.so/v1/citations",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.signa.so/v1/citations"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.signa.so/v1/citations")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.signa.so/v1/citations")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"object": "list",
"data": [
{
"id": "cit_0198c2f1-7e2a-7b34-9c11-3d5f8a2b4c6e",
"object": "citation",
"office_code": "US",
"application_ref": "98123456",
"trademark": {
"id": "tm_019f34d6-2000-7777-8888-000000000001",
"mark_text": "ACME BREW",
"office_code": "US",
"application_number": "98123456",
"registration_number": null,
"status_primary": "pending"
},
"cited_ref": "5567890",
"cited_ref_type": "registration",
"cited_trademark": {
"id": "tm_8kLm2nPq",
"mark_text": "ACME",
"office_code": "US",
"application_number": "87999999",
"registration_number": "5567890",
"status_primary": "active"
},
"refusal_type": "2d",
"action_date": "2026-01-15",
"action_stage": "final",
"disposition": "maintained",
"disposition_as_of": "2026-08-30T13:30:00.000Z",
"source_document_id": "med_0198c2f1-7e2a-7b34-9c11-3d5f8a2b4c6e"
}
],
"has_more": true,
"pagination": { "cursor": "eyJ2IjoxLCJ0IjoiY2l0YXRpb25zIn0" },
"request_id": "req_cV2nL8pQ"
}
Citations
Search Citations
Query examiner refusal citations across all marks by office, disposition, stage, and date
GET
/
v1
/
citations
Search Citations
curl --request GET \
--url https://api.signa.so/v1/citations \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.signa.so/v1/citations"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.signa.so/v1/citations', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.signa.so/v1/citations",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.signa.so/v1/citations"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.signa.so/v1/citations")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.signa.so/v1/citations")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"object": "list",
"data": [
{
"id": "cit_0198c2f1-7e2a-7b34-9c11-3d5f8a2b4c6e",
"object": "citation",
"office_code": "US",
"application_ref": "98123456",
"trademark": {
"id": "tm_019f34d6-2000-7777-8888-000000000001",
"mark_text": "ACME BREW",
"office_code": "US",
"application_number": "98123456",
"registration_number": null,
"status_primary": "pending"
},
"cited_ref": "5567890",
"cited_ref_type": "registration",
"cited_trademark": {
"id": "tm_8kLm2nPq",
"mark_text": "ACME",
"office_code": "US",
"application_number": "87999999",
"registration_number": "5567890",
"status_primary": "active"
},
"refusal_type": "2d",
"action_date": "2026-01-15",
"action_stage": "final",
"disposition": "maintained",
"disposition_as_of": "2026-08-30T13:30:00.000Z",
"source_document_id": "med_0198c2f1-7e2a-7b34-9c11-3d5f8a2b4c6e"
}
],
"has_more": true,
"pagination": { "cursor": "eyJ2IjoxLCJ0IjoiY2l0YXRpb25zIn0" },
"request_id": "req_cV2nL8pQ"
}
When To Use This
Use this endpoint when the question spans marks rather than sitting on one record. Each row is one citation occurrence: one prior mark an examiner cited against one application in one office action. The corpus is a record of which marks an office has actually treated as a bar to registration, and what happened next. Typical uses: pull every §2(d) citation an office issued in a date window, find every application a specific registration has been cited against, or resolve an office-printed registration number to the mark behind it. For one mark at a time, use Trademark Citations and Trademark Cited By.Rows are citation occurrences, not applications. One application cited over the same prior mark in both a nonfinal and a final office action produces two rows. To count distinct applications, group by
trademark.id, falling back to application_ref when trademark is null. This endpoint returns no total_count, so a raw row count is both the easiest number to reach for and the easiest to get wrong: it overstates how many applications a mark has actually blocked.Coverage today is USPTO only. Citations are extracted from USPTO office actions and cover §2(d) likelihood-of-confusion refusals. Requests filtered to any other office return an empty list, including offices whose examiners never cite prior marks at all. Check
capabilities.citations on List Offices to see the state of any office programmatically, rather than inferring coverage from an empty response.Freshness
Citations are extracted hourly from stored office actions. Dispositions are recomputed once a day, so a newly extracted citation carriesdisposition: null until the next daily refresh, which can be up to about 24 hours. A disposition can also change on a later run as prosecution continues. disposition_as_of is stamped when the current disposition was first derived or last changed, and deliberately does not move when a daily run re-derives the same value. An unchanged timestamp means the disposition has been stable, not that the refresh stopped running.
Office Coverage And capabilities.citations
List Offices and Retrieve Office carry capabilities.citations, which is the programmatic answer to “should I expect anything here?”.
| Value | Meaning |
|---|---|
available | Live pipeline. Citations are being served for this office today. |
in_progress | A pipeline build is underway. Data is not complete yet. |
not_available | Signa serves no citations for this office. Either the office refuses on relative grounds and there is no pipeline yet, or its regime has not been classified. A gap that may close. |
not_applicable | The office does not refuse on relative grounds ex officio, so it never issues a citation-bearing refusal at all. |
not_applicable covers the opposition-only registries, where earlier-rights conflicts are left to third parties rather than raised by the examiner. The EUIPO (EM), INPI France (FR), the Swiss IPI (CH) and the UKIPO (GB) all work this way, and the DPMA (DE) and the UIBM (IT) are classified the same way. WIPO (WO) is not_applicable for a narrower reason: the International Bureau does formalities only and never examines the mark, so substantive refusals come from the designated national offices under their own codes. An empty citation list for a not_applicable office is not a coverage gap, and it will not become non-empty.
Those codes are illustrative, not a fixed list. capabilities.citations on List Offices is the authoritative, current answer for every office, and it is the one to read programmatically rather than hard-coding office codes from this page.
Query Parameters
All filters are optional and combine with AND. An unfiltered request is allowed and returns the newest citations across the corpus.string
Filter by issuing office, comma-separated (e.g.
US or US,EM). Values are uppercase ST.3 office codes; legacy lowercase codes (e.g. uspto, and eu for EUIPO) are accepted as permanent aliases, and the two forms can be mixed in one list. Up to 100 values. An unrecognized code returns 200 with an empty list rather than an error, so polling for a not-yet-covered office is safe.string
Filter by how the citation resolved, comma-separated. One or more of
citation_issued, maintained, withdrawn, abandoned_after, published. Rows whose disposition has not been computed yet are excluded when this filter is supplied.string
Filter by the stage the citation reached, comma-separated. One or both of
nonfinal, final. final includes citations first raised in a nonfinal action that a later final action maintained.string
Filter by refusal ground, comma-separated.
2d is the only value today, the USPTO §2(d) likelihood-of-confusion ground. This vocabulary is office-scoped rather than canonical across offices.string
Restrict to citations issued against one citing application (
tm_...).string
Restrict to citations naming one prior mark (
tm_...). This matches on the resolved link and additionally on that mark’s own application and registration numbers for unlinked citations from the same office, the same predicate Trademark Cited By uses, so the two views return the same rows.string
Exact cited reference, as an application or registration number. Punctuation is ignored, digits are matched. Requires
offices: references are only unique within an office, so an office-less lookup is rejected with 400. Use this to go from a number an examiner printed to the citations that name it, including citations Signa has not linked to a record.string
Office action date >= (
YYYY-MM-DD).string
Office action date <= (
YYYY-MM-DD).string
default:"-action_date"
-action_date for newest first, action_date for oldest first. No other sort fields. Sort is bound into the pagination cursor, so it cannot be changed mid-walk.integer
default:"20"
Page size (1-100).
string
Opaque cursor from the previous response’s
pagination.cursor.id as the final tiebreaker.
Response
string
Always
list.object[]
Show Citation object
Show Citation object
string
Citation ID (
cit_...).string
Always
citation.string | null
Office that issued the action, uppercase ST.3 (e.g.
US).string
Application number the office action was issued against, as printed by the office.
object | null
Summary of the citing application (
id, mark_text, office_code, application_number, registration_number, status_primary). null when the citation carries no persisted link to a Signa record for that application, which is not the same as the application being absent from the register: resolution runs once, at extraction time.string
The prior mark reference the examiner cited.
string
Whether
cited_ref is a registration or an application number. This label is inferred from how the citing office action worded the reference, and it is occasionally wrong: a serial can be labelled as a registration, or the reverse. Signa matches the number against both namespaces regardless of the label, so a mislabelled reference still resolves. Treat it as a hint, and when cited_trademark is present read that as the authoritative identification of the cited mark.object | null
Summary of the cited prior mark, same fields as
trademark. null means the citation is matched by reference only, with cited_ref as the sole identifier.string
Office-local refusal ground.
2d is the USPTO §2(d) likelihood-of-confusion ground.string | null
ISO date of the office action (
YYYY-MM-DD).string | null
nonfinal or final. This is the stage the citation reached, not provenance about source_document_id. A citation first raised in a nonfinal action reads final once a later dated final action maintained the refusal, so final does not mean the row was extracted from a final action.string | null
How the citation resolved. See the table below.
null while pending the daily refresh.string | null
ISO 8601 timestamp of when the current
disposition was first derived or last changed. It does not advance when a daily run re-derives the same value, so a stale-looking timestamp means the disposition has been stable.string | null
The office action the citation was extracted from (
med_...), retrievable through Trademark Documents on the citing mark. Every citation served today carries one. The field is nullable so a citation derived without a stored source document can be represented. Documents are only addressable under a trademark, so when trademark is null there is no route that resolves this id.boolean
Whether more citations are available.
object
Cursor for the next page.
string
Unique request identifier for support and debugging.
Disposition Values
A citation carries exactly one disposition, derived from the citing application’s prosecution events and from whether the citation reappeared in subsequent office actions. The disposition is one verdict per (application, cited reference) pair. It is computed across that pair’s whole occurrence history and then written onto every occurrence row for the pair. It is not per row, and it is not per date.action_stage does vary from row to row, but it records the stage that occurrence of the citation reached, not the kind of document the row was extracted from: a citation first raised in a nonfinal action is upgraded to final once a later dated final action maintains the refusal, so a final row can still carry a nonfinal source_document_id. disposition is per pair and describes the citation’s fate overall.
So a row with action_stage: nonfinal alongside disposition: maintained is expected, not a data error. It means a different occurrence of this same citation, against the same application, reached a final action. Filter action_stage=final if you want the occurrences that reached final, remembering that those rows include upgraded ones whose source_document_id is a nonfinal action; read disposition from any row of the pair if you want the pair’s outcome.
published and abandoned_after are evaluated against the pair’s earliest office action date rather than against the individual row’s date, which is another reason every row of a pair carries the same answer.
| Value | Meaning |
|---|---|
published | The application published or registered after the citation date. The citation did not stop it. |
maintained | The refusal reached a final office action. The citation held. |
abandoned_after | The application went abandoned after the citation date and was not revived. |
withdrawn | A later citation-bearing office action for the same application dropped this reference, with no publication yet. The examiner backed off. |
citation_issued | No later signal yet. The application is still in prosecution, or its event record does not yet support a stronger label. |
null | Not computed yet. Filled on the daily refresh. |
published, maintained, abandoned_after, withdrawn, citation_issued.
Worked Example: Finding The Marks That Actually Block
A clearance search tells you which registrations look similar. It does not tell you which ones an examiner has ever used to refuse somebody. This endpoint does, and the disposition filter is what separates the two. Ask fordisposition=maintained,abandoned_after:
curl -G "https://api.signa.so/v1/citations" \
-H "Authorization: Bearer $SIGNA_API_KEY" \
--data-urlencode "offices=US" \
--data-urlencode "disposition=maintained,abandoned_after" \
--data-urlencode "action_date_gte=2023-01-01" \
--data-urlencode "limit=100"
maintainedmeans the examiner did not back down. The refusal was carried into a final office action, so the office has committed to the position that this prior mark bars the application. It is the cleanest evidence that a mark is a live obstacle.abandoned_aftermeans the application died after being cited and was never revived. The applicant walked away rather than fight, which is the practical outcome a clearance search is trying to predict, even though the office never ruled.
withdrawnmeans the examiner dropped the citation in a later action. The prior mark was raised and then set aside, so it is weak evidence of blocking, and sometimes evidence of the opposite.publishedmeans the application went on to publish or register anyway. The cited mark did not stop it.citation_issuedmeans prosecution has not produced a signal yet. Including it mixes unresolved cases into a set you are treating as resolved.
curl -G "https://api.signa.so/v1/trademarks/tm_8kLm2nPq/cited-by" \
-H "Authorization: Bearer $SIGNA_API_KEY" \
--data-urlencode "disposition=maintained,abandoned_after" \
--data-urlencode "limit=100"
trademark.id, falling back to application_ref when trademark is null. A registration that blocked a dozen distinct applications in the last three years is an owner whose mark the office reaches for routinely. One with none, despite years on the register and plenty of similar filings around it, is a much softer conflict. Pair it with the unfiltered cited-by set to get a rate rather than a raw number: a mark cited against twenty applications where eighteen citations were withdrawn or published is not the same risk as a mark cited against five where all five stuck.
Two caveats worth building around. Rows with cited_trademark: null are real citations that Signa could not link to a record, so count them; on the per-mark cited-by endpoint they are already matched by reference for you. And abandoned_after is a censored observation, not a ruling: the application stopped, and the citation is one plausible reason among several.
Example Response
{
"object": "list",
"data": [
{
"id": "cit_0198c2f1-7e2a-7b34-9c11-3d5f8a2b4c6e",
"object": "citation",
"office_code": "US",
"application_ref": "98123456",
"trademark": {
"id": "tm_019f34d6-2000-7777-8888-000000000001",
"mark_text": "ACME BREW",
"office_code": "US",
"application_number": "98123456",
"registration_number": null,
"status_primary": "pending"
},
"cited_ref": "5567890",
"cited_ref_type": "registration",
"cited_trademark": {
"id": "tm_8kLm2nPq",
"mark_text": "ACME",
"office_code": "US",
"application_number": "87999999",
"registration_number": "5567890",
"status_primary": "active"
},
"refusal_type": "2d",
"action_date": "2026-01-15",
"action_stage": "final",
"disposition": "maintained",
"disposition_as_of": "2026-08-30T13:30:00.000Z",
"source_document_id": "med_0198c2f1-7e2a-7b34-9c11-3d5f8a2b4c6e"
}
],
"has_more": true,
"pagination": { "cursor": "eyJ2IjoxLCJ0IjoiY2l0YXRpb25zIn0" },
"request_id": "req_cV2nL8pQ"
}
Code Examples
curl -G "https://api.signa.so/v1/citations" \
-H "Authorization: Bearer sig_YOUR_KEY_HERE" \
--data-urlencode "offices=US" \
--data-urlencode "disposition=maintained,abandoned_after" \
--data-urlencode "limit=20"
import { Signa } from "@signa-so/sdk";
const signa = new Signa({ api_key: process.env.SIGNA_API_KEY });
// Comma-separated on the wire; the SDK accepts an array and joins it.
const citations = await signa.citations.list({
offices: "US",
disposition: ["maintained", "abandoned_after"],
limit: 20,
});
for (const citation of citations.data) {
console.log(citation.action_date, citation.cited_ref, citation.disposition);
}
import requests
resp = requests.get(
"https://api.signa.so/v1/citations",
headers={"Authorization": "Bearer sig_YOUR_KEY_HERE"},
params={
"offices": "US",
"disposition": "maintained,abandoned_after",
"limit": 20,
},
)
Resolve An Office-Printed Number
cited_ref plus offices turns a number on an office action into the citations that name it, and into the mark behind it when Signa holds the record.
cURL
curl -G "https://api.signa.so/v1/citations" \
-H "Authorization: Bearer sig_YOUR_KEY_HERE" \
--data-urlencode "offices=US" \
--data-urlencode "cited_ref=5567890"
Errors
| Status | Type | Description |
|---|---|---|
| 400 | validation_error | cited_ref supplied without offices, blank cited_ref, action_date_gte later than action_date_lte, bad enum value, a malformed trademark_id / cited_trademark_id, or unknown query parameter |
| 400 | id_type_mismatch | trademark_id or cited_trademark_id is a well-formed ID of another type (e.g. own_...) rather than a tm_... |
| 400 | cursor_expired | Cursor is blank, expired, tampered with, or was issued for a different endpoint |
| 400 | cursor_invalid | Cursor was issued under a different sort value. Restart pagination from the first page, or keep the sort the cursor was issued under |
| 401 | unauthorized | Missing or invalid API key |
| 403 | forbidden | API key lacks the trademarks:read scope |
| 429 | rate_limited | Rate limit exceeded |
offices value is not an error. It returns 200 with an empty list.
Related Endpoints
- Trademark Citations: prior marks cited against one application
- Trademark Cited By: applications one mark was cited against
- List Offices: per-office
capabilities.citationsstate - Search Proceedings: contested proceedings, the third-party counterpart to examiner refusals
- Use Case: Trademark Clearance: where citation history fits in a clearance workflow