Suggest Goods & Services
curl --request POST \
--url https://api.signa.so/v1/goods-services/suggest \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"description": "<string>",
"jurisdiction_code": "<string>",
"class_number": 123
}
'import requests
url = "https://api.signa.so/v1/goods-services/suggest"
payload = {
"description": "<string>",
"jurisdiction_code": "<string>",
"class_number": 123
}
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({description: '<string>', jurisdiction_code: '<string>', class_number: 123})
};
fetch('https://api.signa.so/v1/goods-services/suggest', 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/goods-services/suggest",
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([
'description' => '<string>',
'jurisdiction_code' => '<string>',
'class_number' => 123
]),
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/goods-services/suggest"
payload := strings.NewReader("{\n \"description\": \"<string>\",\n \"jurisdiction_code\": \"<string>\",\n \"class_number\": 123\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/goods-services/suggest")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"description\": \"<string>\",\n \"jurisdiction_code\": \"<string>\",\n \"class_number\": 123\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.signa.so/v1/goods-services/suggest")
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 \"description\": \"<string>\",\n \"jurisdiction_code\": \"<string>\",\n \"class_number\": 123\n}"
response = http.request(request)
puts response.read_body{
"object": "goods_services_suggestion",
"query": "e-commerce company selling sneakers",
"classifier_version": "classify-v1.0",
"classes": [
{
"class_number": 25,
"title": "Clothing, footwear, headwear",
"confidence": "high",
"rank": 1,
"recommendation_type": "core",
"conditional_on": null,
"rationale": "Sneakers are athletic footwear, squarely in class 25.",
"accepted_terms": [
{
"term": "Running shoes",
"source": "tmclass",
"accepted_offices": ["EUIPO"],
"harmonised": true
},
{
"term": "Athletic footwear",
"source": "uspto_idm",
"accepted_offices": ["USPTO"],
"harmonised": false
}
]
},
{
"class_number": 35,
"title": "Advertising",
"confidence": "medium",
"rank": 2,
"recommendation_type": "conditional",
"conditional_on": "brand used for the storefront, not only the products",
"rationale": "Operating an online store is retail services.",
"accepted_terms": []
}
],
"ambiguous": false,
"clarification_question": null,
"request_id": "req_dV4mN8pQ"
}
Classification
Suggest Goods & Services
Draft a goods/services specification from a description, with filing-ready wording per class
POST
/
v1
/
goods-services
/
suggest
Suggest Goods & Services
curl --request POST \
--url https://api.signa.so/v1/goods-services/suggest \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"description": "<string>",
"jurisdiction_code": "<string>",
"class_number": 123
}
'import requests
url = "https://api.signa.so/v1/goods-services/suggest"
payload = {
"description": "<string>",
"jurisdiction_code": "<string>",
"class_number": 123
}
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({description: '<string>', jurisdiction_code: '<string>', class_number: 123})
};
fetch('https://api.signa.so/v1/goods-services/suggest', 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/goods-services/suggest",
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([
'description' => '<string>',
'jurisdiction_code' => '<string>',
'class_number' => 123
]),
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/goods-services/suggest"
payload := strings.NewReader("{\n \"description\": \"<string>\",\n \"jurisdiction_code\": \"<string>\",\n \"class_number\": 123\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/goods-services/suggest")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"description\": \"<string>\",\n \"jurisdiction_code\": \"<string>\",\n \"class_number\": 123\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.signa.so/v1/goods-services/suggest")
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 \"description\": \"<string>\",\n \"jurisdiction_code\": \"<string>\",\n \"class_number\": 123\n}"
response = http.request(request)
puts response.read_body{
"object": "goods_services_suggestion",
"query": "e-commerce company selling sneakers",
"classifier_version": "classify-v1.0",
"classes": [
{
"class_number": 25,
"title": "Clothing, footwear, headwear",
"confidence": "high",
"rank": 1,
"recommendation_type": "core",
"conditional_on": null,
"rationale": "Sneakers are athletic footwear, squarely in class 25.",
"accepted_terms": [
{
"term": "Running shoes",
"source": "tmclass",
"accepted_offices": ["EUIPO"],
"harmonised": true
},
{
"term": "Athletic footwear",
"source": "uspto_idm",
"accepted_offices": ["USPTO"],
"harmonised": false
}
]
},
{
"class_number": 35,
"title": "Advertising",
"confidence": "medium",
"rank": 2,
"recommendation_type": "conditional",
"conditional_on": "brand used for the storefront, not only the products",
"rationale": "Operating an online store is retail services.",
"accepted_terms": []
}
],
"ambiguous": false,
"clarification_question": null,
"request_id": "req_dV4mN8pQ"
}
Overview
Draft a goods/services specification from a natural-language description. Returns ranked Nice classes with filing-ready wording per class, grounded in the pre-approved catalog (Harmonised Database + USPTO ID Manual). Every term in the response is an actual accepted term; invented wording never appears. Use this to power:- Filing wizards that auto-draft the goods/services block of an application
- Attorney drafting tools
- Multi-class application flows where each class is a separate line item
Just need the class numbers (no wording)? Use Suggest Classifications instead: same input, lighter response, billed at 1 unit.
class_number in the body to restrict the response to a single, already-chosen class. This is useful when you’re refining wording inside a class the user has already picked.
For background on Nice classes and office acceptance, see the Classifications and Goods/Services guide.
Body Parameters
string
required
Description of the goods, services, or business (3-500 characters). Natural-language, no special format.
string
Optional ISO-3166-1 alpha-2 jurisdiction code (e.g.
US, EU, GB). Biases retail-vs-product interpretation toward local practice.integer
Optional Nice class (1-45). When set, scopes the response to that single class. Useful for refining wording when the class has already been chosen.
Response
string
Always
goods_services_suggestion.string
The description you submitted, echoed back.
string
Version tag of the classifier that produced this response.
object[]
Ranked suggested classes, each with filing-ready accepted terms.
integer
Nice class number (1-45).
string
Canonical class title.
string
One of
high, medium, or low.integer
1-indexed position in the returned ordering.
string
One of
core, conditional, or adjacent.string | null
When
recommendation_type is conditional, the condition under which this class applies. Otherwise null.string
Short explanation of why this class was suggested.
object[]
Paste-ready goods/services terms for this class, drawn only from the pre-approved catalog.
boolean
true when the description has two or more materially different filing strategies.string | null
When
ambiguous is true, a question to ask the user. Otherwise null.string
Unique request identifier for support and debugging.
accepted_terms has this shape:
| Field | Type | Description |
|---|---|---|
term | string | The canonical term text. |
source | string | Source catalog (e.g. tmclass, uspto_idm). |
accepted_offices | string[] | Offices that accept this term (e.g. USPTO, EUIPO). |
harmonised | boolean | Whether the term is on the TMClass harmonised list. |
{
"object": "goods_services_suggestion",
"query": "e-commerce company selling sneakers",
"classifier_version": "classify-v1.0",
"classes": [
{
"class_number": 25,
"title": "Clothing, footwear, headwear",
"confidence": "high",
"rank": 1,
"recommendation_type": "core",
"conditional_on": null,
"rationale": "Sneakers are athletic footwear, squarely in class 25.",
"accepted_terms": [
{
"term": "Running shoes",
"source": "tmclass",
"accepted_offices": ["EUIPO"],
"harmonised": true
},
{
"term": "Athletic footwear",
"source": "uspto_idm",
"accepted_offices": ["USPTO"],
"harmonised": false
}
]
},
{
"class_number": 35,
"title": "Advertising",
"confidence": "medium",
"rank": 2,
"recommendation_type": "conditional",
"conditional_on": "brand used for the storefront, not only the products",
"rationale": "Operating an online store is retail services.",
"accepted_terms": []
}
],
"ambiguous": false,
"clarification_question": null,
"request_id": "req_dV4mN8pQ"
}
Code Examples
Full draft (let the classifier pick the classes)
curl -X POST "https://api.signa.so/v1/goods-services/suggest" \
-H "Authorization: Bearer sig_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"description": "e-commerce company selling sneakers",
"jurisdiction_code": "US"
}'
import { Signa } from "@signa-so/sdk";
const signa = new Signa({ api_key: process.env.SIGNA_API_KEY });
const spec = await signa.goodsServices.suggest({
description: "e-commerce company selling sneakers",
jurisdiction_code: "US",
});
for (const cls of spec.classes) {
console.log(`Class ${cls.class_number}: ${cls.title}`);
for (const term of cls.accepted_terms) {
console.log(` ${term.term}`);
}
}
Refine wording for a known class
Passclass_number when the applicant has already decided which class to file under and only needs the wording.
TypeScript
const refined = await signa.goodsServices.suggest({
description: "men's running shoes for marathon training",
class_number: 25,
});
// refined.classes has a single entry for class 25 with accepted terms.
Errors
| Status | Type | Description |
|---|---|---|
| 400 | validation_error | description missing, shorter than 3, longer than 500 chars, or class_number outside 1-45 |
| 401 | unauthorized | Missing or invalid API key |
| 403 | forbidden | API key lacks trademarks:read scope |
| 502 | upstream_error | Classification service temporarily unavailable |
Related Endpoints
- Suggest Classifications, same input, lighter response, billed at 1 unit
- List Goods & Services, browse and search the pre-approved terms catalog directly
- List Classifications
- Retrieve Classification