Authentication and embedding
Private value receipts require a signed JWT for access. This page covers how to set up the signing key, mint tokens, embed receipts in your app, and handle login redirects for direct link sharing.
For a conceptual overview of published vs. private visibility, see the overview.
Setting up embed authentication
1. Generate a signing key
In Settings > Embed authentication, click Generate key to create an HS256 signing key. The secret is shown once — copy it and store it securely (e.g. in an environment variable or secret manager).
2. Configure your settings
In the same settings page, configure:
Rotating the signing key
You can rotate the signing key at any time from the same settings page. Rotating generates a new secret and invalidates the old one — any JWTs signed with the previous key will be rejected. After rotating, update the secret in your backend environment.
Rotating a share token
Each value receipt has its own share token that forms its URL (https://app.paid.ai/public/value-receipts/{token}). You can rotate a receipt’s share token to invalidate all existing links to it. A new token is generated and old URLs stop working immediately. This is useful if a link was shared with the wrong person or you want to revoke access without unpublishing.
Revoking all public access
If you need to make all value receipts private at once — for example, when first enabling JWT-gated access across your organization — use the Revoke all action in embed authentication settings. This unpublishes every value receipt in your organization in a single operation.
Minting JWTs
Your backend mints JWTs using the signing secret. Never expose the secret to the browser.
Python
Node.js
JWT claims reference
Scoping modes
JWTs support two scoping modes:
-
Resource-scoped — include
resourceIdin the JWT claims. This grants access to one specific value receipt only. TheresourceIdcan be either the value receipt’s UUID or itspublicUrlToken. -
Customer-scoped — omit
resourceIdand only includesub(the customer’s ID or external ID). This grants access to all value receipts belonging to that customer.
Use resource-scoped tokens when sharing a specific receipt with an end user. Use customer-scoped tokens when embedding multiple receipts in a customer portal where the viewer should see all their receipts.
Embedding value receipts
Use the @paid-ai/embed library to embed value receipts in your application. The library handles iframe creation, secure token delivery via postMessage, auto-resizing, and token refresh — so you don’t have to manage any of that manually.
The library automatically:
- Creates and mounts the iframe in your container element
- Delivers the JWT securely via
postMessage(never in URLs or browser history) - Resizes the iframe to match content height
- Handles token expiry by calling your
onTokenExpiredcallback
Login redirect flow
For direct link sharing (not embeds), private value receipts use a login redirect to authenticate viewers. The login page is yours — Paid just redirects to it and expects a signed token back. You can use any authentication method you want: your own login form, an OAuth provider like Auth0 or Okta, SSO, or anything else.
How it works
- A viewer opens a private value receipt link:
https://app.paid.ai/public/value-receipts/{token} - Since there’s no valid token, Paid redirects the viewer to your configured
loginUrlwith a?redirect=parameter pointing back to the value receipt - Your login page takes over. This is a page you host — it can show a login form, redirect to an OAuth provider, check an existing session, or anything else your app normally does to authenticate users
- Once the viewer is authenticated, your backend identifies which customer they belong to, mints a signed JWT, and redirects them back to the original value receipt URL with
?token={jwt}appended - The value receipt page picks up the token and loads the receipt
Example: simple session-based login
If your app already has sessions (e.g. the viewer is logged into your dashboard), the login endpoint can skip showing a login screen entirely — just check the session, mint a token, and redirect back:
Python
Node.js
Example: with an external auth provider (OAuth / SSO)
If you use an external provider like Auth0 or Okta, the flow adds one more redirect hop — but the pattern is the same. Your login endpoint kicks off the OAuth flow, and the callback mints the Paid token:
Python
Node.js
Token refresh endpoint
For embedded value receipts, implement a refresh endpoint that the embed can call when a token expires: