curl --request POST \
--url https://api.maxcare.ai/v2/patients/{id}/documents/{documentId}/fetch \
--header 'Authorization: Bearer <token>' \
--header 'X-Organization-Id: <x-organization-id>'import requests
url = "https://api.maxcare.ai/v2/patients/{id}/documents/{documentId}/fetch"
headers = {
"X-Organization-Id": "<x-organization-id>",
"Authorization": "Bearer <token>"
}
response = requests.post(url, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-Organization-Id': '<x-organization-id>', Authorization: 'Bearer <token>'}
};
fetch('https://api.maxcare.ai/v2/patients/{id}/documents/{documentId}/fetch', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.maxcare.ai/v2/patients/{id}/documents/{documentId}/fetch",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"X-Organization-Id: <x-organization-id>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.maxcare.ai/v2/patients/{id}/documents/{documentId}/fetch"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("X-Organization-Id", "<x-organization-id>")
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.maxcare.ai/v2/patients/{id}/documents/{documentId}/fetch")
.header("X-Organization-Id", "<x-organization-id>")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.maxcare.ai/v2/patients/{id}/documents/{documentId}/fetch")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Organization-Id"] = '<x-organization-id>'
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"code": "success",
"data": {
"status": "completed",
"reason": null,
"document": {
"id": "9c1f0f7a-2f4b-4f2e-8a1e-6b0f2d3c4a5b",
"kind": "insurance_card",
"sourceCategory": "Insurance Card Front",
"title": "Insurance Card Front",
"filename": "insurance_card_front.jpg",
"mimeType": "image/jpeg",
"bytes": 184320,
"createdAt": "2026-02-27T15:04:05.000Z",
"updatedAt": "2026-08-14T10:15:00.000Z",
"downloaded": true,
"url": "https://storage.maxcare.ai/…?X-Amz-Signature=…",
"expiresInSeconds": 3600,
"deletedFromEhrAt": null
}
}
}{
"code": "bad_request",
"message": "'id' must be a valid UUID",
"trace_id": "550e8400-e29b-41d4-a716-446655440000"
}{
"code": "unauthorized",
"message": "Invalid or missing API key",
"trace_id": "550e8400-e29b-41d4-a716-446655440000"
}{
"code": "forbidden",
"message": "Insufficient scope",
"trace_id": "550e8400-e29b-41d4-a716-446655440000"
}{
"code": "not_found",
"message": "Resource not found",
"trace_id": "550e8400-e29b-41d4-a716-446655440000"
}{
"code": "conflict",
"message": "Cannot edit a signed note",
"trace_id": "550e8400-e29b-41d4-a716-446655440000"
}{
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded. Maximum 1000 requests per 60 seconds.",
"trace_id": "550e8400-e29b-41d4-a716-446655440000"
}{
"code": "unexpected_integration_error",
"message": "EHR sync failed",
"trace_id": "550e8400-e29b-41d4-a716-446655440000"
}Pull one chart document's bytes from the EHR
Stages the bytes of a document GET /patients/{id}/documents reported with downloaded: false, so it becomes downloadable. Returns when the pull is done, so there is nothing to poll — one file is typically a sub-second EHR call, but a cold session or a large attachment can take considerably longer and the request is held for as long as the download runs. Set a client timeout accordingly: a retry after one lands on the in-flight 409 rather than starting a second download. The response carries the document exactly as the list endpoint now reports it, with downloaded: true, a signed url and expiresInSeconds. Already-staged bytes are served from cache with no EHR call, so this is safe to call again for a fresh URL. status: "unavailable" is NOT a failure: it means this platform cannot pull the bytes on its own and reason says what a human has to do (needs_user_session — a clinic user must open the patient’s Documents panel once; ehr_auth — the practice’s EHR connection needs reconnecting). A second call while one pull is in flight is normally a 409 — though if the platform’s coordination store is briefly unavailable it may instead join the running pull and answer 200 with the same result, or 409 if that pull is still running after a short wait — and a document that has since been removed from the chart and was never staged is a 404. Guarded beyond the shared rate limiter by a cap on LIVE pulls per EHR connection per UTC day (429, resetting at 00:00 UTC) — so one practice location running out does not affect another; documents already staged keep being served after the cap, since they cost the EHR nothing. Requires read:patient_documents scope.
curl --request POST \
--url https://api.maxcare.ai/v2/patients/{id}/documents/{documentId}/fetch \
--header 'Authorization: Bearer <token>' \
--header 'X-Organization-Id: <x-organization-id>'import requests
url = "https://api.maxcare.ai/v2/patients/{id}/documents/{documentId}/fetch"
headers = {
"X-Organization-Id": "<x-organization-id>",
"Authorization": "Bearer <token>"
}
response = requests.post(url, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-Organization-Id': '<x-organization-id>', Authorization: 'Bearer <token>'}
};
fetch('https://api.maxcare.ai/v2/patients/{id}/documents/{documentId}/fetch', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.maxcare.ai/v2/patients/{id}/documents/{documentId}/fetch",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"X-Organization-Id: <x-organization-id>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.maxcare.ai/v2/patients/{id}/documents/{documentId}/fetch"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("X-Organization-Id", "<x-organization-id>")
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.maxcare.ai/v2/patients/{id}/documents/{documentId}/fetch")
.header("X-Organization-Id", "<x-organization-id>")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.maxcare.ai/v2/patients/{id}/documents/{documentId}/fetch")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Organization-Id"] = '<x-organization-id>'
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"code": "success",
"data": {
"status": "completed",
"reason": null,
"document": {
"id": "9c1f0f7a-2f4b-4f2e-8a1e-6b0f2d3c4a5b",
"kind": "insurance_card",
"sourceCategory": "Insurance Card Front",
"title": "Insurance Card Front",
"filename": "insurance_card_front.jpg",
"mimeType": "image/jpeg",
"bytes": 184320,
"createdAt": "2026-02-27T15:04:05.000Z",
"updatedAt": "2026-08-14T10:15:00.000Z",
"downloaded": true,
"url": "https://storage.maxcare.ai/…?X-Amz-Signature=…",
"expiresInSeconds": 3600,
"deletedFromEhrAt": null
}
}
}{
"code": "bad_request",
"message": "'id' must be a valid UUID",
"trace_id": "550e8400-e29b-41d4-a716-446655440000"
}{
"code": "unauthorized",
"message": "Invalid or missing API key",
"trace_id": "550e8400-e29b-41d4-a716-446655440000"
}{
"code": "forbidden",
"message": "Insufficient scope",
"trace_id": "550e8400-e29b-41d4-a716-446655440000"
}{
"code": "not_found",
"message": "Resource not found",
"trace_id": "550e8400-e29b-41d4-a716-446655440000"
}{
"code": "conflict",
"message": "Cannot edit a signed note",
"trace_id": "550e8400-e29b-41d4-a716-446655440000"
}{
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded. Maximum 1000 requests per 60 seconds.",
"trace_id": "550e8400-e29b-41d4-a716-446655440000"
}{
"code": "unexpected_integration_error",
"message": "EHR sync failed",
"trace_id": "550e8400-e29b-41d4-a716-446655440000"
}Authorizations
Marketplace API key
Headers
Target clinic organization ID
Path Parameters
Patient ID
Document ID, as returned by GET /patients/{id}/documents
