Batch Document Dispatch
Render multiple documents from a single payload, get an intake receipt, route through an approver, and deliver each PDF to its recipient via REFRACT Delivery.
This tutorial covers the full REFRACT Dispatch batch flow: submitting a batch payload, reviewing the intake receipt, approving, and tracking delivery per recipient.
Products used: REFRACT Dispatch + REFRACT Delivery
Feature gates required: vaultDispatch (and optionally vaultDelivery for per-record email delivery)
How Batch Dispatch Works
Batch dispatch is triggered via the standard POST /api/render endpoint with dataSource as an array of records and features.vaultDispatch: true. There is no separate batch endpoint.
The Dispatcher validates the records, generates a batch intake receipt PDF, and returns it as the response body (HTTP 202). The batch then enters the approval flow (if requireApproval: true) before the Processor renders and delivers each document independently.
Step 1: Submit the Batch
Submit all records in a single render request. Each record in dataSource is an independent document payload sharing the same template.
At most 1,000 records per batch
A batch holds at most 1,000 records, or fewer where your license sets a lower limit. A larger batch is refused before anything is stored: the response is an error-report PDF with status 400 and code BATCH_TOO_LARGE, stating the limit and the number of records received, and no batch, receipt or Activity item is created and nothing is sent. To send more documents, split the records into several smaller batches and submit each one.
POST /api/render
Authorization: Bearer <Entra ID JWT>
Content-Type: application/json{
"templatePath": "templates/account-statement.rpkg",
"options": {
"correlationId": "batch-stmt-may-2026",
"documentId": "BATCH-STMT-MAY-2026",
"generatedBy": "system@contoso.com",
"sourceSystem": "D365_FO",
"documentIdTemplate": "STMT-{{accountNumber}}"
},
"dataSource": [
{
"accountNumber": "ACC-001",
"accountName": "Contoso Ltd",
"recipientEmail": "customer1@contoso.com",
"recipientName": "Customer One",
"statementPeriod": "May 2026",
"closingBalance": 850.00
},
{
"accountNumber": "ACC-002",
"accountName": "Fabrikam Inc",
"recipientEmail": "customer2@fabrikam.com",
"recipientName": "Customer Two",
"statementPeriod": "May 2026",
"closingBalance": 2100.00
}
],
"templateSettings": {
"distribution": {
"mode": "individual",
"requireApproval": true,
"fileNameTemplate": "Statement_{{accountNumber}}_{BATCHID_1}",
"approversEmail": "ap-approver@contoso.com",
"deliveryConfig": {
"mode": "secure-email",
"expiresInHours": 168
}
}
},
"features": {
"vaultDispatch": true
}
}Response 202 Accepted:
The response body is the batch intake receipt PDF. Extract the batch identifiers from the response headers:
| Header | Value |
|---|---|
X-Refract-BatchId | UUID - use this for all /api/dispatch/batch/* calls |
X-Refract-CorrelationId | Correlation ID for the batch activity record |
X-Refract-DispatchReadiness | VALID, WARNINGS, or INVALID |
File the receipt
The intake receipt PDF summarises the validation result for every record (ready, warning, or invalid). Store it against the originating record in your source system (Dynamics 365, SharePoint) for audit purposes. Its times are printed in UTC with the zone shown, and recipient email addresses in the validation details are masked (for example j***@example.com).
INVALID response is 422
When any records have error-severity validation failures, X-Refract-DispatchReadiness is INVALID and the status code is 422. Correct the failing records and resubmit. The receipt details which records failed and why.
Step 2: Approve the Batch
When requireApproval: true, the batch waits in pending-approval state. The configured approver(s) receive an email notification. To approve:
POST /api/dispatch/batch/{batchId}/decide
Authorization: Bearer <Entra ID JWT>
Content-Type: application/json{
"decision": "approve",
"comments": "Validated against AP records - proceed."
}decision accepts approve, reject, or request-changes. On approval, the batch transitions to queued and the Processor begins rendering. comments is optional and at most 1,000 characters; longer comments are refused with 400 (DECISION_COMMENTS_TOO_LONG) and the batch is not changed. The batch's audit chain records a hash of the comments, not the text.
Skip approval for automated pipelines
Set distribution.requireApproval: false in the template settings to auto-approve immediately at intake. The batch goes directly from validation to queued - no /decide call is needed. Use this for fully automated pipelines where the submitting system is authoritative.
Step 3: Track Processing
Poll the batch to track overall progress:
GET /api/dispatch/batch/{batchId}
Authorization: Bearer <Entra ID JWT>The response includes processedCount and errorCount which update as records complete. The batch reaches completed (all succeeded) or partially-failed (some failed) when processing finishes. Reading the batch requires the Lifecycle.Reader role; without it the call returns 403 with code ROLE_MISSING.
To see all individual documents from the batch in REFRACT Lifecycle, open:
https://your-sharepoint-site/SitePages/Home.aspx?batchId={batchId}All child activity items link back to the batch via their ReferenceID column.
Step 4: Track Delivery Per Recipient
Each record that completes processing gets its own correlationId (set by the Processor). Recipients receive a REFRACT Delivery notification email with a time-limited portal link.
For the whole batch, GET /api/dispatch/batch/{batchId} returns deliveryResults: how many recipients' emails were sent (accepted by the email service, which does not confirm inbox delivery), failed (after every automatic retry), or are still pending. Results arrive about 2 minutes after each email is sent, and failures can take longer. In REFRACT Lifecycle, the batch's Batch Timeline shows the same summary under Completed ("Delivery: 146 sent, 1 failed, 3 pending.") with a line for each failed recipient below it; every result, sent ones included, is on the batch's audit chain. See Delivery Results.
Track delivery for any record:
GET /api/delivery-sessions?correlationId={itemCorrelationId}
Authorization: Bearer <Entra ID JWT>Access and download events are recorded per document. Proof of delivery for every statement is available from the REFRACT Lifecycle workspace under the Deliveries tab.
Without Approval: Fully Automated Pipeline
For automated pipelines (nightly batch jobs, event-driven triggers), set requireApproval: false to skip the human approval gate entirely:
{
"templateSettings": {
"distribution": {
"mode": "individual",
"requireApproval": false,
"fileNameTemplate": "Remittance_{{invoiceNumber}}_{BATCHID_1}",
"deliveryConfig": {
"mode": "secure-email",
"expiresInHours": 72
}
}
},
"features": { "vaultDispatch": true }
}The batch receipt is still generated and returned (202). The batch immediately enters queued state - no approver action required.
REFRACT Dispatch Reference
Batch lifecycle states, template distribution settings, and full API reference for list, get, decide, and cancel.
Run a Governed Approval Workflow
Use REFRACT Workflow to collect structured data from a participant, run schema-driven validation, route to an approver, and seal the final PDF on approval.
Invoice Template
A complete recipe for building a professional invoice PDF - line items, totals, and formatted billing parties - using Section, Layout Group, Table, and Template Settings together.