Document Workflows
Send and void documents via the API.
Document Workflows API
Trigger document lifecycle actions. These endpoints require an API token with the appropriate documents.send or documents.void ability.
Send Document
POST /api/v1/documents/{id}/send — Permission: documents.send
Sends a draft document to its recipient. The document must be in draft or viewed status and must have a recipient assigned.
Example Request
curl -X POST "https://your-domain.com/api/v1/documents/42/send" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"const response = await fetch("https://your-domain.com/api/v1/documents/42/send", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_TOKEN",
"Accept": "application/json"
}
});
const data = await response.json();$ch = curl_init("https://your-domain.com/api/v1/documents/42/send");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer YOUR_API_TOKEN",
"Accept: application/json",
],
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);import requests
response = requests.post(
"https://your-domain.com/api/v1/documents/42/send",
headers={
"Authorization": "Bearer YOUR_API_TOKEN",
"Accept": "application/json"
}
)
data = response.json()Example Response
{
"data": {
"id": 42,
"type": "invoice",
"number": "INV-0042",
"title": "March Services",
"status": "sent",
"total": "1500.00",
"sent_at": "2025-06-02T10:30:00.000000Z",
"created_at": "2025-06-01T09:00:00.000000Z",
"updated_at": "2025-06-02T10:30:00.000000Z"
}
}
Returns 422 if the document is not in a sendable status or has no recipient.
Void Document
POST /api/v1/documents/{id}/void — Permission: documents.void
Voids a document and any subsequent workflow steps. Cannot void documents that are already void, cancelled, paid, or refunded. Documents with partial payments must be refunded first.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
void_reason | string | No | Reason for voiding (max 500 characters) |
Example Request
curl -X POST "https://your-domain.com/api/v1/documents/42/void" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"void_reason": "Client requested cancellation"}'const response = await fetch("https://your-domain.com/api/v1/documents/42/void", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_TOKEN",
"Accept": "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify({ void_reason: "Client requested cancellation" })
});
const data = await response.json();$ch = curl_init("https://your-domain.com/api/v1/documents/42/void");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode(["void_reason" => "Client requested cancellation"]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer YOUR_API_TOKEN",
"Accept: application/json",
"Content-Type: application/json",
],
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);import requests
response = requests.post(
"https://your-domain.com/api/v1/documents/42/void",
headers={
"Authorization": "Bearer YOUR_API_TOKEN",
"Accept": "application/json"
},
json={"void_reason": "Client requested cancellation"}
)
data = response.json()Example Response
{
"data": {
"id": 42,
"type": "invoice",
"number": "INV-0042",
"status": "void",
"total": "1500.00",
"created_at": "2025-06-01T09:00:00.000000Z",
"updated_at": "2025-06-02T11:00:00.000000Z"
}
}
Returns 422 if the document cannot be voided in its current status.
Was this article helpful?