Skip to main content
Documentation

Documents

documents.get

Get one document's details and what happened to it
Read-onlyRead budget

REST

Shipping
POST /api/v1/documents/get

MCP tool

Live
documents.get

Exposed 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

FieldTypeDescription
document_idrequiredstringuuid

The document's id, as returned by documents.list or documents.for_record.

Output

FieldTypeDescription
idstring

titlestring | null

kindstring

content_typestring | null

size_bytesnumber | null

tagsstring[]

created_atstring

filed_againstobject[]

filed_against[].owner_typestring

filed_against[].owner_idstring

filed_against[].labelstring

filed_against[].rolestring | null

timelineobject[]

timeline[].atstring

timeline[].descriptionstring

Examples

Built from this capability's own schema — required fields and the ones carrying a default, and nothing invented. Paste one and it validates.

curl
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"}'

TypeScript (fetch)
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;

Python (requests)
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"]

MCP tools/call — https://www.servicevin.com/api/mcp
{
  "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.

StatusCodeWhen
404not_foundThe id is unknown, or the feature is not enabled for this account. Deliberately the same answer for both.
422validation_errorAn argument was wrong. The message names the field.
429rate_limitedToo many read calls. Back off and retry.
500internal_errorSomething failed on our side. Nothing was changed.