Get started
Authentication
The gateway uses a Bearer token issued by login. The same token is forwarded to every upstream service.
Bearer token
Call POST /api/v1/login with a company account. Read data.access_token and send it on protected routes:
Authorization: Bearer 1|abcdefghijklmnopqrstuvwxyzThere is no gateway API key, HMAC, or OAuth client-credentials flow. Social login is available as POST /api/v1/social-auth (provider is google or facebook plus the provider access_token).
Login responses
Send email and password. Two success shapes exist:
{
"status": "success",
"message": "Logged in successfully",
"data": {
"user": { "id": 4, "role": "user", "email": "user@acme.test", "locale": "fr" },
"access_token": "1|abcdefghijklmnopqrstuvwxyz",
"mfa_setup_required": false
}
}If the account has a usable MFA method, no token is issued:
{
"status": "success",
"message": "MFA required",
"data": {
"mfa_required": true,
"challenge_token": "opaque-challenge",
"methods": ["email", "totp"],
"email_hint": "u***@acme.test"
}
}Complete the challenge with POST /api/v1/login/mfa/verify (challenge_token, method = email or totp, code). For WebAuthn, call .../webauthn/options then .../webauthn/verify with the browser assertion. Wrong credentials always return 401 Invalid email or password (no user enumeration).
When company policy requires MFA but nothing is enrolled, login still succeeds and mfa_setup_required is true. Enroll factors on /api/v1/mfa/....
Register
POST /api/v1/register creates an account and returns 201. No access token is issued — the user must log in. Required fields: first_name, last_name, email, card_id_number, phone_number (E.164, starts with +), address, city, country, password (min 8, mixed case, number, symbol).
Company roles
Only admin (company administrator) and user (employee) may use this API. The gateway checks the role at login and again on every protected request.
| Role | Access |
|---|---|
admin | Allowed. Company settings, users, certificates, license, audit, vault purge. |
user | Allowed. Day-to-day signing, workflows, contacts, vault (ACL-limited). |
| Any other role | 403 — API gateway is restricted to company admin and user roles |
Fine-grained permissions (workflow roles, EDM ACLs, and so on) are enforced by upstream services. The gateway only applies this binary company-user gate. A license in read-only grace returns 403 LICENSE_READONLY on writes; an expired license returns 403 LICENSE_EXPIRED on introspection.
Public routes
These paths do not require a Bearer token:
- Login, register, social login, password reset, login MFA, email verification
- External-identity self-service under
/api/v1/public/external-identity(uses X-Identity-Token after the code is verified) - Public signing session under
/api/v4/public/envelopes/{signer_uuid} - Vault share links:
GET /api/edm/shared/{token} GET /api/v1/certificates/{certificate}/downloadGET /api/v4/documents/{uuid}/downloadGET /api/v4/verify/{uuid}GET /api/v4/attachments/{att_uuid}/download
Everything else requires a valid company-user token.
MFA
Two separate MFA surfaces exist:
- Login MFA — public, authenticated by
challenge_tokenonly:/api/v1/login/mfa/email/send,.../verify,.../webauthn/options,.../webauthn/verify. - Account enrollment — Bearer required:
GET /api/v1/mfa/status, then email / TOTP / WebAuthn enroll and disable routes. Disabling a method requires the accountpassword.
Company admins configure policy on PUT /api/v1/companies/{company}/security-settings (mfa_enforced, allowed_methods, min_signature_level, …) and can reset an employee with POST /api/v1/users/{user}/mfa/reset.
POST /api/v1/2fa/send and .../verify are a legacy step-up OTP tied to the current Bearer token — not the login challenge.
External identity
External signers manage verified identities without a company account:
POST /api/v1/public/external-identity/codewithemail— always202(anti-enumeration)POST /api/v1/public/external-identity/verifywithemail+ 6-digitcode→{ "access_token": "…" }- Send that value as
X-Identity-Token(not Bearer) onGET /api/v1/public/external-identityandPOST .../{identity}/revoke
Statuses: pending, verified, rejected, revoked, expired. Face capture for a signing session lives on the public envelope identity routes.
Profile
Self-service only — {user} must be the authenticated user. PATCH /api/v1/profile/{user}/update is a partial update. Use multipart/form-data when uploading seal (png/jpg, max 20 MB).
job_title— shown under the signature (max 120)locale—fr,en, ornullto reset (emails fall back to the request locale, then French)signature_mentions—{ enabled, frame, mentions[] }.mentionsis a closed list of at most 4:fullName,jobTitle,company,email,signedAt,provider
Password change uses old_password and new_password (not current_password). Availability uses is_available, optional unavailable_until (Y-m-d), and interim_user_ids (0–2 colleagues).
Headers
| Header | When |
|---|---|
Authorization: Bearer {token} | All protected routes |
Content-Type: application/json | JSON request bodies |
Content-Type: multipart/form-data | File uploads (envelopes, workflows, vault, identity, seals) |
Accept: application/json | Recommended on every call |
Accept-Language | Optional; forwarded upstream. Profile locale also controls email language. |
X-Identity-Token | Public external-identity routes after POST /api/v1/public/external-identity/verify |