Authentication
The API authenticates servers with organization API keys. A key belongs to an organization (not to a person), carries a set of permissions, and works in exactly one mode: test or live.
Sending the key
Section titled “Sending the key”Use either header:
# Authorization header (recommended)curl https://api.bonafidesign.com/v1/envelopes -H "Authorization: Bearer bf_live_…"
# or x-api-keycurl https://api.bonafidesign.com/v1/envelopes -H "x-api-key: bf_live_…"Keys look like bf_live_… or bf_test_…. A missing key is a 401 (unauthorized); a malformed, revoked or
expired key is a 401 too. Keep keys on your server: never ship them to a browser or a mobile app. For signing in
the browser, mint a signing session instead.
Test and live keys
Section titled “Test and live keys”Test (bf_test_…) |
Live (bf_live_…) |
|
|---|---|---|
| Documents | Rendered with a TEST watermark |
Clean |
| Delivered only to members of your organization | Delivered to every recipient | |
| Billing | Free and unlimited, never counted | Completed envelopes count toward your plan |
| Data | Envelopes, links and webhook endpoints created with the key are test-mode | Live-mode |
The mode comes from the key, never from the request: ?test_mode=true on POST /v1/envelopes only applies to
dashboard sessions. Lists (GET /v1/envelopes, GET /v1/signing-links) only return the key’s mode, and an
envelope’s events go only to webhook endpoints of the same mode. Every envelope and webhook payload says which
mode it is in (testMode).
Creating and revoking keys
Section titled “Creating and revoking keys”Keys are managed in the dashboard, Settings › API keys, by members
with the apikey:manage permission (owners and admins). The secret is shown once, when the key is created. You
can give a key a name, a mode, an expiry (1 to 365 days, or none) and scopes.
Scopes
Section titled “Scopes”A key’s scopes are the organization permissions it may use. By
default a new key gets the creator’s permissions minus the administrative ones (org:manage, member:manage,
sso:manage, apikey:manage, billing:manage), and nobody can grant a key a permission they do not have. A call
outside the key’s scopes is a 403 naming the missing permission:
{ "type": "https://bonafidesign.com/problems/forbidden", "title": "Forbidden", "status": 403, "detail": "Missing permission: envelope:send.", "requestId": "req_V1StGXR8Z5jdHi6BmyT2"}| Permission | Lets a key |
|---|---|
template:read |
List and read templates, versions and their PDFs |
template:write |
Create templates, upload files, save drafts, delete unused templates |
template:publish |
Publish a draft as a new version |
envelope:read |
List and read envelopes, documents and audit trails; list signing links |
envelope:send |
Create envelopes, signing sessions and signing links; resend links |
envelope:void |
Void envelopes in progress |
org:manage |
Manage webhook endpoints and redeliver events; read organization settings |
billing:manage |
Read usage (GET /v1/usage) and invoice amounts |
Managing webhook endpoints needs org:manage, which keys do not get by default: register endpoints in the
dashboard, or create a key with that scope explicitly.
Which endpoints take what
Section titled “Which endpoints take what”Each operation in the API reference lists its security schemes. In short:
- API key or dashboard session: templates, envelopes, signing sessions, signing links, webhook endpoints, organization settings, billing overview and usage.
- Dashboard session only: API keys, SCIM tokens, SSO connection settings, organization logo upload, billing checkout and portal, revealing a webhook secret.
- Signer token:
/v1/signing/*, used by the hosted page and<bf-signing>with a session token (bfs_…) or the access token it is exchanged for (bfa_…). - Public:
/v1/links/{id}(always-on links),/v1/sso/discover, and the verification API (/v1/public/*,/.well-known/bona-fide/keys.json).
Signing in to the dashboard
Section titled “Signing in to the dashboard”People (not servers) sign in to the dashboard at https://app.bonafidesign.com/sign-in. The default is an email and password; the alternatives are an emailed six-digit code (Email me a code instead), a magic link, a passkey, Google or Microsoft, and your company’s SSO.
- Creating an account with a password sends one email: a code that confirms the address is yours. Until then the password does not sign you in. Signing up with an address that already has an account changes nothing and answers exactly like a new sign-up; the owner of the address gets an email explaining how to sign in instead.
- Passwords are 12 to 128 characters and stored as salted scrypt hashes. A new password that appears in a known data breach is refused: only the first five characters of its SHA-1 hash are sent to Have I Been Pwned (k-anonymity), never the password. If that service does not answer within two seconds, the password is accepted without the check.
- Forgot your password? The reset email links to a page where you choose a new one. The link works once and expires after one hour, and using it signs you out on every device.
- No password yet? Accounts created with a code, a link, a passkey or Google / Microsoft keep signing in that way, and can add a password in Settings › Account. Setting the first password needs a sign-in in the last 15 minutes (the page emails you a code to confirm it is you); changing it needs the current one. Both sign out your other sessions.
- Errors never reveal accounts: a wrong password, an unknown address and an account without a password get the same answer, and a reset request always says the email is on its way.
- Rate limits: password sign-in, sign-up and reset requests are limited per IP address and per email address;
past the limit the answer is
429until the window passes. - Company SSO: when your organization enforces SSO, members at its email domains sign in through the identity provider only. Passwords, codes and magic links are refused for them; owners keep the email code as a break-glass sign-in.
Request ids
Section titled “Request ids”Every response carries an x-request-id header, and every error body a requestId. You may send your own
x-request-id (8 to 128 characters of A-Z a-z 0-9 . _ -) to correlate logs; otherwise the API generates one.
Quote it when you contact support.