Compute Oppositions
curl --request POST \
--url https://api.signa.so/v1/oppositions/compute \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"items": [
{
"office": "<string>",
"filing_route": "<string>",
"publication_date": "<string>"
}
],
"as_of_date": "<string>"
}
'import requests
url = "https://api.signa.so/v1/oppositions/compute"
payload = {
"items": [
{
"office": "<string>",
"filing_route": "<string>",
"publication_date": "<string>"
}
],
"as_of_date": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
items: [{office: '<string>', filing_route: '<string>', publication_date: '<string>'}],
as_of_date: '<string>'
})
};
fetch('https://api.signa.so/v1/oppositions/compute', 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/oppositions/compute",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'items' => [
[
'office' => '<string>',
'filing_route' => '<string>',
'publication_date' => '<string>'
]
],
'as_of_date' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.signa.so/v1/oppositions/compute"
payload := strings.NewReader("{\n \"items\": [\n {\n \"office\": \"<string>\",\n \"filing_route\": \"<string>\",\n \"publication_date\": \"<string>\"\n }\n ],\n \"as_of_date\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.signa.so/v1/oppositions/compute")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"items\": [\n {\n \"office\": \"<string>\",\n \"filing_route\": \"<string>\",\n \"publication_date\": \"<string>\"\n }\n ],\n \"as_of_date\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.signa.so/v1/oppositions/compute")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"items\": [\n {\n \"office\": \"<string>\",\n \"filing_route\": \"<string>\",\n \"publication_date\": \"<string>\"\n }\n ],\n \"as_of_date\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"object": "list",
"data": [
{
"object": "opposition_window",
"supported": true,
"unsupported_reason": null,
"jurisdiction_code": "EU",
"office_code": "EM",
"filing_route": "domestic",
"publication_date": "2026-05-01",
"window_opens": "2026-05-02",
"window_closes": "2026-08-03",
"status": "open",
"days_until_open": null,
"days_remaining": 29,
"office_time_zone": "Europe/Madrid",
"trigger_event": "application_publication",
"rule_version": "2026-05-06",
"common_extension": null,
"source": {
"citation": "Article 46(1) EUTMR (Regulation (EU) 2017/1001)",
"url": "https://eur-lex.europa.eu/eli/reg/2017/1001/oj/eng"
}
}
],
"has_more": false,
"pagination": { "cursor": null },
"request_id": "req_bT9kM3nP"
}
Oppositions
Compute Oppositions
Compute trademark opposition windows from publication dates
POST
/
v1
/
oppositions
/
compute
Compute Oppositions
curl --request POST \
--url https://api.signa.so/v1/oppositions/compute \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"items": [
{
"office": "<string>",
"filing_route": "<string>",
"publication_date": "<string>"
}
],
"as_of_date": "<string>"
}
'import requests
url = "https://api.signa.so/v1/oppositions/compute"
payload = {
"items": [
{
"office": "<string>",
"filing_route": "<string>",
"publication_date": "<string>"
}
],
"as_of_date": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
items: [{office: '<string>', filing_route: '<string>', publication_date: '<string>'}],
as_of_date: '<string>'
})
};
fetch('https://api.signa.so/v1/oppositions/compute', 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/oppositions/compute",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'items' => [
[
'office' => '<string>',
'filing_route' => '<string>',
'publication_date' => '<string>'
]
],
'as_of_date' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.signa.so/v1/oppositions/compute"
payload := strings.NewReader("{\n \"items\": [\n {\n \"office\": \"<string>\",\n \"filing_route\": \"<string>\",\n \"publication_date\": \"<string>\"\n }\n ],\n \"as_of_date\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.signa.so/v1/oppositions/compute")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"items\": [\n {\n \"office\": \"<string>\",\n \"filing_route\": \"<string>\",\n \"publication_date\": \"<string>\"\n }\n ],\n \"as_of_date\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.signa.so/v1/oppositions/compute")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"items\": [\n {\n \"office\": \"<string>\",\n \"filing_route\": \"<string>\",\n \"publication_date\": \"<string>\"\n }\n ],\n \"as_of_date\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"object": "list",
"data": [
{
"object": "opposition_window",
"supported": true,
"unsupported_reason": null,
"jurisdiction_code": "EU",
"office_code": "EM",
"filing_route": "domestic",
"publication_date": "2026-05-01",
"window_opens": "2026-05-02",
"window_closes": "2026-08-03",
"status": "open",
"days_until_open": null,
"days_remaining": 29,
"office_time_zone": "Europe/Madrid",
"trigger_event": "application_publication",
"rule_version": "2026-05-06",
"common_extension": null,
"source": {
"citation": "Article 46(1) EUTMR (Regulation (EU) 2017/1001)",
"url": "https://eur-lex.europa.eu/eli/reg/2017/1001/oj/eng"
}
}
],
"has_more": false,
"pagination": { "cursor": null },
"request_id": "req_bT9kM3nP"
}
Overview
Compute the opposition window for a published mark (when it opens, when it closes, and how much time is left) from a publication date, without storing anything. Opposition windows are short, unforgiving, and specific to each office. When a conflicting mark publishes, the oppose-by date is what separates a cheap, procedural opposition now from a costly cancellation later. Send a publication date and Signa returns the window, its current status, any routine extensions, and the office rule behind it. Pair it with List Opposition Rules to inspect the office rules, trigger events, time zones, extensions, and citations behind each computation.This endpoint computes the forward-looking opposition window (dates and timing) from a publication date. It does not return opposition cases that have actually been filed. For filed opposition, cancellation, and appeal cases, use List Proceedings.
Request Body
object[]
required
Publications to compute, max 1,000 items. Results are returned in the same order, with one
opposition_window per input item.Show Item object
Show Item object
string
required
Uppercase ST.3 trademark office code, e.g.
US, EM, or CA. Legacy lowercase codes (e.g. uspto, and eu for EUIPO) are accepted as permanent aliases.string
Filing route. One of
national, regional, or madrid. Defaults to national. The response reports the office rule discriminator as domestic or madrid_designation.string
Publication calendar date as
YYYY-MM-DD. Omit when the publication date is unknown; the response status will be unknown.string
Office-local calendar date to compute relative to, as
YYYY-MM-DD. Defaults to today.Response
A standard list response withdata: OppositionWindowComputation[]. Pagination is not used; data[i] corresponds to items[i].
string
Always
list.object[]
Show OppositionWindowComputation
Show OppositionWindowComputation
string
Always
opposition_window.boolean
true when Signa has an opposition rule for the office and route.string | null
unsupported_office, window_not_computable, or null.string | null
Jurisdiction for the office rule, e.g.
EU.string | null
Uppercase ST.3 office code used for the computation, e.g.
EM.string | null
Rule discriminator:
domestic or madrid_designation.string | null
Publication date used as the trigger.
string | null
First day the opposition window is open.
string | null
Last day to oppose, after office-calendar rollover.
string | null
One of
not_started, open, closed, or unknown.integer | null
Days until
window_opens when the status is not_started.integer | null
Days remaining in the window when known.
string | null
IANA office time zone for display.
string | null
application_publication, registration_publication, or international_designation_publication.string | null
Date the office rule was last verified.
object | null
boolean
Always
false.object
Always
{ "cursor": null }.string
Unique request identifier for support and debugging.
supported: false with nullable window fields. A far-future or out-of-calendar-range item that cannot be rolled forward returns unsupported_reason: "window_not_computable" for that item only.
{
"object": "list",
"data": [
{
"object": "opposition_window",
"supported": true,
"unsupported_reason": null,
"jurisdiction_code": "EU",
"office_code": "EM",
"filing_route": "domestic",
"publication_date": "2026-05-01",
"window_opens": "2026-05-02",
"window_closes": "2026-08-03",
"status": "open",
"days_until_open": null,
"days_remaining": 29,
"office_time_zone": "Europe/Madrid",
"trigger_event": "application_publication",
"rule_version": "2026-05-06",
"common_extension": null,
"source": {
"citation": "Article 46(1) EUTMR (Regulation (EU) 2017/1001)",
"url": "https://eur-lex.europa.eu/eli/reg/2017/1001/oj/eng"
}
}
],
"has_more": false,
"pagination": { "cursor": null },
"request_id": "req_bT9kM3nP"
}
Code Examples
curl "https://api.signa.so/v1/oppositions/compute" \
-H "Authorization: Bearer sig_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"items": [
{
"office": "EM",
"publication_date": "2026-05-01"
}
],
"as_of_date": "2026-07-05"
}'
import { Signa } from "@signa-so/sdk";
const signa = new Signa({ api_key: process.env.SIGNA_API_KEY });
const windows = await signa.oppositions.compute({
items: [{ office: "EM", publication_date: '2026-05-01' }]
});
for (const window of windows.data) {
console.log(window.office_code, window.status, window.window_closes);
}
Errors
| Status | Type | Description |
|---|---|---|
| 400 | validation_error | Malformed body, missing items, invalid date format, invalid enum value, 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 1,000 items. The error carries item_count and item_count_limit |
| 429 | rate_limited | Too many requests |
Related Endpoints
- List Opposition Rules, inspect the office rule corpus and statutory citations
- List Proceedings, filed opposition, cancellation, and appeal cases
- Trademark Proceedings, proceedings scoped to one mark
⌘I