Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.trycollate.ai/llms.txt

Use this file to discover all available pages before exploring further.

In about ten minutes you will create a sandbox authorization, answer its questionnaire, attach a supporting document, and confirm the current action. By the end, the authorization is in processing, waiting_on_payer, or — if you chose policy.finalSubmission = requires_confirmation — paused at approve_submission for final approval.

Before you start

You need:
export API_BASE_URL="https://api.sandbox.trycollate.ai"
export API_KEY="your-sandbox-api-key"

Run the example

Save this as quickstart.ts:
const API_BASE_URL = process.env.API_BASE_URL ?? "https://api.sandbox.trycollate.ai";
const API_KEY = process.env.API_KEY;

if (!API_KEY) {
  throw new Error("Set API_KEY before running this example.");
}

type RequestOptions = {
  method?: "GET" | "POST" | "PATCH";
  body?: unknown;
  headers?: Record<string, string>;
};

type Authorization = {
  id: string;
  version: number;
  status:
    | "requires_input"
    | "requires_confirmation"
    | "processing"
    | "waiting_on_payer"
    | "completed"
    | "canceled";
  outcome?: string | null;
  requirements: {
    version: number;
    questions: Array<{ linkId: string; message?: string | null }>;
    documents: Array<{ type: string; message?: string | null }>;
    issues: Array<{ code: string; message: string }>;
  };
  nextAction?: {
    id: string;
    type: "provide_requirements" | "advance_case" | "approve_submission";
  } | null;
  submission: {
    reviewSnapshot?: unknown | null;
    payerReceipt?: { referenceNumber?: string | null } | null;
    decision?: unknown | null;
  };
};

type CreateFileResponse = {
  file: { id: string };
  upload: { method: "PUT"; url: string; headers?: Record<string, string> };
};

type FileDto = { id: string; status: string };

async function request<T>(path: string, options: RequestOptions = {}): Promise<T> {
  const response = await fetch(`${API_BASE_URL}${path}`, {
    method: options.method ?? "GET",
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
      ...options.headers,
    },
    body: options.body ? JSON.stringify(options.body) : undefined,
  });
  if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
  return response.json() as Promise<T>;
}

const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
const idem = (label: string) => `${label}-${Date.now()}-${crypto.randomUUID()}`;

async function main() {
  let auth = await request<Authorization>("/v1/prior-auth/authorizations", {
    method: "POST",
    headers: { "Idempotency-Key": idem("create") },
    body: {
      providerNpi: "1234567893",
      templateSelection: {
        payerId: "payer_aetna",
        insuranceState: "CA",
        serviceType: "drug",
        serviceCode: "J0791",
        serviceCodeSystem: "hcpcs",
      },
      policy: { finalSubmission: "requires_confirmation" },
      portalAuthMode: "automated",
    },
  });

  auth = await request<Authorization>(
    `/v1/prior-auth/authorizations/${auth.id}/answers`,
    {
      method: "PATCH",
      headers: { "If-Match": `"${auth.version}"` },
      body: {
        questionnaireResponse: {
          item: [
            { linkId: "patient.first_name", answer: [{ valueString: "Jane" }] },
            { linkId: "patient.last_name", answer: [{ valueString: "Doe" }] },
            { linkId: "coverage.member_id", answer: [{ valueString: "W123456789" }] },
            { linkId: "request.diagnosis_code", answer: [{ valueString: "D57.1" }] },
            { linkId: "request.requested_dose", answer: [{ valueString: "5 mg/kg IV" }] },
          ],
        },
      },
    },
  );

  const created = await request<CreateFileResponse>("/v1/files", {
    method: "POST",
    body: {
      fileName: "clinical-notes.pdf",
      contentType: "application/pdf",
      purpose: "authorization_attachment",
    },
  });

  const pdf = new TextEncoder().encode("%PDF-1.4\n1 0 obj\n<<>>\nendobj\ntrailer\n<<>>\n%%EOF\n");
  const upload = await fetch(created.upload.url, {
    method: created.upload.method,
    headers: created.upload.headers,
    body: pdf,
  });
  if (!upload.ok) throw new Error(`Upload failed: ${upload.status}`);

  const file = await request<FileDto>(
    `/v1/files/${created.file.id}/complete`,
    { method: "POST" },
  );

  auth = await request<Authorization>(
    `/v1/prior-auth/authorizations/${auth.id}/attachments`,
    {
      method: "POST",
      headers: {
        "If-Match": `"${auth.version}"`,
        "Idempotency-Key": idem("attach"),
      },
      body: { fileId: file.id, documentTypes: ["clinical_notes"] },
    },
  );

  if (auth.status === "requires_input") {
    console.log("Outstanding requirements:", auth.requirements);
    return;
  }

  if (auth.status === "requires_confirmation" && auth.nextAction?.type === "advance_case") {
    auth = await request<Authorization>(
      `/v1/prior-auth/authorizations/${auth.id}/confirm`,
      {
        method: "POST",
        headers: {
          "If-Match": `"${auth.version}"`,
          "Idempotency-Key": idem("confirm"),
        },
        body: { nextActionId: auth.nextAction.id },
      },
    );
  }

  while (auth.status === "processing") {
    await sleep(1000);
    auth = await request<Authorization>(`/v1/prior-auth/authorizations/${auth.id}`);
  }

  console.log("Status:", auth.status);
  console.log("Next action:", auth.nextAction?.type ?? "none");
  console.log("Receipt:", auth.submission.payerReceipt?.referenceNumber ?? "none");
}

main().catch((error) => {
  console.error(error);
  process.exit(1);
});
Run it:
npx tsx quickstart.ts

What just happened

The script created an authorization, patched five answers, uploaded a PDF and attached it, and confirmed advance_case. It then polled the authorization until Collate finished processing. If the authorization later returns nextAction.type = approve_submission, render submission.reviewSnapshot and call /confirm to cross the final payer-submission boundary. See Final submission approval.

Next

Authorization lifecycle

The full state machine.

Attaching files

The file upload and attachment flow in detail.

Canonical fields

Map answers from your source systems.

Errors

Recognize and recover from public errors.