Skip to main content

Overview

Use the Record Retrieval API to ask Tavrn to retrieve medical records, billing records, and provider invoices from a healthcare facility. The basic flow is:
  1. Create or select a case and, if needed, configure a Requestor profile.
  2. Upload the signed HIPAA authorization form and any profile documents.
  3. Create a retrieval request.
  4. Track the request with webhooks and incremental polling.
  5. Download records and provider invoices as they become available.

What You’ll Need

  • API key with retrievals:write and retrievals:read scopes (plus cases:write if you’ll create the case via the API in step 1)
  • requestors:read if you’ll list or read Requestor profiles; requestors:write if you’ll create or configure one, including inline creation
  • A signed HIPAA authorization PDF for the patient
  • Patient name (date of birth if available)
  • A facility ID from facility search, or the facility name and address
  • At least one record type to request

Step-by-Step Guide

1. Create or Select a Case

Every new Enterprise API retrieval request needs a case. If you already have a case, skip to step 2 and use its id. Otherwise, create one:
Use the returned case id when you create the retrieval request. You can also create the case in the same call as its first retrieval using POST /v2/retrieval-requests. Upload files first using the retrieval upload endpoint, which does not require a case ID.

2. Upload the Authorization Form

Request an upload URL for the signed HIPAA authorization PDF:
The case upload endpoint accepts file_name and file_type for a retrieval attachment. Response:
Upload the file to the returned upload_url:
Save the upload_id. You will use it in auth_form when creating the retrieval request.
Upload supporting files the same way, one file per sign-upload call. Use the returned upload_id values in attachments.

3. Create the Retrieval Request

This minimal example requests medical records for one patient from one facility:
Response (abridged):
Save the retrieval request id. Webhook events reference it as retrieval_request_id, and you use it to fetch status and download returned files. Both creation endpoints accept patient and requested_records, plus exactly one of a facility_id from search or a manual facility object: For organizations with duplicate detection enabled, creation can return 409 duplicate_request_detected with a duplicates array. Review those matches before retrying with "allow_duplicate": true if the new request is intentional.

Find a facility

Search by facility name, alias, phone, fax, address, or NPI using an API key with retrievals:read:
Choose a result and replace the facility object in your creation body with "facility_id": "facility_example". Send exactly one of facility_id or facility. If the API reports an invalid or expired facility selection, search again and use the new ID. Review any listed requirements before submitting. Each includes a label, optional description, category (input, document, or instruction), and applicable record_types; an empty record_types list means all record types. Document requirements may include template_download_url for a blank template. The link is valid for 1 hour; repeat the search for a fresh link. Search text must be 3–200 characters after trimming, with at least 3 alphanumeric characters. state is optional; limit is 1–10 and defaults to 10. Results are not paginated. On 429, wait for Retry-After; on 503, try again later.

Select a Requestor

A Requestor is a retrieval profile within your organization: its name, letter of representation, RFC form, affidavits, correspondence settings, and provider invoice approval limit. To use an existing profile, add its ID to the retrieval body:
Omitting both requestor_id and requestor keeps the existing organization default. Each retrieval retains the selected ID. Configuration updates to that profile apply to its linked retrievals. Find available profiles with GET /v2/requestors, or read one with GET /v2/requestors/{requestor_id}. Both require requestors:read. List responses contain results, next, and previous; limit defaults to 20 and has a maximum of 100. Each profile includes is_default. An unavailable profile ID returns 404. If you need a different name, packet documents, correspondence settings, or invoice limit, you can create a reusable profile before submitting the retrieval. Give it a nonblank name using POST /v2/requestors, which requires requestors:write:
Omitted document and correspondence settings start empty. An omitted invoice limit uses $100. Creating a profile does not change the default profile. Each successful POST creates another profile. Save the returned id and use it as requestor_id for this and later retrievals. You can also supply an inline requestor on either retrieval creation endpoint; it requires requestors:write and cannot be combined with requestor_id.

Upload Requestor Documents

