Skip to content

Keys and IP allowlist

View as Markdown

The Partner API is server-to-server only. Your servers call NimbusMint with a private key; browsers and apps never do.

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.

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 is nmk_<id>. It is not secret: it appears in /health, our logs and support tickets. <secret> is 64 hex characters.
  • Shown once. The secret is 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 for GET /hits.
  • Rate limits are set per key. See Rate limits.
Terminal window
curl https://api.nimbusmint.bot/partner/v1/health \
-H "Authorization: Bearer $NIMBUS_PRIVATE_KEY"

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.

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.x or 192.168.x address.
  • Up to 16 entries, as single addresses or CIDR ranges, public addresses only. IPv4 ranges can be at most a /24 and IPv6 ranges at most a /48 (for example 203.0.113.0/24, a documentation range).
  • “Allow everything” (0.0.0.0/0, ::/0) is never accepted.

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.

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.