DocuSign
DocuSign is the native eSignature provider for contracts. Once connected, sending a contract creates a DocuSign envelope, the recipients sign on DocuSign's UI, and the signed PDF flows back into Kinderpedia automatically.
Connecting
Integrations → DocuSign → Connect redirects you to DocuSign's OAuth consent screen. You'll need a DocuSign admin to grant signature, impersonation, and extended scopes.
The OAuth app is registered once at the Kinderpedia level — every school's connection uses the same app, and DocuSign handles per-account isolation via the account-id captured during consent.
After consent, DocuSign hands back an access token + refresh token + account info. Kinderpedia stores these encrypted on the integration. The tile flips green.
Production vs sandbox
Each Kinderpedia instance points at one DocuSign environment:
- Sandbox (
account-d.docusign.com) — demo accounts, used for E2E testing - Production (
account.docusign.com) — live signers
Sandbox and production are completely separate — sandbox signers don't exist in production and vice versa. Your Kinderpedia admin decides which environment your instance uses; if you're unsure, check with them.
What happens when you send
The full send-via-DocuSign flow is documented under Contracts → DocuSign signing. Short version:
- On
/contracts/{id}/send, pick DocuSign as the channel. - Backend assembles signer recipients from the contract's participants (linked parents).
- Backend POSTs
/v2.1/accounts/{account_id}/envelopeswith the PDF + signer block. - DocuSign emails each recipient a signing link.
- As recipients sign, DocuSign Connect (webhook) fires updates to
/api/integrations/docusign/webhook. - We mirror per-recipient status (sent / delivered / signed / declined) onto
contract_participantsand the contract's overall status. - When all sign, the completed PDF is fetched + stored on S3 + linked from the contract record.
Connect (webhook) for live updates
DocuSign Connect is configured per Kinderpedia instance (not per school) at DocuSign Admin → Connect. Endpoint: https://<your-domain>/api/integrations/docusign/webhook. We use HMAC signature validation with a shared key configured at the Kinderpedia level.
Without Connect, status updates only arrive when staff manually click Refresh status on the contract page. With Connect, they flow in real-time within seconds of recipient action.
Token refresh
DocuSign access tokens are short (8h). On every API call, DocuSignTokenManager::getCredentialsForSchool():
- Returns the cached access token if it's still valid (with a 60s safety margin).
- Otherwise uses the refresh token to mint a new access token.
- On refresh failure (revoked, expired refresh, etc.): tile →
errorwithlast_error = 'reauth_required', and the page surfaces a re-connect prompt.
Correct recipient (email edit)
If a contract is in flight and you discover the parent's email is wrong, edit the email on the Signers card. We call DocuSign's PUT /envelopes/{id}/recipients?resend_envelope=true to:
- Update the recipient's email server-side at DocuSign.
- Trigger DocuSign to re-send the signing email to the corrected address.
We also update contract_participants.participant_email and contracts.docusign_recipients JSON locally so the next manual refresh stays in sync.
Edit is only enabled when:
- The envelope is in a non-terminal state (
sent,delivered— NOTcompleted,declined, orvoided). - The specific recipient hasn't yet signed/declined.
Resend signing email
The paper-plane icon next to a pending recipient triggers PUT /envelopes/{id}/recipients?resend_envelope=true with their existing email — DocuSign treats this no-op PUT as a "re-notify" hint and sends a fresh signing email. Useful when the original ended up in spam.
For non-DocuSign contracts (sent via the share-token email path), the same button regenerates and re-emails the share-token URL instead.
Voiding
The thread header has Void envelope (admin-only). This calls PUT /envelopes/{id} with status=voided plus a reason. The envelope is dead — no further signing possible, no automatic email to recipients. The contract's local status flips to voided. To collect signatures, create a new envelope.
What data DocuSign sees
Recipients see: the PDF content + signer name + signer email. DocuSign does NOT see your linked-lead data, your S3 attachments, or your AuditService entries — only what's embedded in the PDF and the envelope metadata you set (subject + email message).
Common errors
| Symptom | Likely cause |
|---|---|
| Send returns 401 from DocuSign | Refresh token revoked. Re-connect. |
| Status pill stuck at "Sent" forever | DocuSign Connect not configured. Click "Refresh status" manually. |
| Correct-recipient returns 422 with "ENVELOPE_CANNOT_CORRECT_RECIPIENT_NOT_CORRECTABLE" | That signer is already signed/declined — you can't change their email post-fact. |
| Webhook returns 401 in DocuSign Connect logs | HMAC key mismatched between DocuSign Admin and Kinderpedia — contact your Kinderpedia admin. |
| Tile error: "consent_required" | DocuSign added a new required scope. Re-connect. |
Per-school vs per-Kinderpedia
The OAuth client_id is per-Kinderpedia (one app registered with DocuSign). The account is per-school (each school authenticates with its own DocuSign account). So a school in sandbox doesn't accidentally hit a production-mode school's templates.