Payna is backed by Y Combinator

Getting started

Authentication

Every request carries an API key as a bearer token. The key identifies your company, so no endpoint takes a tenant parameter.

The header

Authorization: Bearer pk_live_...

Keys always begin with pk_live_. A key that does not is rejected before any lookup happens. There is no sandbox key prefix and no test mode: the API is read only, so there is nothing to sandbox.

curl -s https://app.payna.com/api/v1/licenses \
  -H "Authorization: Bearer $PAYNA_API_KEY"

Managing keys

Keys are created and revoked by an admin from Settings, then API Keys, in the Payna dashboard. Each key carries a label, and the dashboard records when it was last used, which is the fastest way to find a key that nothing depends on any more.

Rotating a key

Mint the replacement first, deploy it, confirm the old key has stopped being used, then revoke. Revocation takes effect immediately and any request still presenting the old key gets a REVOKED response, so revoking before deploying will cause an outage.

Capabilities

A key is entitled to specific resource groups rather than to the whole API. There are two, and a key can hold either or both.

CapabilityGrants access to
licensesThe company license portfolio endpoints.
individualsPer-person licensing, conditions, CE, attestations, and tasks.

Rate limits

300 requests per 15 minutes, on a sliding window. The budget is bucketed per API key, not per IP address, so two services sharing one key share one budget. Give each service its own key if you want them isolated.

Exceeding the budget returns 429 with a Retry-After header giving the number of seconds until the window frees up. Wait that long rather than retrying immediately.

// A 429 always carries Retry-After, in seconds.
if (res.status === 429) {
  const wait = Number(res.headers.get('Retry-After') ?? 30)
  await new Promise((r) => setTimeout(r, wait * 1000))
  // then retry once
}

Staying inside it

  • Poll the summary endpoint, not the list endpoint, when you only need to know whether anything changed.
  • Raise limit toward its maximum of 200 rather than walking many small pages.
  • Cache against meta.synced_at. Payna reconciles with the registries on a schedule, so polling faster than that returns identical data and spends budget for nothing.

Handling keys safely

  • A key reads your entire compliance portfolio. Treat it like a database credential.
  • Server side only. Never in browser JavaScript, a mobile binary, or a repository.
  • One key per consuming system, so revoking one does not take down the others.
  • Revoke immediately if a key may have leaked. It is free, and minting a replacement takes seconds.

See how Payna runs licensing.

Tell us a little about the company and we’ll walk through how Payna handles licensing and compliance in every US state.