curl --request PUT \
--url https://api.vaquill.ai/workspace/v1/matters/{matterId}/drafts/{draftId} \
--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/matters/{matterId}/drafts/{draftId}"
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/matters/{matterId}/drafts/{draftId}', 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/matters/{matterId}/drafts/{draftId}"
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": "drf_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6",
"matterId": "mat_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6",
"title": "Master Services Agreement",
"category": "commercial",
"practiceArea": "commercial",
"status": "draft",
"source": "generated",
"version": 3,
"generationStatus": "succeeded",
"governingLawState": "ca",
"createdAt": "2026-08-19T14:32:10Z",
"updatedAt": "2026-08-19T14:32:10Z",
"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 draft's body
Replace a draft’s body, keeping the previous one as a version.
A PUT, not a PATCH: contentMarkdown is the WHOLE body, so sending one
paragraph replaces the document with that paragraph. Pass expectedVersion
with the version you read to make this a safe read-modify-write; omitting it
means “overwrite whatever is there”. Title and status are left alone when
omitted.
curl --request PUT \
--url https://api.vaquill.ai/workspace/v1/matters/{matterId}/drafts/{draftId} \
--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/matters/{matterId}/drafts/{draftId}"
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/matters/{matterId}/drafts/{draftId}', 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/matters/{matterId}/drafts/{draftId}"
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": "drf_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6",
"matterId": "mat_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6",
"title": "Master Services Agreement",
"category": "commercial",
"practiceArea": "commercial",
"status": "draft",
"source": "generated",
"version": 3,
"generationStatus": "succeeded",
"governingLawState": "ca",
"createdAt": "2026-08-19T14:32:10Z",
"updatedAt": "2026-08-19T14:32:10Z",
"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
mat_ identifier of the matter to work inside. Everything in this API hangs off a matter, and the matter in the path is what the authorization boundary is checked against. Take it from GET /v1/matters.
drf_ identifier of the draft. Take it from the matter's draft list.
Body
Replace a draft's body, and optionally its title and lifecycle status.
A PUT rather than a PATCH because contentMarkdown is the whole body:
a partial body is not a thing this format can express, and pretending
otherwise would invite a caller to send one paragraph and lose the rest.
Title and status are left alone when omitted, which is what makes a
body-only edit possible without restating metadata the caller did not read.
expectedVersion is how a headless read-modify-write avoids a lost update.
Omitting it means "overwrite whatever is there", which is a legitimate thing
to want and a bad default to impose.
The COMPLETE new body as markdown. This replaces the whole document: a partial body is not something this format can express, so sending one paragraph loses the rest. 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 title. Omit to leave the title alone.
1 - 200"Master Services Agreement"
New document lifecycle status: draft, review, final or archived. Omit to leave it alone.
draft, review, final, archived "draft"
Why this change was made. Recorded on the version snapshot the replace creates, so it shows up in the version list later.
500"Tightened the indemnity carve-outs after counsel review."
The version you read before editing. Supply it so a concurrent write is refused rather than silently overwritten. Omitting it means 'overwrite whatever is there'.
x >= 11
Response
Successful Response
One draft with its body, section by section.
Public identifier, drf_ followed by 32 hex characters.
"drf_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6"
The draft's title.
"Master Services Agreement"
What kind of document this is, as a category slug.
"commercial"
Practice area the draft sits in.
"commercial"
Where the DOCUMENT is in its own lifecycle: draft, review, final or archived. Set by you. This is not the same as generationStatus.
"draft"
How the draft came to exist: generated by the pipeline, uploaded from a file, imported from editor content, or analysis where an analysis produced it.
"generated"
Current version number, counting from 1. Pass it as expectedVersion on a replace to avoid a lost update.
3
Where the JOB that produced this draft got to, in the five public statuses. Set only by the pipeline. A draft the pipeline never touched reads succeeded.
queued, running, succeeded, failed, cancelled "succeeded"
When the draft was created (RFC 3339).
"2026-08-19T14:32:10Z"
When the draft was last modified (RFC 3339).
"2026-08-19T14:32:10Z"
The draft body, section by section. Send edits back as contentMarkdown; request bytes from the export route.
Show child attributes
Show child attributes
mat_ identifier of the matter this draft belongs to, when it belongs to one.
"mat_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6"
The governing law pinned on the draft, for example ca or federal.
"ca"
Was this page helpful?

