Skip to main content

Full example

A small helper wrapping the whole flow: mint a signed URL per file, PUT each file straight to storage, then create the claim referencing them. The same partner_claim_id is used throughout so the upload paths line up with the claim.

import { readFile } from 'node:fs/promises'
import { basename } from 'node:path'

const BASE = 'https://www.garfield.law/api/partner/v1'
const TOKEN = process.env.GARFIELD_API_KEY! // 'pk_live_<partner_id>.<key_id>.<secret>' (or pk_test_… in the sandbox)

const jsonHeaders = {
Authorization: `Bearer ${TOKEN}`,
'Content-Type': 'application/json',
}

// Mint a signed URL, then PUT the file straight to storage.
// Returns the document_refs entry to pass to POST /claims.
async function uploadDocument(
entityId: string,
partnerClaimId: string,
filePath: string,
mimeType: string
) {
const filename = basename(filePath)

const mint = await fetch(`${BASE}/documents/upload-url`, {
method: 'POST',
headers: jsonHeaders,
body: JSON.stringify({
entity_id: entityId,
partner_claim_id: partnerClaimId,
filename,
mime_type: mimeType,
}),
})
if (!mint.ok)
throw new Error(`upload-url failed: ${(await mint.json()).code}`)
const { upload_url, storage_path, required_headers } = await mint.json()

// Send required_headers exactly as returned.
const put = await fetch(upload_url, {
method: 'PUT',
headers: required_headers,
body: await readFile(filePath),
})
if (!put.ok) throw new Error(`upload PUT failed: ${put.status}`)

return { storage_path, mime_type: mimeType, filename }
}

// Upload every file first (in parallel), then create the claim.
export async function createClaimWithDocuments(input: {
entityId: string
partnerClaimId: string
message?: string
defendant: { name: string } & Record<string, unknown>
invoices: Array<Record<string, unknown>>
files: Array<{ path: string; mimeType: string }>
}) {
const document_refs = await Promise.all(
input.files.map((f) =>
uploadDocument(input.entityId, input.partnerClaimId, f.path, f.mimeType)
)
)

const res = await fetch(`${BASE}/claims`, {
method: 'POST',
headers: jsonHeaders,
body: JSON.stringify({
entity_id: input.entityId,
partner_claim_id: input.partnerClaimId,
message: input.message ?? null,
defendant: input.defendant,
invoices: input.invoices,
document_refs,
}),
})
if (!res.ok)
throw new Error(`create claim failed: ${(await res.json()).code}`)

// { claim_id, message_id, document_ids, already_existed }
return res.json()
}