REST API
Run scans from your own code. The API is available on the Pro plan and above, authenticates with a bearer key, and is paid for with credits.
Last updated: 6 September 2026
Authentication
Create a key under Settings → API keys. The plaintext key is shown once and cannot be recovered afterwards; only its prefix is stored in a readable form. Send it as a bearer token on every request.
curl https://api.namesight.app/v1/usage \
-H "Authorization: Bearer ns_live_..."Every key carries a set of scopes. A request that needs a scope the key does not have is refused with 403, so a key you hand to a read-only integration cannot start a paid scan.
| Scope | Grants |
|---|---|
| scans:write | POST /v1/scans — starting a scan, which spends credits |
| scans:read | GET /v1/scans, GET /v1/scans/{id}, GET /v1/usage |
| reference:read | The /v1/ref/* lookup endpoints |
| reports:write | POST /v1/scans/{id}/shares — minting a public share link |
| ideas:write | POST /v1/ideas — the name generator |
| projects:read | GET /v1/projects — listing projects so a scan can be filed |
| webhooks:manage | The /v1/webhooks endpoints |
Credits and quota
Every scan is paid for with credits, whether you start it here or in the web app. A scan costs the sum of the modules it runs: 100 credits with all five default modules, and less when you leave one out. Your plan grants a credit allowance each month; unspent credits roll over.
The charge is written before any work is queued, so a scan that cannot be paid for never runs and never leaves a row behind. If queueing fails after the charge, the credits are refunded automatically.
- Balance too low → 429 with a problem body explaining the shortfall
- Plan without API access → 402 and an upgrade URL
- Credit spending switched off for the workspace → 403
Starting a scan
POST /v1/scans queues a scan and answers 202 straight away. Scanning is asynchronous: the response carries a scanId, not the result.
curl -X POST https://api.namesight.app/v1/scans \
-H "Authorization: Bearer ns_live_..." \
-H "Content-Type: application/json" \
-d '{
"name": "lumina labs",
"regions": ["TR", "EM", "US"],
"niceClasses": [9, 41],
"tlds": ["com", "io"],
"modules": ["trademark", "domain", "social"]
}'{ "scanId": "scn_...", "totalJobs": 12, "creditsSpent": 100, "balance": 1900 }| Field | Required | Meaning |
|---|---|---|
| name | yes | The brand name to check, 2–64 characters |
| regions | no | Trademark offices to search. Defaults to your workspace default |
| niceClasses | no | Goods/services classes 1–45. Narrows trademark hits to real conflicts |
| tlds | no | Domain extensions, without the leading dot |
| modules | no | trademark, domain, social, dev, appstore |
| adapters | no | Restrict to specific source adapters by id |
| projectId | no | File the scan under an existing project |
| options.similarSearch | no | Fuzzy trademark query for near-miss marks (Pro and above) |
Reading the result
Poll GET /v1/scans/{id} until status is completed or completed_partial. A typical scan finishes in under a minute; poll about once a second and widen the interval as you wait, so a long scan does not eat your rate limit.
curl https://api.namesight.app/v1/scans/scn_... \
-H "Authorization: Bearer ns_live_..."| status | Means |
|---|---|
| queued | Accepted, no source contacted yet |
| running | Some checks are done; doneJobs / totalJobs shows progress |
| completed | Every check finished |
| completed_partial | Finished, but at least one source could not be verified |
| failed | The scan could not be run |
Each entry in checks is one source answering about one target, with its own verdict, the sourceUrl it was read from and the fetchedAt timestamp. The summary object appears once the scan finishes and carries the score, the risk band and the trademark tally.
| verdict | Means |
|---|---|
| available | The source says the name is free |
| taken | In use — a registered handle, a resolving domain |
| conflict | A live trademark that overlaps the requested classes |
| risky | In use in a way that may or may not block you |
| unknown | The source could not be verified |
| error | The source failed; errorCode says how |
Reference data
Four lookup endpoints describe what a scan request may contain. They need the reference:read scope and cost nothing.
| Endpoint | Returns |
|---|---|
| GET /v1/ref/nice-classes | The 45 Nice classification classes |
| GET /v1/ref/regions | Trademark offices a scan can search |
| GET /v1/ref/tlds | Domain extensions grouped by tier |
| GET /v1/ref/adapters | Every source adapter, with its module |
Errors and rate limits
Errors are RFC 9457 problem documents sent as application/problem+json. The type field identifies the failure, detail explains it, and some carry extras such as upgradeUrl.
{
"type": "https://namesight.app/errors/quota-exceeded",
"title": "Quota exceeded",
"status": 429,
"detail": "Not enough credits (balance 0, need 100). Top up or switch off a module to continue."
}| Status | When |
|---|---|
| 400 | The request body did not validate |
| 401 | Key missing, unknown, revoked or expired |
| 402 | The plan does not include the public API |
| 403 | The key lacks a scope, or credit spending is off |
| 404 | No such scan in this workspace |
| 403 (key-cap-exceeded) | This key's monthly credit cap is reached; raise it under Settings → API keys |
| 409 | An Idempotency-Key was reused with a different body |
| 429 | Rate limit or credit balance exceeded |
Rate limits are counted per key over a sliding minute and reported on every response, so you can back off before being refused.
x-ratelimit-limit: 60
x-ratelimit-remaining: 58
x-ratelimit-reset: 41Acting on a scan, and the rest
Beyond starting and reading a scan, a key can run it again, retry the sources that could not answer, delete it, share its report, list the workspace's projects and generate name ideas. Each needs the scope shown.
| Method and path | Scope | Does |
|---|---|---|
| POST /v1/scans/{id}/rescan | scans:write | Starts a new scan with the same name and settings. Priced like a new scan; the original is kept. |
| POST /v1/scans/{id}/retry-unknowns | scans:write | Queues again only the checks that ended unknown or errored, bypassing the cache. Free. |
| DELETE /v1/scans/{id} | scans:write | Removes the scan, its checks and its share links. Credits are not refunded. |
| POST /v1/scans/{id}/shares | reports:write | Returns a public URL for the report. Anyone holding it can read the report; the plan caps how long it lives. |
| GET /v1/projects | projects:read | The workspace's projects, with their default classes, offices and TLDs. |
| POST /v1/ideas | ideas:write | Runs the name generator from a brief, a seed name or themes. Free. |
| GET /v1/usage/events | scans:read | Every API call the workspace made in the last days, failures included. |
Retrying safely: send an Idempotency-Key header (any unique string) with POST /v1/scans or a rescan. A retry that carries the same key within 24 hours replays the first answer — the response says Idempotent-Replayed: true — instead of starting and charging a second scan. The same key with a different body is refused with 409.
curl -X POST https://api.namesight.app/v1/scans \
-H "Authorization: Bearer ns_live_..." \
-H "Idempotency-Key: 4f7c2c1e-order-1187" \
-H "Content-Type: application/json" \
-d '{"name":"Lumina Labs","modules":["trademark","domain"]}'Waiting without polling: GET /v1/scans/{id}?wait=60000 holds the request until the scan finishes or the wait (at most 60 seconds) elapses, then answers with the scan as it stands. One request, one rate-limit slot, no loop.
Paging: GET /v1/scans answers with items and nextCursor. Pass nextCursor back as cursor for the next page; null means the last page. status filters by one or more comma-separated statuses.
Webhooks
Instead of polling, register an https endpoint and receive a signed POST when a scan finishes. Endpoints are managed under Settings → API or through /v1/webhooks with the webhooks:manage scope; a workspace may hold ten. The signing secret is shown once, at creation and on rotate.
| Event | When | data carries |
|---|---|---|
| scan.completed | A scan reached completed, completed_partial or failed | scanId, status, kind, rawName, queryName, projectId, score, band, unknownCount, trademarkLiveConflicts, totalJobs, doneJobs, createdAt, completedAt, url |
Every delivery carries four headers: x-namesight-event, x-namesight-delivery (the same id on every retry, so you can deduplicate), x-namesight-timestamp (unix seconds) and x-namesight-signature. The signature is v1= followed by the hex HMAC-SHA256 of "<timestamp>.<raw body>" under your secret. Verify it against the raw request body, and reject timestamps older than five minutes.
import { createHmac, timingSafeEqual } from "node:crypto";
// Express-style handler; keep the RAW body — a re-serialised JSON will not match.
app.post("/hooks/namesight", express.raw({ type: "*/*" }), (req, res) => {
const ts = req.header("x-namesight-timestamp");
const sig = req.header("x-namesight-signature"); // "v1=<hex>"
const body = req.body.toString("utf8");
const expected = "v1=" + createHmac("sha256", process.env.NAMESIGHT_WEBHOOK_SECRET)
.update(`${ts}.${body}`).digest("hex");
const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300;
if (!fresh || expected.length !== sig.length || !timingSafeEqual(Buffer.from(expected), Buffer.from(sig))) {
return res.status(401).end();
}
const event = JSON.parse(body); // { id, event, createdAt, test, data }
res.status(202).end(); // ack first, work later
if (!event.test) handleScanCompleted(event.data); // data.scanId, data.status, data.score, data.url
});Answer with any 2xx within ten seconds and do the work afterwards. Anything else is retried four more times, after 30 seconds, 2, 10 and 60 minutes. Ten deliveries that fail every attempt in a row switch the endpoint off; re-enabling it clears the count. The Test button sends a synthetic scan.completed with test: true.
OpenAPI
The full machine-readable description is served at /v1/openapi.json. It needs no authentication, so you can generate a client from it before you have a key.