curl --request POST \
--url https://api.vaquill.ai/workspace/v1/templates \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"title": "Mutual NDA",
"contentMarkdown": "# Mutual Non-Disclosure Agreement\n\n## 1. Confidential Information\n\nEach party may disclose information that is confidential and proprietary to the other party.\n"
}
'import requests
url = "https://api.vaquill.ai/workspace/v1/templates"
payload = {
"title": "Mutual NDA",
"contentMarkdown": "# Mutual Non-Disclosure Agreement
## 1. Confidential Information
Each party may disclose information that is confidential and proprietary to the other party.
"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
title: 'Mutual NDA',
contentMarkdown: '# Mutual Non-Disclosure Agreement\n\n## 1. Confidential Information\n\nEach party may disclose information that is confidential and proprietary to the other party.\n'
})
};
fetch('https://api.vaquill.ai/workspace/v1/templates', 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://api.vaquill.ai/workspace/v1/templates"
payload := strings.NewReader("{\n \"title\": \"Mutual NDA\",\n \"contentMarkdown\": \"# Mutual Non-Disclosure Agreement\\n\\n## 1. Confidential Information\\n\\nEach party may disclose information that is confidential and proprietary to the other party.\\n\"\n}")
req, _ := http.NewRequest("POST", url, payload)
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": "tpl_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6",
"title": "Master Services Agreement",
"description": "Master services agreement with Acme for the 2026 platform rollout.",
"category": "commercial",
"sourceFilename": "msa-acme-v3.docx",
"createdAt": "2026-08-19T14:32:10Z",
"updatedAt": "2026-08-19T14:32:10Z",
"variables": [
{
"id": "party_a_name",
"name": "Counterparty name",
"label": "Counterparty name",
"kind": "matrix",
"hint": "value",
"defaultValue": "value",
"position": 0
}
],
"sections": [
{
"heading": "8. Limitation of Liability",
"level": 1,
"text": "Neither party shall be liable for indirect or consequential damages."
}
]
}{
"type": "https://vaquill.ai/docs/workspace-api/errors/insufficient-scope",
"title": "Insufficient scope",
"status": 403,
"detail": "This credential carries matters:read. This operation needs matters:write.",
"instance": "/workspace/v1/matters/mat_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6",
"requestId": "req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6"
}{
"type": "https://vaquill.ai/docs/workspace-api/errors/insufficient-scope",
"title": "Insufficient scope",
"status": 403,
"detail": "This credential carries matters:read. This operation needs matters:write.",
"instance": "/workspace/v1/matters/mat_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6",
"requestId": "req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6"
}{
"type": "https://vaquill.ai/docs/workspace-api/errors/insufficient-scope",
"title": "Insufficient scope",
"status": 403,
"detail": "This credential carries matters:read. This operation needs matters:write.",
"instance": "/workspace/v1/matters/mat_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6",
"errors": [
{
"location": "<string>",
"message": "<string>",
"type": "<string>"
}
],
"requestId": "req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6"
}{
"type": "https://vaquill.ai/docs/workspace-api/errors/insufficient-scope",
"title": "Insufficient scope",
"status": 403,
"detail": "This credential carries matters:read. This operation needs matters:write.",
"instance": "/workspace/v1/matters/mat_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6",
"requestId": "req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6"
}{
"type": "https://vaquill.ai/docs/workspace-api/errors/insufficient-scope",
"title": "Insufficient scope",
"status": 403,
"detail": "This credential carries matters:read. This operation needs matters:write.",
"instance": "/workspace/v1/matters/mat_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6",
"requestId": "req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6"
}{
"type": "https://vaquill.ai/docs/workspace-api/errors/insufficient-scope",
"title": "Insufficient scope",
"status": 403,
"detail": "This credential carries matters:read. This operation needs matters:write.",
"instance": "/workspace/v1/matters/mat_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6",
"requestId": "req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6"
}Create a template from markdown
Author a template from markdown.
Fillable spans are detected as part of this call and returned in
variables, so a template created here can never be one that runs and
interpolates nothing. Detection is a deterministic regex pass over the text:
[BRACKETED PLACEHOLDERS], {{jinja_fields}}, <<mergefields>>, runs of
underscores, dates, amounts and durations. The product also runs an LLM
refinement pass over an upload and this API does not, so a template created
here may carry fewer variables than the same text imported in the browser.
curl --request POST \
--url https://api.vaquill.ai/workspace/v1/templates \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"title": "Mutual NDA",
"contentMarkdown": "# Mutual Non-Disclosure Agreement\n\n## 1. Confidential Information\n\nEach party may disclose information that is confidential and proprietary to the other party.\n"
}
'import requests
url = "https://api.vaquill.ai/workspace/v1/templates"
payload = {
"title": "Mutual NDA",
"contentMarkdown": "# Mutual Non-Disclosure Agreement
## 1. Confidential Information
Each party may disclose information that is confidential and proprietary to the other party.
"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
title: 'Mutual NDA',
contentMarkdown: '# Mutual Non-Disclosure Agreement\n\n## 1. Confidential Information\n\nEach party may disclose information that is confidential and proprietary to the other party.\n'
})
};
fetch('https://api.vaquill.ai/workspace/v1/templates', 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://api.vaquill.ai/workspace/v1/templates"
payload := strings.NewReader("{\n \"title\": \"Mutual NDA\",\n \"contentMarkdown\": \"# Mutual Non-Disclosure Agreement\\n\\n## 1. Confidential Information\\n\\nEach party may disclose information that is confidential and proprietary to the other party.\\n\"\n}")
req, _ := http.NewRequest("POST", url, payload)
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": "tpl_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6",
"title": "Master Services Agreement",
"description": "Master services agreement with Acme for the 2026 platform rollout.",
"category": "commercial",
"sourceFilename": "msa-acme-v3.docx",
"createdAt": "2026-08-19T14:32:10Z",
"updatedAt": "2026-08-19T14:32:10Z",
"variables": [
{
"id": "party_a_name",
"name": "Counterparty name",
"label": "Counterparty name",
"kind": "matrix",
"hint": "value",
"defaultValue": "value",
"position": 0
}
],
"sections": [
{
"heading": "8. Limitation of Liability",
"level": 1,
"text": "Neither party shall be liable for indirect or consequential damages."
}
]
}{
"type": "https://vaquill.ai/docs/workspace-api/errors/insufficient-scope",
"title": "Insufficient scope",
"status": 403,
"detail": "This credential carries matters:read. This operation needs matters:write.",
"instance": "/workspace/v1/matters/mat_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6",
"requestId": "req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6"
}{
"type": "https://vaquill.ai/docs/workspace-api/errors/insufficient-scope",
"title": "Insufficient scope",
"status": 403,
"detail": "This credential carries matters:read. This operation needs matters:write.",
"instance": "/workspace/v1/matters/mat_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6",
"requestId": "req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6"
}{
"type": "https://vaquill.ai/docs/workspace-api/errors/insufficient-scope",
"title": "Insufficient scope",
"status": 403,
"detail": "This credential carries matters:read. This operation needs matters:write.",
"instance": "/workspace/v1/matters/mat_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6",
"errors": [
{
"location": "<string>",
"message": "<string>",
"type": "<string>"
}
],
"requestId": "req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6"
}{
"type": "https://vaquill.ai/docs/workspace-api/errors/insufficient-scope",
"title": "Insufficient scope",
"status": 403,
"detail": "This credential carries matters:read. This operation needs matters:write.",
"instance": "/workspace/v1/matters/mat_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6",
"requestId": "req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6"
}{
"type": "https://vaquill.ai/docs/workspace-api/errors/insufficient-scope",
"title": "Insufficient scope",
"status": 403,
"detail": "This credential carries matters:read. This operation needs matters:write.",
"instance": "/workspace/v1/matters/mat_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6",
"requestId": "req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6"
}{
"type": "https://vaquill.ai/docs/workspace-api/errors/insufficient-scope",
"title": "Insufficient scope",
"status": 403,
"detail": "This credential carries matters:read. This operation needs matters:write.",
"instance": "/workspace/v1/matters/mat_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6",
"requestId": "req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6"
}Authorizations
Workspace credential issued from the automation console at /automation. Send it as Authorization: Bearer vq_ws_.... This is NOT a Data API key: a vq_key_ credential is refused here and names the other product in the error.
Body
Author a template from markdown you supply.
Variables are detected for you, on this call, and the response carries
what was found. A placeholder written as [COUNTERPARTY NAME],
{{party_a}} or a run of underscores survives the markdown round trip as
literal characters, and the detector re-derives the mark from it, so a
template authored here cannot land in the state where it runs and
interpolates nothing.
Detection is regex over the flattened text: deterministic, free and
sub-millisecond. The product also has an LLM refinement pass and this API
does not run it, so a template imported here may detect fewer variables than
the same file imported in the browser. It refines display NAMES and adds
spans the regex missed; the identifiers slotOverrides is keyed by are
deliberately left alone by it either way.
Display name for the template.
1 - 300"Mutual NDA"
The template body as markdown, placeholders included. Whitespace alone is refused: the converter answers it with a valid EMPTY document, which would be a template that renders a blank page.
1 - 500000"# Mutual Non-Disclosure Agreement\n\n## 1. Confidential Information\n\nEach party may disclose information that is confidential and proprietary to the other party.\n"
What this template is for, in your own words.
2000"Master services agreement with Acme for the 2026 platform rollout."
How you classify this template. Defaults to custom; free-form, not a drafting category.
1 - 100"commercial"
Response
Successful Response
One template with everything needed to run it without guessing.
variables is the reason this model exists at all, and sections is here
for the same reason a draft publishes them: a caller deciding WHICH template
to run needs to read what it says, and the editor's own document model does
not cross this boundary in either direction.
Public identifier, tpl_ followed by 32 hex characters. Name it when starting a run.
"tpl_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6"
The template's display name.
"Master Services Agreement"
The template's category, as the customer classified it on upload.
"commercial"
When the template was created (RFC 3339).
"2026-08-19T14:32:10Z"
When the template was last modified (RFC 3339).
"2026-08-19T14:32:10Z"
Every fillable span, in document order. The id of each is what slotOverrides on a run is keyed by.
Show child attributes
Show child attributes
The template body, section by section, with the placeholder text left in place. Send a replacement as contentMarkdown.
Show child attributes
Show child attributes
Free-text description of what the template is for.
"Master services agreement with Acme for the 2026 platform rollout."
Filename of the document this template was created from. Published because it is how a person recognizes which template a run used, months later.
"msa-acme-v3.docx"
Was this page helpful?

