Upload and retrieve documents
Encode files locally, attach them at the right stage, and handle readiness and partial outcomes explicitly.
Choose when to upload
You can include session_documents during creation or add them later with POST /sessions/{bn_session_id}/documents. Prepare required documents before directing participants into signing.
| Approach | Use when |
|---|---|
| Upload at creation | Your application already has the final input PDF. |
| Upload after creation | Documents arrive in a later application step. |
| Preparation hold | Fields must be placed and reviewed before invitations. |
| Saved templates | A prepared document or repeatable field layout is reusable. |
Encode a PDF locally
Send JSON with an array of document objects. The later-upload endpoint validates readable PDF content and does not accept multipart form uploads.
import { readFile } from 'node:fs/promises';
const bytes = await readFile('./agreement.pdf');
const body = {
session_documents: [{
name: 'agreement.pdf',
base64Doc: bytes.toString('base64')
}]
};Base64 increases the payload size. Confirm tested endpoint and gateway limits for your document sizes rather than treating a logging limit as an upload limit.
Respect session and merge restrictions
Documents cannot be added to a closed session. A merged document with fields placed after the merge can also block additions to preserve preparation work.
| Condition | Current outcome |
|---|---|
| Cancelled, complete, expired, or terminated | Upload blocked with a closed-session response. |
| Completion marker says completed | Upload blocked. |
| Fields placed after a document merge | 409 merge-lock response. |
| Session closes during a batch | Partial attachment can return 409 with counts. |
Handle partial attachment
A batch is not guaranteed to be atomic. If the session closes after some documents attach, the response can report how many were stored. Other per-file and annotation/template failures may still produce a generic success when some work succeeds.
{
"response": "Partial",
"error_reason": "session_closed_partial_upload",
"stored_documents_count": 1,
"requested_documents_count": 2
}Do not blindly replay a document batch after an ambiguous timeout or partial result. Already stored documents can remain attached.
Retrieve the final PDFs
Use GET /sessions/{bn_session_id}/signed_documents. The response contains Base64 files under final_documents. An empty array can mean files are not yet available.
{
"final_documents": [
{
"name": "signed-agreement.pdf",
"base64Doc": "BASE64_PDF_CONTENT",
"initial_document_name": "agreement.pdf"
}
]
}Separate API retrieval from webhook delivery
Webhook delivery can carry files, temporary download links, or names only. These choices are independent from signer-facing final-document release settings.
| Channel | Format |
|---|---|
| Signed documents API | Base64 content in final_documents. |
| Webhook files mode | Base64 content inside the event’s document array. |
| Webhook links mode | document_url and document_url_expires_at; current links expire after 24 hours. |
| Webhook none mode | Names and metadata only. |
| Completion report | Optional separate artifact in GET session; not automatically added to signed_documents. |
Persist the artifacts you need
Decode Base64 on your server, verify the expected files, and save them under your application’s access and retention policy. Store the original-document mapping and session ID with each output. Treat temporary download links as access credentials, not durable storage locations.