Skip to content
Hermes Health API
API referenceOpenAPI spec

Guide

Check an authorization with the API

Run the auth check on any document and read the verdicts as JSON.

The auth check reads a signed authorization and reports, item by item, whether it will hold up: the signature, the patient’s name and date of birth, the expiry, the recipient, and more. You can run it on any document, outside any patient or project, and read the result as JSON.

To show the result to your own users, embed the UI instead of rendering this JSON: see Embed the auth-check UI. The JSON schema changes as coverage grows, and the iframe absorbs that.

1. Request an upload URL

PUT /v0/auth-check/{filename}, with the patient the document should be for:

Request an upload URL
curl
curl https://api.hermeshealth.ai/v0/auth-check/jane-doe-authorization.pdf \
  -X PUT \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "firstName": "Jane",
  "lastName": "Doe",
  "dateOfBirth": "1990-04-12",
  "referenceId": "MRN-00042"
}'
import requests

response = requests.put(
    "https://api.hermeshealth.ai/v0/auth-check/jane-doe-authorization.pdf",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={
        "firstName": "Jane",
        "lastName": "Doe",
        "dateOfBirth": "1990-04-12",
        "referenceId": "MRN-00042",
    },
)
response.raise_for_status()
print(response.json())
const response = await fetch("https://api.hermeshealth.ai/v0/auth-check/jane-doe-authorization.pdf", {
    method: "PUT",
    headers: {
        Authorization: "Bearer YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    body: JSON.stringify({
      "firstName": "Jane",
      "lastName": "Doe",
      "dateOfBirth": "1990-04-12",
      "referenceId": "MRN-00042"
    }),
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
const data = await response.json();

The response carries an uploadUrl, any uploadHeaders to send with it, and an embedToken you will need to read the result. The patient details are what the check compares the document against, and they are stored with the submission.

referenceId is optional: your own identifier for the patient, such as an MRN, of up to 255 characters. It is shown with the submission in the auth-checker’s Submissions tab, so you can match each one back to your patient.

filename names the document among your own uploads. Uploading again under the same name records a new submission.

filename must be one path segment of at most 255 bytes, must not start with a dot, and needs a name before its extension. Anything else returns 400.

If you don’t have the patient’s details yet, send no body. You get an upload URL but no token; see Get a token later.

2. Upload the document

PUT the PDF to uploadUrl as raw bytes, with any uploadHeaders and no Authorization header:

Upload the PDF
curl
curl "UPLOAD_URL" \
  -X PUT \
  --data-binary @jane-doe-authorization.pdf
import requests

with open("jane-doe-authorization.pdf", "rb") as document:
    response = requests.put("UPLOAD_URL", data=document)
response.raise_for_status()
import { readFile } from "node:fs/promises";

const response = await fetch("UPLOAD_URL", {
    method: "PUT",
    body: await readFile("jane-doe-authorization.pdf"),
});
if (!response.ok) throw new Error(`Upload failed: ${response.status}`);

Send the URL exactly as issued. Its signature is in the query string, so changing any part of it returns 403.

The check starts on its own once the upload lands.

3. Read the result

GET /v0/auth-check/{filename}?token=<embedToken>:

Read the result
curl
curl "https://api.hermeshealth.ai/v0/auth-check/jane-doe-authorization.pdf?token=YOUR_TOKEN" \
  -H "Authorization: Bearer YOUR_API_KEY"
import requests

response = requests.get(
    "https://api.hermeshealth.ai/v0/auth-check/jane-doe-authorization.pdf?token=YOUR_TOKEN",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
)
response.raise_for_status()
print(response.json())
const response = await fetch("https://api.hermeshealth.ai/v0/auth-check/jane-doe-authorization.pdf?token=YOUR_TOKEN", {
    method: "GET",
    headers: {
        Authorization: "Bearer YOUR_API_KEY",
    },
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
const data = await response.json();

While the check is running, verdicts is null. A check can take a minute or more, so poll every few seconds until verdicts is filled in.

Poll on verdicts, not extraction. extraction can appear, with empty data, before the check has finished.

Response (excerpt)
json
{
  "verdicts": {
    "signature":          { "status": "Passed",  "message": "Signed and dated by the patient.", "basis": "legal" },
    "patientDateOfBirth": { "status": "Failed",  "message": "Date of birth does not match.",     "basis": "legal" },
    "dateOfExpiration":   { "status": "Warning", "message": "Expires in 12 days.",               "basis": "requestCoverage" },
    "datesOfService":     null
  },
  "verdictCounts": { "passed": 14, "failed": 1, "warning": 2 },
  "downloadUrl": "https://..."
}
FieldWhat it is
verdictsOne entry per check. Each has a status (Passed, Warning or Failed), a message saying what was found, and a basis naming the kind of requirement (legal, requestCoverage, providerAcceptance or operational).
verdictCountsHow many checks passed, failed or warned.
extractionThe fields read off the document. Its schema changes as coverage grows.
downloadUrlA short-lived link to the uploaded document.

A null verdict means that check did not run, not that it passed. datesOfService never runs here, because it needs a record request to compare against.

Get a token later

If you uploaded without the patient’s details, or the token has expired, create one with POST /v0/auth-check/{filename}/embed-token, sending the same body: firstName, lastName, dateOfBirth and, optionally, referenceId. Tokens last one hour.

Sending different details for the same filename corrects the ones stored with the submission.

Run the check again

POST /v0/auth-check/{filename}/retrigger, with no body, runs the check again on the document already uploaded. Read the result the same way as before.

When a request fails

StatusCause
400The filename breaks the naming rules above.
401The token is missing, expired, altered, or was created for a different filename.
403On the upload: the upload URL was changed.

Next steps