Skip to main content
POST
Create and send many envelopes from one template, in one request.

Authorizations

Authorization
string
header
required

Authorization: Bearer vsk_live_…. Chosen over a bespoke X-API-KEY header because every client, proxy and log-redaction rule already knows this one. What a key may DO is its scopes — see x-scopes at the root of this document and x-required-scope on each operation. The scope list is not written here because OpenAPI reserves a requirement’s scope array for oauth2 and openIdConnect and requires it to be empty for an http scheme.

Headers

Idempotency-Key
string
required

Any string that identifies this request; at most 255 characters. ⚠️ REQUIRED, and this is the endpoint it matters most on: without it a timeout is unresolvable and a retry creates a second hundred envelopes and emails everybody in them twice. The caller’s own request identifier.

Example:

"01960000-0000-4000-8000-00000000ffff"

Body

application/json

The template, the rows, and whether to send.

The request.

template_id
string<uuid>
required

The template every row instantiates. ⚠️ BATCH-LEVEL, AND ONE TEMPLATE IS THE FEATURE — a request that could name a different template per row would be POST /api/v1/envelopes in a loop with the loop moved inside our process.

Example:

"01960000-0000-4000-8000-0000000007e1"

rows
object[]
required

The recipient sets, one envelope each, in order. ⚠️ AT MOST 100 ROWS AND AT MOST 1000 RECIPIENTS IN TOTAL ACROSS THEM; either bound is invalid_request and nothing is created. results[i] in the response is what happened to rows[i], and every result also carries its own index.

send
boolean

Optional, default false, and it applies to the whole batch. False creates the drafts and emails nobody; true sends every row, consuming one unit of the plan’s allowance per envelope.

expires_at
string<date-time> | null

Optional, default null. One deadline for every envelope in the batch. Same rules as on POST /api/v1/envelopes: an absolute ISO 8601 instant, at least 1 hour and at most 365 days out.

brand_id
string<uuid> | null

Optional, default null — the organisation’s default brand. Which brand the envelope goes out under: the letterhead, the colours and the sending name a signer sees. ⚠️ THIS IS THE FIELD FOR SENDING ON BEHALF OF MANY CUSTOMER BRANDS FROM ONE ACCOUNT — change it between calls and the same integration sends Customer A’s paperwork under Customer A’s brand and Customer B’s under Customer B’s.

⚠️ AN ID THAT NAMES NO LIVE BRAND OF YOUR ORGANISATION IS REFUSED WITH brand_unknown, NOT IGNORED — including one that has been archived. The branding an envelope went out under is frozen the moment it is sent and cannot be corrected afterwards, so a wrong constant in your configuration would otherwise put somebody else’s letterhead on every envelope you ever send and nothing would say so.

It is recorded on the envelope, so a draft created with send: false still goes out under this brand when it is sent later.

⚠️ PER BATCH, NOT PER ROW. One request sends under one brand — which is the reseller case exactly, since a batch already names one template and two customers do not share one. Two brands means two batches. A row-level override remains additive if that ever changes.

completion_delivery
enum<string>

Who tells the recipients the envelope is done and sends them the executed document. vumasign (the default for a send from the dashboard) means we email the sender and every recipient we are able to email, with the sealed PDF attached. integrator (the default for a send made with an API key) means we send nothing at completion and you do it. Omit it and the origin of the send decides — an envelope created with send: false and then sent from the dashboard is vumasign. It cannot be changed once the envelope has been sent.

⚠️ AN embedded RECIPIENT IS NEVER EMAILED, WHATEVER THIS SAYS. We issue one no signing link and send them no invitation, because their address may be an identifier of yours rather than a mailbox — so they are not sent the completed document either, even under vumasign. Delivering the executed document to an embedded recipient is yours on every envelope, and this field only decides who tells everybody else.

⚠️ IF YOU TAKE THIS ON, SUBSCRIBE TO envelope.sealed RATHER THAN envelope.completed. envelope.completed fires when the last person signs, which is about a minute before the executed document exists, and envelope.sealing_failed tells you it never will.

⚠️ PER BATCH, NOT PER ROW. One request is one answer, written onto every envelope it creates. Two answers means two batches. A row-level override remains additive if that ever changes.

Available options:
vumasign,
integrator

Response

Every row succeeded. failed is 0 and every results[i].error is null. Idempotency-Replayed says whether this request created the batch (false) or is being shown an earlier one’s result (true).

The batch.

batch_id
string<uuid>
required

This request’s own identifier, recorded on every envelope it created. There is no endpoint that takes it back — the answer is in your hand, and a caller who lost it replays their Idempotency-Key.

template_id
string<uuid>
required

The template every row was made from.

count
integer
required

How many envelopes exist. Always the number of rows in the request: every row produces an envelope, or the whole request is refused.

sent
integer
required

How many went out. Zero when send was false.

failed
integer
required

⚠️ THE ONE FIELD THAT ANSWERS "DID IT WORK", AND IT IS AN INTEGER RATHER THAN A WALK. Zero on a 201 and non-zero on a 207, always — so the status line and this number never disagree, and a client that reads neither the body nor this field still gets the truth from the status.

results
object[]
required

One entry per row, in the order the request listed them.