v1: account
Balance
Section titled “Balance”GET /v1/balance (scope balance:read):
export NOPTCHA_KEY=nop_test_... # your test or live keycurl -s "https://api.noptcha.com/v1/balance" \ -H "Authorization: Bearer $NOPTCHA_KEY"import os
import requests
API = "https://api.noptcha.com"KEY = os.environ["NOPTCHA_KEY"]
r = requests.get( f"{API}/v1/balance", headers={ "Authorization": f"Bearer {KEY}", }, timeout=30,)print(r.status_code, r.json())const API = 'https://api.noptcha.com';const KEY = process.env.NOPTCHA_KEY;
const res = await fetch(`${API}/v1/balance`, { method: 'GET', headers: { Authorization: `Bearer ${KEY}`, },});console.log(res.status, await res.json());| Field | Meaning |
|---|---|
available |
What new tasks can use: cash + promo + credit_limit − held |
cash |
Money you paid in |
promo |
Promotional credit |
held |
Reserved for tasks in flight |
credit_limit |
Credit agreed with us separately; zero unless you have such an agreement (accounts are prepaid by default) |
All amounts are decimal strings with 6 places; currency is USD.
Task types and prices
Section titled “Task types and prices”GET /v1/types returns the types your organization can use, with their deadline, variants and the price of each
variant for your organization. Any valid key can call it.
export NOPTCHA_KEY=nop_test_... # your test or live keycurl -s "https://api.noptcha.com/v1/types" \ -H "Authorization: Bearer $NOPTCHA_KEY"import os
import requests
API = "https://api.noptcha.com"KEY = os.environ["NOPTCHA_KEY"]
r = requests.get( f"{API}/v1/types", headers={ "Authorization": f"Bearer {KEY}", }, timeout=30,)print(r.status_code, r.json())const API = 'https://api.noptcha.com';const KEY = process.env.NOPTCHA_KEY;
const res = await fetch(`${API}/v1/types`, { method: 'GET', headers: { Authorization: `Bearer ${KEY}`, },});console.log(res.status, await res.json());data is an empty list when no type is available. price_version identifies the price list the prices come from.
Public catalog
Section titled “Public catalog”GET /v1/catalog lists every public task type with its list price, in the same shape, and needs no key (a key sent
along is ignored). It is meant for price tables and for tools that have no key yet; use GET /v1/types for the prices
that apply to your organization.
curl https://api.noptcha.com/v1/catalogThe response also has currency (USD) and placeholder (true only on test deployments, where the prices are not
real). It may be cached for 5 minutes (Cache-Control: public, max-age=300) and carries an ETag: send it back in
If-None-Match to get 304 Not Modified. Any website may read it from the browser (Access-Control-Allow-Origin: *, on error responses too). There is no
CORS preflight: send a simple request (a plain fetch(url), or only safelisted headers such as Accept); a request
with Authorization or another custom header is blocked by the browser. The rate limit is per client IP (IPv6: per
/64, and per /48 at ten times the rate), see Limits.
Requests are limited per client IP: 60 per minute, bursts of 30 (starting values); beyond that 429 rate_limited
with Retry-After.
The key itself
Section titled “The key itself”GET /v1/me shows the organization, the key (prefix and last four characters, mode, scopes, allowed types and IP
ranges, expiry), its budget and how much of it is used in the current period, and the rate limits that apply. Any
valid key can call it; it never returns the key itself.
export NOPTCHA_KEY=nop_test_... # your test or live keycurl -s "https://api.noptcha.com/v1/me" \ -H "Authorization: Bearer $NOPTCHA_KEY"import os
import requests
API = "https://api.noptcha.com"KEY = os.environ["NOPTCHA_KEY"]
r = requests.get( f"{API}/v1/me", headers={ "Authorization": f"Bearer {KEY}", }, timeout=30,)print(r.status_code, r.json())const API = 'https://api.noptcha.com';const KEY = process.env.NOPTCHA_KEY;
const res = await fetch(`${API}/v1/me`, { method: 'GET', headers: { Authorization: `Bearer ${KEY}`, },});console.log(res.status, await res.json());For test keys limits.sandbox shows the sandbox limits and the budget’s used is always zero.
GET /v1/usage (scope usage:read) reports solved (billed) and unbilled tasks and the amounts charged, by hour or
day and by type or key:
export NOPTCHA_KEY=nop_test_... # your test or live keycurl -s "https://api.noptcha.com/v1/usage?granularity=day&group_by=type" \ -H "Authorization: Bearer $NOPTCHA_KEY"import os
import requests
API = "https://api.noptcha.com"KEY = os.environ["NOPTCHA_KEY"]
r = requests.get( f"{API}/v1/usage", params={ "granularity": "day", "group_by": "type", }, headers={ "Authorization": f"Bearer {KEY}", }, timeout=30,)print(r.status_code, r.json())const API = 'https://api.noptcha.com';const KEY = process.env.NOPTCHA_KEY;
const res = await fetch(`${API}/v1/usage?granularity=day&group_by=type`, { method: 'GET', headers: { Authorization: `Bearer ${KEY}`, },});console.log(res.status, await res.json());| Parameter | Values | Default |
|---|---|---|
granularity |
hour, day |
day |
group_by |
type, key |
type |
from, to |
RFC 3339 or YYYY-MM-DD, UTC; to is exclusive |
the last 24 hours (hour) or 30 days (day) |
- Ranges are rounded to whole hours or days. At most 7 days by hour and 92 days by day;
group_by=keycovers only the last 90 days (an earlierfromis moved forward, and the response’sfromshows the effective start). - At most 10,000 rows; a larger request is
400 invalid_request(narrow the range or use days). - Amounts are what was actually deducted from your balance, including corrections.
datalists only periods with activity;totalssums them. Withgroup_by=key, a row with"key": nullholds any amount not attributed to a key (usually zero). - Limited to 20 requests per minute per organization (bursts of 5), with
RateLimit-PolicyandRateLimitheaders. - Test keys get an empty report with
"sandbox": true.
These ranges and limits are starting values and may change.