Skip to main content

Upload supporting documents

Attaching a document takes two separate requests:

  1. POST /documents/upload-url: Garfield returns a short-lived (15-minute) signed upload_url. No file is sent here; this call is JSON metadata only.
  2. PUT <upload_url>: you send the file bytes straight to storage (Google Cloud Storage), not to Garfield.

Do both before POST /claims, and use the same partner_claim_id on both API calls: POST /documents/upload-url and the later POST /claims (the PUT itself carries no partner_claim_id). That is how the upload path is scoped to the claim (see POST /claims).

Step 1: request the signed URL

Required: entity_id, partner_claim_id, filename, mime_type. max_bytes is optional (default and cap 50 MB).

Allowed mime_type: application/pdf, image/jpeg, image/png, image/heic, image/heif, image/webp, image/tiff, image/gif, application/msword, and application/vnd.openxmlformats-officedocument.wordprocessingml.document (.docx).

curl -X POST "$BASE/documents/upload-url" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"entity_id": "aZ4kQ9pX2",
"partner_claim_id": "case-2026-00412",
"filename": "invoice-00412.pdf",
"mime_type": "application/pdf",
"max_bytes": 5242880
}'

Response (201 Created):

{
"upload_url": "https://storage.googleapis.com/...",
"storage_path": "entities/aZ4kQ9pX2/claims/pc_af66fa4b5cb7283356863b7554d4e140/documents/0TCsxImkxYI.pdf",
"method": "PUT",
"expires_at": "2026-05-31T15:19:05.000Z",
"required_headers": {
"Content-Type": "application/pdf",
"x-goog-content-length-range": "0,5242880"
}
}

Step 2: upload the file

Send the file to the upload_url, echoing required_headers exactly. This is a separate request to Google Cloud Storage: no bearer token, and it is PUT-only (opening the URL in a browser returns MalformedSecurityHeader).

curl -X PUT "<upload_url>" \
-H "Content-Type: application/pdf" \
-H "x-goog-content-length-range: 0,5242880" \
--data-binary @invoice-00412.pdf

Then pass each returned storage_path in the claim's document_refs. At claim time each storage_path must sit under the entity+claim prefix and the file must already be uploaded; otherwise POST /claims fails with document_path_invalid or document_not_uploaded respectively.