To include a letter of representation in retrieval packets, upload it to the selected profile. A profile without its own document does not use the default profile’s document. Request an upload URL with POST /v2/requestors/sign-upload, then PUT the PDF bytes to the returned upload_url:
Use the returned upload_id in the profile create or update body. Profile documents must be readable, unencrypted PDFs with a .pdf extension and application/pdf type, of at most 25 MiB. Upload bytes within 15 minutes; the upload ID expires after one hour. These upload IDs are for Requestor documents. Authorization forms and retrieval attachments use the retrieval upload endpoint. For example, attach the uploaded letter to an existing profile with PATCH /v2/requestors/{requestor_id}:
Read responses include document metadata such as file_name, page_count, and uploaded_at.

Create a Case and Requestor Inline

Use POST /v2/retrieval-requests to create the case, Requestor, and retrieval in one request. This request requires retrievals:write, cases:write, and requestors:write. First upload the signed authorization through POST /v2/retrieval-requests/sign-upload. For profile documents such as the letter of representation, follow Upload Requestor Documents. Both take file_name and file_type; PUT each file to its returned upload_url. Use each upload ID with the matching document field. Upload the bytes within 15 minutes and use the upload_id within one hour.
The response includes the new case_id, requestor_id, and retrieval id. Upload files before creating the retrieval. POST creation is not idempotent: each successful request with an inline case or requestor creates a new one. Retain the returned IDs and use case_id and requestor_id for subsequent retrievals. Use case_id instead of case for an existing case, and requestor_id instead of requestor for an existing profile. Exactly one case choice is required. Do not send both alternatives for either resource. The case-scoped creation endpoint continues to use the case in its URL and does not accept an inline case.

Update Requestor Settings

Use PATCH /v2/requestors/{requestor_id} to update a profile’s settings for linked retrievals. It requires requestors:write and at least one field. Omitted fields remain unchanged. Read responses include effective_provider_invoice_limit, so you can see the limit used when provider_invoice_limit is null. The API does not delete profiles, change the organization default, or reassign an existing retrieval to another profile.

4. Track Status

Subscribe to retrieval request webhooks for status updates, action requests, and available records or invoices: When an event arrives, use its retrieval request ID to fetch the current request:
Use status for the overall request state and stage to show its progress in Tavrn. status values: completed and cancelled are final statuses. Both trigger a retrieval_request.status_changed event. Continue incremental polling to pick up later document changes.
When status is action_required, read pending_action_request for what your firm needs to provide. Respond through the API or follow platform_url to handle it in Tavrn. After a response, the request returns to processing.
stage values: stage_label and stage_description carry the exact text shown on the dashboard for the current stage. Not every request passes through every stage — for example, a request whose facility contact is already known goes straight to request_sent. Example response (abridged):
Each timeline entry has a state: completed (happened), current (where the request is now), pending (standard step not reached yet), or skipped (standard step that was not needed). checkpoints list individual attempts within a step, such as phone calls. action_request is set on action_required steps and includes what was asked, whether your firm has responded (awaiting_response, answered, or resolved), and the response text.
timeline is returned by GET /v2/retrieval-requests/{id} and list queries with include=details. Summary list results include stage, stage_label, and stage_description but omit the timeline.
Filtering the list by stage:
stage accepts one or more comma-separated values and can be combined with status and case_id.

Incremental polling

Use public_updated_since with the list endpoint to reconcile status, action request, and document updates alongside webhooks:
  1. Start with your saved checkpoint, or the epoch timestamp above for an initial sync.
  2. Upsert each result by request ID. include=details adds the timeline, open action request, and released document metadata.
  3. Follow each next URL as returned until it is null.
  4. After processing the final page, save its next_public_updated_since for the next round.
The lower bound is inclusive, so a request may appear in successive rounds. Compare public_updated_at when updating a cached request. The final page supplies next_public_updated_since even when no requests were returned. For an organization-wide sync, leave status, stage, and case filters unset so completed and cancelled requests stay in scope. You can divide a large initial sync into fixed creation-date windows, with a checkpoint for each window. Choose a polling interval that fits your integration. Changes during a round may appear in that round or the next. If a cursor expires or polling returns 503, resume from the last saved checkpoint. Fetch an individual request when you need current costs.

5. Download Records and Invoices

