API Reference

/api/b2b/verify

Single POST endpoint for verifying pre-owned clothing. Bearer-key auth, tier-based rate limits, server-rendered SLA. The page below is generated from the constants the running endpoint enforces; drift between this copy and production should be impossible.

Authentication

Send your API key in the Authorization header with the Bearer scheme. Keys are issued from the partner dashboard and always start with tt_.

Authorization: Bearer tt_demo_replace_with_your_real_key

A key not prefixed with tt_ is rejected with 401 Invalid API key format. Keys start with tt_. An unknown or revoked key is rejected with 401 Invalid or revoked API key.

Request

POST https://api.threadtag.com/api/b2b/verify with a JSON body. brand is optional and defaults to the platform default.

{
  "imageUrl": "https://example.com/photo.jpg",
  "brand": "nike"
}

A missing imageUrl returns 400 { "error": "imageUrl is required" }. A malformed URL returns 400 { "error": "imageUrl must be a valid URL" }.

Response (200)

Every successful call returns the analysis, the resolved brand label, the SLA lane, and a per-minute usage snapshot. X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers are always set.

{
  "id": "f1a3...e7",
  "score": 92,
  "verdict": "verified",
  "reasons": ["stitch gauge matches catalogue", "label typography matches"],
  "brand": "Nike",
  "organization": "Acme Resale",
  "sla": {
    "latencyTier": "priority",
    "priorityLane": true,
    "dedicatedCapacity": true
  },
  "usage": {
    "used": 12,
    "limit": 3000,
    "remaining": 2988
  },
  "tier": "enterprise",
  "rateLimitPerMinute": 3000
}

Rate limits (429)

When a key exceeds its per-minute budget the call is rejected immediately, before any analysis runs. The same rate-limit headers are returned alongside a Retry-After hint.

{
  "error": "Rate limit exceeded",
  "tier": "pro",
  "rateLimitPerMinute": 600,
  "used": 601,
  "remaining": 0,
  "resetAt": "2026-08-05T14:32:00.000Z"
}
Header Value
Retry-After60 (seconds)
X-RateLimit-Limittier's rateLimitPerMinute
X-RateLimit-Remaining0
X-RateLimit-Resetepoch seconds when the window rolls over

Tiers

Rates and quotas are read live from the same constants the rate-limiter enforces. Change a tier in db/api-keys.js and the table updates on the next render.

Tier Rate (per min) Monthly quota Latency lane Dedicated capacity
Starter
starter
60 /min 2,592,000 Standard No
Growth
pro
600 /min 25,920,000 Priority No
Scale
enterprise
3,000 /min 129,600,000 Priority Yes

Monthly quota = rateLimitPerMinute × 60 × 24 × 30. Soft cap: exceeding it returns 429 just like exceeding the per-minute window.

Examples

curl

curl -X POST https://api.threadtag.com/api/b2b/verify \
  -H "Authorization: Bearer tt_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"imageUrl":"https://example.com/photo.jpg","brand":"nike"}'

JavaScript (fetch)

const res = await fetch('https://api.threadtag.com/api/b2b/verify', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer tt_your_api_key',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    imageUrl: 'https://example.com/photo.jpg',
    brand: 'nike'
  })
});
const json = await res.json();

Last reviewed: 2026-08-08