Documentation
Documents
documents.get
REST
ShippingPOST /api/v1/documents/getMCP tool
Livedocuments.getExposed on: REST API · Shop MCP server · Claude connector · Dash (in-app copilot) · Zapier. Part of the Documents domain.
Operating contract
One file: what it is, what it is filed against, and its timeline — uploaded, viewed, sent, signed, filed.
The TIMELINE is the part that is only here. It is what answers 'did the customer ever see this' and 'when was this signed', which is the question anybody has about a contract weeks later.
filed_against may name several records. A document attached to a job and to a vehicle is one file, not two, and detaching it from one leaves it on the other.
AGAIN: THE BYTES ARE NOT HERE. There is no URL on this response and no capability that produces one. If somebody needs the file, they open it from /documents/[id] where their own login is the gate.
Refuses when nothing in this shop has that id, including a document that has been removed.
Who may call it
- Permission
- NoneThe library is open to every active member of the shop — `/documents` is guarded by `requireShopContext()` and by no section at all, because a technician needs the photos of the car they are working on. Gating this would make a machine see less of the shop's own filing than the bench does.
- Plan
- Every planNo plan gate. Available on every Service VIN plan.
- Retries
naturalNaturally idempotent — running it twice leaves the same world as running it once. A retrying integration needs no key.- Rate class
readCounted against the read budget — the widest of the four.
Input
| Field | Type | Description |
|---|---|---|
| document_idrequired | stringuuid | The document's id, as returned by documents.list or documents.for_record. |
Output
| Field | Type | Description |
|---|---|---|
| id | string | — |
| title | string | null | — |
| kind | string | — |
| content_type | string | null | — |
| size_bytes | number | null | — |
| tags | string[] | — |
| created_at | string | — |
| filed_against | object[] | — |
| filed_against[].owner_type | string | — |
| filed_against[].owner_id | string | — |
| filed_against[].label | string | — |
| filed_against[].role | string | null | — |
| timeline | object[] | — |
| timeline[].at | string | — |
| timeline[].description | string | — |
Examples
Built from this capability's own schema — required fields and the ones carrying a default, and nothing invented. Paste one and it validates.
export SERVICEVIN_API_KEY=svk_live_…
curl -X POST https://www.servicevin.com/api/v1/documents/get \
-H "Authorization: Bearer $SERVICEVIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"document_id":"9b2f1c6e-4a77-4d2b-9f31-0f1c9a8e5d20"}'const res = await fetch("https://www.servicevin.com/api/v1/documents/get", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SERVICEVIN_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"document_id": "9b2f1c6e-4a77-4d2b-9f31-0f1c9a8e5d20"
}),
});
// Success and failure are both envelopes. Switch on error.code, never
// on error.message — the codes are stable, the messages are for people.
const payload = await res.json();
if (!res.ok) throw new Error(payload.error.code);
const data = payload.data;import os, requests
res = requests.post(
"https://www.servicevin.com/api/v1/documents/get",
headers={"Authorization": f"Bearer {os.environ['SERVICEVIN_API_KEY']}"},
json={
"document_id": "9b2f1c6e-4a77-4d2b-9f31-0f1c9a8e5d20"
},
timeout=30,
)
payload = res.json()
if not res.ok:
raise RuntimeError(payload["error"]["code"])
data = payload["data"]{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "documents.get",
"arguments": {
"document_id": "9b2f1c6e-4a77-4d2b-9f31-0f1c9a8e5d20"
}
}
}Refusals
The four gates run in this order on every surface, and the order is not arbitrary — see Authentication.
| Status | Code | When |
|---|---|---|
| 404 | not_found | The id is unknown, or the feature is not enabled for this account. Deliberately the same answer for both. |
| 422 | validation_error | An argument was wrong. The message names the field. |
| 429 | rate_limited | Too many read calls. Back off and retry. |
| 500 | internal_error | Something failed on our side. Nothing was changed. |