List documents when you receive retrieval_request.documents_available or need current files. Provider invoices can become visible before or after request completion:
Response:
This endpoint returns all current documents in one response. next and previous are always null. Use category to distinguish records, provider invoice documents, and cost_summary PDFs. Each invoice entry includes metadata.provider_fee_amount: the invoice amount in USD, not cents, that contributes to costs.provider_fees. 0 is a valid amount. Record and cost summary entries omit metadata. The embedded documents array on GET /v2/retrieval-requests/{id} and the document list use the same entries. A documents_available event’s document_ids and invoice_ids match their id values. An invoice can appear in the list and costs before it is downloadable. In that case, its download route returns 404. The invoice documents_available webhook fires when the file becomes downloadable. Get a download URL for each document:
Response:
Download the file from download_url before it expires.

Request cost PDF

Once a request is completed and its billing is finalized, its documents include an entry with id and category both set to cost_summary. The PDF shows Tavrn credits and fees, provider fees, and the total. It always includes a Tavrn credits line, showing 0 credits × $0.00 = $0.00 when the request has no credit entries.
The response contains download_url and expires_in: 3600. Fetch the URL to download the PDF. The endpoint returns 404 while the document is unavailable. The entry appears in the request GET response and list results with include=details, but is excluded from documents_summary counts. Refetch the request or document list to check availability: billing finalization does not trigger a documents_available webhook or advance public_updated_at.

Invoice Availability Notifications

Subscribe to retrieval_request.documents_available through Webhooks to learn when a document becomes downloadable. When a provider invoice becomes downloadable, the request’s public_updated_at advances and the event identifies the available invoice:
For an invoice, its ID appears in both document_ids and invoice_ids. Use it as {document_id} on the download route, and fetch the request for current document and cost details.
Retrieval documents are separate from case documents you upload for other workflows. Their metadata is available from /v2/retrieval-requests/{id}/documents, the request GET response, and list queries with include=details. Use the retrieval document download endpoint to access the files.

Optional Fields

The minimal request works with patient name, a facility ID or facility name and address, at least one record type, and an authorization form. Add these fields when you have them:

Requested Records

Use requested_records to describe what you want from the facility. Medical records only:
Medical records plus itemized billing:
Certified medical records:
A request may use only one attestation kind — certification or affidavit — across all of its requested_records. Mixing them (on the same or different lines) returns a 400 validation_error; submit a separate request for records that need the other kind. Ongoing care: Set service_end_date to null to request records through the present.
Some values, including rfc, abstract_medical_records, and requirements, are available only when enabled for your organization. See Permission-gated features.
See the RequestedRecord schema for the full list of record types, billing formats, and advanced patterns.

Responding to Action Requests

When Tavrn needs something from your firm, the request’s status becomes action_required and GET /v2/retrieval-requests/{id} returns the open action request in pending_action_request:
document is a file Tavrn attached to the action request (for example, a provider invoice or no-records letter), or null. Its download_url expires after expires_in seconds; fetch the request for a fresh URL. When an action request opens or reopens, retrieval_request.action_required includes its ID. Fetch the request to read the message and any attachment; incremental polling also captures the update.

Text-only response

Response:
message is required (up to 10,000 characters). requester_email is optional and records who at your firm answered. The endpoint needs the retrievals:write scope.

Response with an attachment

Upload the file under the retrieval request’s case, then pass its upload_id:
The upload must belong to the same case as the retrieval request. PUT the file to the signed URL within 15 minutes, then use its upload_id within one hour. Each upload_id can be used once.

How Tavrn handles your response

A rejected response (400) leaves the action request open so you can retry. After a successful response the request leaves action_required (usually back to processing), and the timeline’s action_request shows status: "answered" with your response_text. Responding again after that returns 409, as does responding when there is no open action request.

Support messages

Send a question or instruction with POST /v2/retrieval-requests/{retrieval_request_id}/messages. Requires retrievals:write and, for CMS-linked requests, support messaging enabled on the connection.
Messages and published replies are logged without changing retrieval status. Drafts and private notes are excluded. message is required (maximum 10,000 characters). Upload attachments under the request’s case, then include attachment: { "upload_id": "..." }. Identical submissions within 10 minutes return the existing conversation with deduplicated: true. Concurrent submissions return 409 (support_message_in_progress); retry shortly. Success confirms submission, not completion of the requested work.

Cancelling a Request

You can cancel a request before it completes:
Cancellation is final. Completed requests cannot be cancelled.

Next Steps