curl --request POST \
--url https://app.vumasign.com/api/v1/envelopes/one-off \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"title": "Offer of employment — A. Dlamini",
"documents": [
{
"content": "JVBERi0xLjcKJYGBgYEKCjUgMCBvYmoKPDwKL0ZpbHRlciAvRmxhdGVEZWNvZGUKL0xlbmd0aCAxODAKPj4Kc3RyZWFtCnicjc9LCgIxDAbgfU7RtSCmj/xpQYRxrLhwI/QCIiqKLhTx/HbGlYOCLQkpDf3SG80Lsen2/UiT1f7y3D9Ou+1YOcUQWWMyFqYcyAVT1mT7VmvARmuUK03DEt0SdY5R65oFC2W0WGrCop6yhpkpZyojyoU2dPulJg0O0QmisfarinrVqeKRoMj19VBFp8mxBkTIwBeIb/7THTNHlhTxU5f3n33rW+0n8E0YatnnD+8FYlhOhwplbmRzdHJlYW0KZW5kb2JqCgo2IDAgb2JqCjw8Ci9GaWx0ZXIgL0ZsYXRlRGVjb2RlCi9UeXBlIC9PYmpTdG0KL04gNAovRmlyc3QgMjAKL0xlbmd0aCAyNjMKPj4Kc3RyZWFtCnicZVDRSgMxEHzPV+wP2E1i7i4HpdCWVkFEaYUK4kN6F46UkkgvJ/XvzcbTUiQv2Z3Zmd0RwEGCUnALlQYFouQwnTJ8+fqwgM+msz3DB9f28JZQDht4Z7gMg48g2GzGLtylieYYOvYzBILI14x18JHhdtjHXFJTMFyY3hICeG+Pnza6xjBc+Sa0zneAO+fnvne/jWtFsiLDk6V9siNubB+GU5NWIF5Wps+f+E3Fa600r3Sdjs4jF6yulCy1LEr9H5Occ82LWpcjllbB16f9wTbZgsrVOd5to4l2bFDv0bbOLMI5JcjTK+piIjVoJSZpg5Tm3PsQKd+crI/pFqqKMe0k8Q0eU3JYCmVuZHN0cmVhbQplbmRvYmoKCjcgMCBvYmoKPDwKL1NpemUgOAovUm9vdCAyIDAgUgovRmlsdGVyIC9GbGF0ZURlY29kZQovVHlwZSAvWFJlZgovTGVuZ3RoIDM4Ci9XIFsgMSAyIDIgXQovSW5kZXggWyAwIDggXQo+PgpzdHJlYW0KeJwVxMEJADAMA7GzC/kVOm+WT2M9BMyYgqTkdMQD6W5u+E9oAsIKZW5kc3RyZWFtCmVuZG9iagoKc3RhcnR4cmVmCjYzNAolJUVPRg=="
}
],
"recipients": [
{
"role": "Employee",
"name": "A. Dlamini",
"email": "a.dlamini@example.test",
"routing_type": "sign",
"embedded": true,
"external_ref": "usr_88213"
}
]
}
'import requests
url = "https://app.vumasign.com/api/v1/envelopes/one-off"
payload = {
"title": "Offer of employment — A. Dlamini",
"documents": [{ "content": "JVBERi0xLjcKJYGBgYEKCjUgMCBvYmoKPDwKL0ZpbHRlciAvRmxhdGVEZWNvZGUKL0xlbmd0aCAxODAKPj4Kc3RyZWFtCnicjc9LCgIxDAbgfU7RtSCmj/xpQYRxrLhwI/QCIiqKLhTx/HbGlYOCLQkpDf3SG80Lsen2/UiT1f7y3D9Ou+1YOcUQWWMyFqYcyAVT1mT7VmvARmuUK03DEt0SdY5R65oFC2W0WGrCop6yhpkpZyojyoU2dPulJg0O0QmisfarinrVqeKRoMj19VBFp8mxBkTIwBeIb/7THTNHlhTxU5f3n33rW+0n8E0YatnnD+8FYlhOhwplbmRzdHJlYW0KZW5kb2JqCgo2IDAgb2JqCjw8Ci9GaWx0ZXIgL0ZsYXRlRGVjb2RlCi9UeXBlIC9PYmpTdG0KL04gNAovRmlyc3QgMjAKL0xlbmd0aCAyNjMKPj4Kc3RyZWFtCnicZVDRSgMxEHzPV+wP2E1i7i4HpdCWVkFEaYUK4kN6F46UkkgvJ/XvzcbTUiQv2Z3Zmd0RwEGCUnALlQYFouQwnTJ8+fqwgM+msz3DB9f28JZQDht4Z7gMg48g2GzGLtylieYYOvYzBILI14x18JHhdtjHXFJTMFyY3hICeG+Pnza6xjBc+Sa0zneAO+fnvne/jWtFsiLDk6V9siNubB+GU5NWIF5Wps+f+E3Fa600r3Sdjs4jF6yulCy1LEr9H5Occ82LWpcjllbB16f9wTbZgsrVOd5to4l2bFDv0bbOLMI5JcjTK+piIjVoJSZpg5Tm3PsQKd+crI/pFqqKMe0k8Q0eU3JYCmVuZHN0cmVhbQplbmRvYmoKCjcgMCBvYmoKPDwKL1NpemUgOAovUm9vdCAyIDAgUgovRmlsdGVyIC9GbGF0ZURlY29kZQovVHlwZSAvWFJlZgovTGVuZ3RoIDM4Ci9XIFsgMSAyIDIgXQovSW5kZXggWyAwIDggXQo+PgpzdHJlYW0KeJwVxMEJADAMA7GzC/kVOm+WT2M9BMyYgqTkdMQD6W5u+E9oAsIKZW5kc3RyZWFtCmVuZG9iagoKc3RhcnR4cmVmCjYzNAolJUVPRg==" }],
"recipients": [
{
"role": "Employee",
"name": "A. Dlamini",
"email": "a.dlamini@example.test",
"routing_type": "sign",
"embedded": True,
"external_ref": "usr_88213"
}
]
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
title: 'Offer of employment — A. Dlamini',
documents: [
{
content: 'JVBERi0xLjcKJYGBgYEKCjUgMCBvYmoKPDwKL0ZpbHRlciAvRmxhdGVEZWNvZGUKL0xlbmd0aCAxODAKPj4Kc3RyZWFtCnicjc9LCgIxDAbgfU7RtSCmj/xpQYRxrLhwI/QCIiqKLhTx/HbGlYOCLQkpDf3SG80Lsen2/UiT1f7y3D9Ou+1YOcUQWWMyFqYcyAVT1mT7VmvARmuUK03DEt0SdY5R65oFC2W0WGrCop6yhpkpZyojyoU2dPulJg0O0QmisfarinrVqeKRoMj19VBFp8mxBkTIwBeIb/7THTNHlhTxU5f3n33rW+0n8E0YatnnD+8FYlhOhwplbmRzdHJlYW0KZW5kb2JqCgo2IDAgb2JqCjw8Ci9GaWx0ZXIgL0ZsYXRlRGVjb2RlCi9UeXBlIC9PYmpTdG0KL04gNAovRmlyc3QgMjAKL0xlbmd0aCAyNjMKPj4Kc3RyZWFtCnicZVDRSgMxEHzPV+wP2E1i7i4HpdCWVkFEaYUK4kN6F46UkkgvJ/XvzcbTUiQv2Z3Zmd0RwEGCUnALlQYFouQwnTJ8+fqwgM+msz3DB9f28JZQDht4Z7gMg48g2GzGLtylieYYOvYzBILI14x18JHhdtjHXFJTMFyY3hICeG+Pnza6xjBc+Sa0zneAO+fnvne/jWtFsiLDk6V9siNubB+GU5NWIF5Wps+f+E3Fa600r3Sdjs4jF6yulCy1LEr9H5Occ82LWpcjllbB16f9wTbZgsrVOd5to4l2bFDv0bbOLMI5JcjTK+piIjVoJSZpg5Tm3PsQKd+crI/pFqqKMe0k8Q0eU3JYCmVuZHN0cmVhbQplbmRvYmoKCjcgMCBvYmoKPDwKL1NpemUgOAovUm9vdCAyIDAgUgovRmlsdGVyIC9GbGF0ZURlY29kZQovVHlwZSAvWFJlZgovTGVuZ3RoIDM4Ci9XIFsgMSAyIDIgXQovSW5kZXggWyAwIDggXQo+PgpzdHJlYW0KeJwVxMEJADAMA7GzC/kVOm+WT2M9BMyYgqTkdMQD6W5u+E9oAsIKZW5kc3RyZWFtCmVuZG9iagoKc3RhcnR4cmVmCjYzNAolJUVPRg=='
}
],
recipients: [
{
role: 'Employee',
name: 'A. Dlamini',
email: 'a.dlamini@example.test',
routing_type: 'sign',
embedded: true,
external_ref: 'usr_88213'
}
]
})
};
fetch('https://app.vumasign.com/api/v1/envelopes/one-off', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.vumasign.com/api/v1/envelopes/one-off"
payload := strings.NewReader("{\n \"title\": \"Offer of employment — A. Dlamini\",\n \"documents\": [\n {\n \"content\": \"JVBERi0xLjcKJYGBgYEKCjUgMCBvYmoKPDwKL0ZpbHRlciAvRmxhdGVEZWNvZGUKL0xlbmd0aCAxODAKPj4Kc3RyZWFtCnicjc9LCgIxDAbgfU7RtSCmj/xpQYRxrLhwI/QCIiqKLhTx/HbGlYOCLQkpDf3SG80Lsen2/UiT1f7y3D9Ou+1YOcUQWWMyFqYcyAVT1mT7VmvARmuUK03DEt0SdY5R65oFC2W0WGrCop6yhpkpZyojyoU2dPulJg0O0QmisfarinrVqeKRoMj19VBFp8mxBkTIwBeIb/7THTNHlhTxU5f3n33rW+0n8E0YatnnD+8FYlhOhwplbmRzdHJlYW0KZW5kb2JqCgo2IDAgb2JqCjw8Ci9GaWx0ZXIgL0ZsYXRlRGVjb2RlCi9UeXBlIC9PYmpTdG0KL04gNAovRmlyc3QgMjAKL0xlbmd0aCAyNjMKPj4Kc3RyZWFtCnicZVDRSgMxEHzPV+wP2E1i7i4HpdCWVkFEaYUK4kN6F46UkkgvJ/XvzcbTUiQv2Z3Zmd0RwEGCUnALlQYFouQwnTJ8+fqwgM+msz3DB9f28JZQDht4Z7gMg48g2GzGLtylieYYOvYzBILI14x18JHhdtjHXFJTMFyY3hICeG+Pnza6xjBc+Sa0zneAO+fnvne/jWtFsiLDk6V9siNubB+GU5NWIF5Wps+f+E3Fa600r3Sdjs4jF6yulCy1LEr9H5Occ82LWpcjllbB16f9wTbZgsrVOd5to4l2bFDv0bbOLMI5JcjTK+piIjVoJSZpg5Tm3PsQKd+crI/pFqqKMe0k8Q0eU3JYCmVuZHN0cmVhbQplbmRvYmoKCjcgMCBvYmoKPDwKL1NpemUgOAovUm9vdCAyIDAgUgovRmlsdGVyIC9GbGF0ZURlY29kZQovVHlwZSAvWFJlZgovTGVuZ3RoIDM4Ci9XIFsgMSAyIDIgXQovSW5kZXggWyAwIDggXQo+PgpzdHJlYW0KeJwVxMEJADAMA7GzC/kVOm+WT2M9BMyYgqTkdMQD6W5u+E9oAsIKZW5kc3RyZWFtCmVuZG9iagoKc3RhcnR4cmVmCjYzNAolJUVPRg==\"\n }\n ],\n \"recipients\": [\n {\n \"role\": \"Employee\",\n \"name\": \"A. Dlamini\",\n \"email\": \"a.dlamini@example.test\",\n \"routing_type\": \"sign\",\n \"embedded\": true,\n \"external_ref\": \"usr_88213\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}{
"id": "01960000-0000-4000-8000-0000000000e7",
"status": "sent",
"template_id": null,
"title": "Offer of employment — A. Dlamini",
"created_at": "2026-09-02T10:00:00.000Z",
"sent_at": "2026-09-02T10:00:01.000Z",
"expires_at": null,
"recipients": [
{
"id": "01960000-0000-4000-8000-000000000060",
"role": "Employee",
"name": "A. Dlamini",
"email": "a.dlamini@example.test",
"routing_type": "sign",
"status": "sent",
"invitation_delivered": null,
"embedded": true,
"external_ref": "usr_88213"
}
]
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}Send a document that is not a template, and optionally send it.
THE ENDPOINT FOR A DOCUMENT THAT EXISTS ONCE — a Letter of Authority, an offer of employment, anything addressed to one person and never reused.
⚠️ IT MAKES NO TEMPLATE, WHICH IS THE POINT. template_id comes back null. Registering a single-use document as a template to send it would leave one behind on every send, and this API has no way to delete one.
LAYOUT COMES FROM THE DOCUMENT’S OWN TEXT TAGS. Write <<sig:Employee>> where a signature goes and give a recipient the role Employee; the field is placed where the tag is. A tag naming a role no recipient holds is refused, with the tag, its page, and the roles the request does declare — because fields.role_name is matched to recipients.role_name by nothing the database checks, so a tag naming the PERSON would bind a field to a slot nobody holds, silently.
EVERY TAG REFUSAL COMES BACK AT ONCE, not the first, so a document with four bad tags is one correction round rather than four. And a refusal creates nothing: no envelope, no recipients, no stored documents.
✅ A PDF OR A WORD .docx, CHECKED BY THE BYTES. A Word document is accepted and converted to PDF on our side, so a docxtemplater or Word pipeline uploads the .docx it already has — text tags survive that render, and it is now our render. The envelope is over the converted PDF: that is what page numbers and field coordinates refer to, and it is what a signer sees. The .docx you sent is retained unchanged and is not what anybody signs. The older .doc format is not accepted.
A REPLAY RETURNS THE SAME ENVELOPE AND CREATES NOTHING, exactly as POST /api/v1/envelopes does. ⚠️ Reordering recipients is a DIFFERENT request and will not replay across, because that order is the routing order.
NO SIGNING URLS ARE RETURNED. Ask for one with POST /api/v1/envelopes/{envelopeId}/recipients/{recipientId}/signing-url when that signer is ready — minting them here would start every single-use URL’s expiry clock at creation, for people who may be days apart in the order.
curl --request POST \
--url https://app.vumasign.com/api/v1/envelopes/one-off \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"title": "Offer of employment — A. Dlamini",
"documents": [
{
"content": "JVBERi0xLjcKJYGBgYEKCjUgMCBvYmoKPDwKL0ZpbHRlciAvRmxhdGVEZWNvZGUKL0xlbmd0aCAxODAKPj4Kc3RyZWFtCnicjc9LCgIxDAbgfU7RtSCmj/xpQYRxrLhwI/QCIiqKLhTx/HbGlYOCLQkpDf3SG80Lsen2/UiT1f7y3D9Ou+1YOcUQWWMyFqYcyAVT1mT7VmvARmuUK03DEt0SdY5R65oFC2W0WGrCop6yhpkpZyojyoU2dPulJg0O0QmisfarinrVqeKRoMj19VBFp8mxBkTIwBeIb/7THTNHlhTxU5f3n33rW+0n8E0YatnnD+8FYlhOhwplbmRzdHJlYW0KZW5kb2JqCgo2IDAgb2JqCjw8Ci9GaWx0ZXIgL0ZsYXRlRGVjb2RlCi9UeXBlIC9PYmpTdG0KL04gNAovRmlyc3QgMjAKL0xlbmd0aCAyNjMKPj4Kc3RyZWFtCnicZVDRSgMxEHzPV+wP2E1i7i4HpdCWVkFEaYUK4kN6F46UkkgvJ/XvzcbTUiQv2Z3Zmd0RwEGCUnALlQYFouQwnTJ8+fqwgM+msz3DB9f28JZQDht4Z7gMg48g2GzGLtylieYYOvYzBILI14x18JHhdtjHXFJTMFyY3hICeG+Pnza6xjBc+Sa0zneAO+fnvne/jWtFsiLDk6V9siNubB+GU5NWIF5Wps+f+E3Fa600r3Sdjs4jF6yulCy1LEr9H5Occ82LWpcjllbB16f9wTbZgsrVOd5to4l2bFDv0bbOLMI5JcjTK+piIjVoJSZpg5Tm3PsQKd+crI/pFqqKMe0k8Q0eU3JYCmVuZHN0cmVhbQplbmRvYmoKCjcgMCBvYmoKPDwKL1NpemUgOAovUm9vdCAyIDAgUgovRmlsdGVyIC9GbGF0ZURlY29kZQovVHlwZSAvWFJlZgovTGVuZ3RoIDM4Ci9XIFsgMSAyIDIgXQovSW5kZXggWyAwIDggXQo+PgpzdHJlYW0KeJwVxMEJADAMA7GzC/kVOm+WT2M9BMyYgqTkdMQD6W5u+E9oAsIKZW5kc3RyZWFtCmVuZG9iagoKc3RhcnR4cmVmCjYzNAolJUVPRg=="
}
],
"recipients": [
{
"role": "Employee",
"name": "A. Dlamini",
"email": "a.dlamini@example.test",
"routing_type": "sign",
"embedded": true,
"external_ref": "usr_88213"
}
]
}
'import requests
url = "https://app.vumasign.com/api/v1/envelopes/one-off"
payload = {
"title": "Offer of employment — A. Dlamini",
"documents": [{ "content": "JVBERi0xLjcKJYGBgYEKCjUgMCBvYmoKPDwKL0ZpbHRlciAvRmxhdGVEZWNvZGUKL0xlbmd0aCAxODAKPj4Kc3RyZWFtCnicjc9LCgIxDAbgfU7RtSCmj/xpQYRxrLhwI/QCIiqKLhTx/HbGlYOCLQkpDf3SG80Lsen2/UiT1f7y3D9Ou+1YOcUQWWMyFqYcyAVT1mT7VmvARmuUK03DEt0SdY5R65oFC2W0WGrCop6yhpkpZyojyoU2dPulJg0O0QmisfarinrVqeKRoMj19VBFp8mxBkTIwBeIb/7THTNHlhTxU5f3n33rW+0n8E0YatnnD+8FYlhOhwplbmRzdHJlYW0KZW5kb2JqCgo2IDAgb2JqCjw8Ci9GaWx0ZXIgL0ZsYXRlRGVjb2RlCi9UeXBlIC9PYmpTdG0KL04gNAovRmlyc3QgMjAKL0xlbmd0aCAyNjMKPj4Kc3RyZWFtCnicZVDRSgMxEHzPV+wP2E1i7i4HpdCWVkFEaYUK4kN6F46UkkgvJ/XvzcbTUiQv2Z3Zmd0RwEGCUnALlQYFouQwnTJ8+fqwgM+msz3DB9f28JZQDht4Z7gMg48g2GzGLtylieYYOvYzBILI14x18JHhdtjHXFJTMFyY3hICeG+Pnza6xjBc+Sa0zneAO+fnvne/jWtFsiLDk6V9siNubB+GU5NWIF5Wps+f+E3Fa600r3Sdjs4jF6yulCy1LEr9H5Occ82LWpcjllbB16f9wTbZgsrVOd5to4l2bFDv0bbOLMI5JcjTK+piIjVoJSZpg5Tm3PsQKd+crI/pFqqKMe0k8Q0eU3JYCmVuZHN0cmVhbQplbmRvYmoKCjcgMCBvYmoKPDwKL1NpemUgOAovUm9vdCAyIDAgUgovRmlsdGVyIC9GbGF0ZURlY29kZQovVHlwZSAvWFJlZgovTGVuZ3RoIDM4Ci9XIFsgMSAyIDIgXQovSW5kZXggWyAwIDggXQo+PgpzdHJlYW0KeJwVxMEJADAMA7GzC/kVOm+WT2M9BMyYgqTkdMQD6W5u+E9oAsIKZW5kc3RyZWFtCmVuZG9iagoKc3RhcnR4cmVmCjYzNAolJUVPRg==" }],
"recipients": [
{
"role": "Employee",
"name": "A. Dlamini",
"email": "a.dlamini@example.test",
"routing_type": "sign",
"embedded": True,
"external_ref": "usr_88213"
}
]
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
title: 'Offer of employment — A. Dlamini',
documents: [
{
content: 'JVBERi0xLjcKJYGBgYEKCjUgMCBvYmoKPDwKL0ZpbHRlciAvRmxhdGVEZWNvZGUKL0xlbmd0aCAxODAKPj4Kc3RyZWFtCnicjc9LCgIxDAbgfU7RtSCmj/xpQYRxrLhwI/QCIiqKLhTx/HbGlYOCLQkpDf3SG80Lsen2/UiT1f7y3D9Ou+1YOcUQWWMyFqYcyAVT1mT7VmvARmuUK03DEt0SdY5R65oFC2W0WGrCop6yhpkpZyojyoU2dPulJg0O0QmisfarinrVqeKRoMj19VBFp8mxBkTIwBeIb/7THTNHlhTxU5f3n33rW+0n8E0YatnnD+8FYlhOhwplbmRzdHJlYW0KZW5kb2JqCgo2IDAgb2JqCjw8Ci9GaWx0ZXIgL0ZsYXRlRGVjb2RlCi9UeXBlIC9PYmpTdG0KL04gNAovRmlyc3QgMjAKL0xlbmd0aCAyNjMKPj4Kc3RyZWFtCnicZVDRSgMxEHzPV+wP2E1i7i4HpdCWVkFEaYUK4kN6F46UkkgvJ/XvzcbTUiQv2Z3Zmd0RwEGCUnALlQYFouQwnTJ8+fqwgM+msz3DB9f28JZQDht4Z7gMg48g2GzGLtylieYYOvYzBILI14x18JHhdtjHXFJTMFyY3hICeG+Pnza6xjBc+Sa0zneAO+fnvne/jWtFsiLDk6V9siNubB+GU5NWIF5Wps+f+E3Fa600r3Sdjs4jF6yulCy1LEr9H5Occ82LWpcjllbB16f9wTbZgsrVOd5to4l2bFDv0bbOLMI5JcjTK+piIjVoJSZpg5Tm3PsQKd+crI/pFqqKMe0k8Q0eU3JYCmVuZHN0cmVhbQplbmRvYmoKCjcgMCBvYmoKPDwKL1NpemUgOAovUm9vdCAyIDAgUgovRmlsdGVyIC9GbGF0ZURlY29kZQovVHlwZSAvWFJlZgovTGVuZ3RoIDM4Ci9XIFsgMSAyIDIgXQovSW5kZXggWyAwIDggXQo+PgpzdHJlYW0KeJwVxMEJADAMA7GzC/kVOm+WT2M9BMyYgqTkdMQD6W5u+E9oAsIKZW5kc3RyZWFtCmVuZG9iagoKc3RhcnR4cmVmCjYzNAolJUVPRg=='
}
],
recipients: [
{
role: 'Employee',
name: 'A. Dlamini',
email: 'a.dlamini@example.test',
routing_type: 'sign',
embedded: true,
external_ref: 'usr_88213'
}
]
})
};
fetch('https://app.vumasign.com/api/v1/envelopes/one-off', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.vumasign.com/api/v1/envelopes/one-off"
payload := strings.NewReader("{\n \"title\": \"Offer of employment — A. Dlamini\",\n \"documents\": [\n {\n \"content\": \"JVBERi0xLjcKJYGBgYEKCjUgMCBvYmoKPDwKL0ZpbHRlciAvRmxhdGVEZWNvZGUKL0xlbmd0aCAxODAKPj4Kc3RyZWFtCnicjc9LCgIxDAbgfU7RtSCmj/xpQYRxrLhwI/QCIiqKLhTx/HbGlYOCLQkpDf3SG80Lsen2/UiT1f7y3D9Ou+1YOcUQWWMyFqYcyAVT1mT7VmvARmuUK03DEt0SdY5R65oFC2W0WGrCop6yhpkpZyojyoU2dPulJg0O0QmisfarinrVqeKRoMj19VBFp8mxBkTIwBeIb/7THTNHlhTxU5f3n33rW+0n8E0YatnnD+8FYlhOhwplbmRzdHJlYW0KZW5kb2JqCgo2IDAgb2JqCjw8Ci9GaWx0ZXIgL0ZsYXRlRGVjb2RlCi9UeXBlIC9PYmpTdG0KL04gNAovRmlyc3QgMjAKL0xlbmd0aCAyNjMKPj4Kc3RyZWFtCnicZVDRSgMxEHzPV+wP2E1i7i4HpdCWVkFEaYUK4kN6F46UkkgvJ/XvzcbTUiQv2Z3Zmd0RwEGCUnALlQYFouQwnTJ8+fqwgM+msz3DB9f28JZQDht4Z7gMg48g2GzGLtylieYYOvYzBILI14x18JHhdtjHXFJTMFyY3hICeG+Pnza6xjBc+Sa0zneAO+fnvne/jWtFsiLDk6V9siNubB+GU5NWIF5Wps+f+E3Fa600r3Sdjs4jF6yulCy1LEr9H5Occ82LWpcjllbB16f9wTbZgsrVOd5to4l2bFDv0bbOLMI5JcjTK+piIjVoJSZpg5Tm3PsQKd+crI/pFqqKMe0k8Q0eU3JYCmVuZHN0cmVhbQplbmRvYmoKCjcgMCBvYmoKPDwKL1NpemUgOAovUm9vdCAyIDAgUgovRmlsdGVyIC9GbGF0ZURlY29kZQovVHlwZSAvWFJlZgovTGVuZ3RoIDM4Ci9XIFsgMSAyIDIgXQovSW5kZXggWyAwIDggXQo+PgpzdHJlYW0KeJwVxMEJADAMA7GzC/kVOm+WT2M9BMyYgqTkdMQD6W5u+E9oAsIKZW5kc3RyZWFtCmVuZG9iagoKc3RhcnR4cmVmCjYzNAolJUVPRg==\"\n }\n ],\n \"recipients\": [\n {\n \"role\": \"Employee\",\n \"name\": \"A. Dlamini\",\n \"email\": \"a.dlamini@example.test\",\n \"routing_type\": \"sign\",\n \"embedded\": true,\n \"external_ref\": \"usr_88213\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}{
"id": "01960000-0000-4000-8000-0000000000e7",
"status": "sent",
"template_id": null,
"title": "Offer of employment — A. Dlamini",
"created_at": "2026-09-02T10:00:00.000Z",
"sent_at": "2026-09-02T10:00:01.000Z",
"expires_at": null,
"recipients": [
{
"id": "01960000-0000-4000-8000-000000000060",
"role": "Employee",
"name": "A. Dlamini",
"email": "a.dlamini@example.test",
"routing_type": "sign",
"status": "sent",
"invitation_delivered": null,
"embedded": true,
"external_ref": "usr_88213"
}
]
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}Authorizations
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
Any string that identifies this request; a UUID is the usual choice, and at most 255 characters. ⚠️ REQUIRED. Without it a timeout is unresolvable: you cannot learn whether the envelope was created, and retrying sends the same document a second time. The caller’s own request identifier.
"01960000-0000-4000-8000-00000000ffff"
Body
The documents, the people, and whether to send.
The request.
What the signers see naming the document. Required — there is no template to borrow a name from.
"Offer of employment — A. Dlamini"
The documents, base64-encoded, in the order a signer meets them. They are stacked into one scroll on the signing screen, and each is sealed on its own with its own Certificate of Completion. ⚠️ A PDF OR A WORD .docx, DECIDED BY THE BYTES AND NOT BY THE FILENAME — a .docx is converted to PDF on our side, and the envelope is over the converted PDF. Text tags survive that render, which is now OUR render rather than a step you take first. A tag addresses a page of the document it is written on, so <<sig:Employee>> on the annexure places a box on the annexure.
1 - 10 elementsShow child attributes
Show child attributes
⚠️ THE ORDER OF THIS ARRAY IS THE ROUTING ORDER, and each role is a slot a text tag can name — <<sig:Employee>> finds the recipient whose role is Employee. A tag naming anything else is refused rather than creating a role nobody fills.
1 - 100 elementsShow child attributes
Show child attributes
Which member of this organisation the signer is asked BY — it becomes the name on the invitation and on the Certificate of Completion. Omitted means the user who minted the key, which is a fallback rather than a choice: when that person leaves, every document still arrives from them.
"01960000-0000-4000-8000-000000000021"
Whether everyone is asked at once, or each in turn. Defaults to parallel.
parallel, sequential "sequential"
Optional, default false. False creates a draft and emails nobody; true sends it, consuming the plan’s allowance and delivering to whoever’s turn it is. Embedded recipients are never emailed either way.
false
When the envelope stops being signable. Omitted means it does not expire.
"2026-10-31T23:59:59Z"
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.
vumasign, integrator Response
The envelope, as it stands, with template_id null. Idempotency-Replayed says whether this request created it (false) or is being shown an earlier one’s result (true); the status is 201 either way, so a client branching on it behaves identically on a retry.
The envelope.
The envelope’s id. A bare uuid.
draft or sent from this endpoint. Later states arrive as people act.
The template this was made from, or null when there was none — an envelope created by POST /api/v1/envelopes/one-off carries the document itself and never had a template. Branch on null, never on the empty string.
What the signers see naming the document. Defaults to the template’s name.
ISO 8601, UTC.
ISO 8601, UTC. Null while it is a draft.
ISO 8601, UTC. Null when this envelope has no deadline, which is the default. Read back from the stored value rather than echoed, so an offset you sent comes back as the same instant in UTC.
In routing order.
Show child attributes
Show child attributes