Keys and IP allowlist
The Partner API is server-to-server only. Your servers call NimbusMint with a private key; browsers and apps never do.
Keep the key on your server
Section titled “Keep the key on your server”If your product has a website or app, put your own server between it and NimbusMint (a “backend for frontend”):
browser or app ──> your server (holds the private key) ──> api.nimbusmint.bot/partner/v1- Your frontend calls your server, with your own user sessions and checks.
- Your server calls NimbusMint with the private key and returns only what your frontend needs.
- Nothing NimbusMint-issued ever reaches a browser, so there is nothing to copy out of your page source.
Your app’s identity is attached server-side: every call made with your private key is attributed to your app. You never send an app identifier or any NimbusMint key from a browser.
The private key
Section titled “The private key”Send it on every request in the Authorization header:
Authorization: Bearer nmk_live_<id>_<secret>For example (a fake key):
Authorization: Bearer nmk_live_exampleid000_0000000000000000000000000000000000000000000000000000000000000000- Prefix.
nmk_live_marks a production key. The fixed prefix lets secret scanners (GitHub and others) spot a leaked key. - Key ID.
<id>is 12 characters; the key ID shown to you isnmk_<id>. It is not secret: it appears in/health, our logs and support tickets.<secret>is 64 hex characters. - Shown once. The
secretis shown once, when the key is issued. NimbusMint stores only a hash of it and cannot show it again. If you lose it, ask for a new key. - Expiry. Every key expires after at most one year. Plan a rotation before then.
- Scopes. Each key has scopes. v1 has one:
read:hits, needed forGET /hits. - Rate limits are set per key. See Rate limits.
curl https://api.nimbusmint.bot/partner/v1/health \ -H "Authorization: Bearer $NIMBUS_PRIVATE_KEY"const headers = { Authorization: `Bearer ${process.env.NIMBUS_PRIVATE_KEY}` };const res = await fetch('https://api.nimbusmint.bot/partner/v1/health', { headers });headers = {"Authorization": f"Bearer {os.environ['NIMBUS_PRIVATE_KEY']}"}res = requests.get("https://api.nimbusmint.bot/partner/v1/health", headers=headers, timeout=10)How a request is checked
Section titled “How a request is checked”In order: the key is parsed and looked up, the secret is compared, then we check that the key is not revoked or expired, that the request comes from an allowlisted IP, that the route exists, that the key has the route’s scope, and finally the rate limit. Because the key is checked first, a request without a valid key learns nothing about which paths exist.
Every key problem (missing, malformed, unknown, wrong secret, revoked, expired, partner disabled) returns the same
401 invalid_key, on purpose: the response never says which part failed. An allowlist or scope problem returns
a 403 with a specific code. See Errors.
IP allowlist
Section titled “IP allowlist”Every private key has an allowlist of source addresses. Requests from anywhere else get
403 ip_not_allowed, even with the right key.
- The allowlist is required: a key cannot be issued without one.
- Send us the public egress addresses of every server that calls the API: the address the internet sees,
not a private
10.xor192.168.xaddress. - Up to 16 entries, as single addresses or CIDR ranges, public addresses only. IPv4 ranges can be at most a
/24and IPv6 ranges at most a/48(for example203.0.113.0/24, a documentation range). - “Allow everything” (
0.0.0.0/0,::/0) is never accepted.
Request signing (coming soon)
Section titled “Request signing (coming soon)”Next, keys gain Ed25519 request signing: you sign each request with a private key that never leaves your server, and we hold only the public half. See Request signing.
Revocation
Section titled “Revocation”We can revoke a key or disable a partner at any time; it takes effect within 10 seconds. Ask us to revoke a key straight away if you think it has leaked.
