curl --request PUT \
--url https://api.vaquill.ai/workspace/v1/templates/{templateId} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"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/{templateId}"
payload = { "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.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
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/{templateId}', 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/{templateId}"
payload := strings.NewReader("{\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("PUT", 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",
"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"
}Replace a template's body
Replace a template’s body, re-detecting its variables.
A PUT, not a PATCH: contentMarkdown is the whole body, so sending one
clause replaces the template with that clause. Title and description are
left alone when omitted.
This is lossy against a template imported from a .docx. Word
formatting the importer preserved cannot be expressed in markdown and is
discarded. Duplicate the template first if you want to keep the original.
curl --request PUT \
--url https://api.vaquill.ai/workspace/v1/templates/{templateId} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"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/{templateId}"
payload = { "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.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
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/{templateId}', 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/{templateId}"
payload := strings.NewReader("{\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("PUT", 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",
"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.
Path Parameters
tpl_ identifier of one of your uploaded draft templates. Take it from GET /v1/templates.
Body
Replace a template's body, and optionally its title and description.
A PUT rather than a PATCH, matching drafts.update: contentMarkdown is
the WHOLE body, so sending one clause replaces the template with that
clause. Title and description are left alone when omitted.
Variables are re-detected from the new body and the frozen-text hash is recomputed in the same write. That hash is the renderer's integrity baseline over the non-variable segments, so leaving it stale would check the next run against the body the template used to have.
This is lossy against a DOCX-imported template. The rich converter preserves Word formatting that markdown cannot express, and replacing the body through here discards it. Duplicate the template first if you want to keep the original.
The COMPLETE new body as markdown. This replaces the whole template: a partial body is not something this format can express. Whitespace alone is refused.
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"
New display name. Omit to leave it alone.
1 - 300"Mutual NDA"
New description. Omit to leave it alone.
2000"Master services agreement with Acme for the 2026 platform rollout."
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?

