Skip to main content

REST API

The Eirly REST API provides programmatic access to manage referrals, results, tests, and bundles. All API requests require authentication via OAuth 2.0.

Base URL: https://api.eirly.health

Current Version: v1

Swagger Documentation

For interactive API documentation and testing, visit our Swagger Documentation

API Versioning

The API supports versioning through both URL paths and custom headers:

  • v1.0.0 (Default) - Blood tests only, single referral per request
  • v1.1.0 - Supports bundles and multiple referrals per request

To use a specific version, include the Accept header:

Accept: application/vnd.bgt.v1.1.0+json

Authentication

All API endpoints require authentication. Include your access token in the Authorization header:

Authorization: Bearer YOUR_ACCESS_TOKEN

Timeouts

The ordering endpoint /referrals can take upwards of 10 seconds to complete, so please allow for this to avoid duplicate orders being sent if you have a retry strategy in place.

Core Resources

Referrals

Referrals represent test orders for patients. A referral contains patient information, requested tests, and metadata.

The referral payload will return an origin property, possible values are:

export enum ReferralOrigin {
ConsumerWebsite = 'CONSUMER_WEBSITE',
BundlePurchase = 'BUNDLE_PURCHASE',
Api = 'API',
StoreIntegration = 'STORE_INTEGRATION',
Unknown = 'UNKNOWN',
}

The referral status property progresses through the following values across the referral lifecycle:

export enum ReferralStatus {
PendingVerification = 'PENDING_VERIFICATION', // awaiting verification before issue
Created = 'CREATED', // created but not yet issued
Issued = 'ISSUED', // PDF generated and ready to deliver
ScheduledReissue = 'SCHEDULED_REISSUE', // a new PDF is being regenerated (e.g. after PATCH)
PartialResults = 'PARTIAL_RESULTS', // some but not all results returned
Complete = 'COMPLETE', // all results returned
InsufficientData = 'INSUFFICIENT_DATA', // unable to process due to missing data
Refunded = 'REFUNDED', // referral refunded
TestFailed = 'FAILED_TEST', // one or more tests failed at the lab
BillingFailed = 'BILLING_FAILED', // billing could not be completed
Transferred = 'TRANSFERRED', // referral transferred to another provider
}

Only referrals with status CREATED or ISSUED can be updated via PATCH. See Update Referral for details.

Create Referral

POST /v1/referrals

Creates a new referral for a patient.

Request Body:

{
"firstName": "John",
"lastName": "Vein",
"email": "john.vein@eirly.health",
"address": {
"addressLine1": "123 Example Way",
"addressLine2": null,
"postCode": "4000",
"city": "Brisbane",
"country": "Australia",
"state": "QLD"
},
"dob": "1980-01-01",
"gender": "male",
"phone": "0412345678",
"tests": ["tft", "free-testosterone"],
"metadata": {
"internalId": "1234"
},
"referenceNumber": "12345678",
"emailReferralToCustomer": true
}

Optional Fields:

FieldTypeDefaultDescription
emailReferralToCustomerbooleantrueControls whether Eirly emails the referral PDF directly to the customer. Set to false if you want to deliver the referral to the customer yourself — when disabled, Eirly will not send the referral email and you are responsible for getting it to the patient.

For v1.1.0 - Bundle Support:

{
"firstName": "John",
"lastName": "Vein",
"email": "john.vein@eirly.health",
"address": {
"addressLine1": "123 Example Way",
"postCode": "4000",
"city": "Brisbane",
"country": "Australia",
"state": "QLD"
},
"dob": "1980-01-01",
"gender": "male",
"phone": "0412345678",
"bundleId": "56ce2120-5480-4657-9e47-7ae4ecf9229b",
"metadata": {
"internalId": "1234"
}
}

Choosing between bundleId and tests:

On v1.1.0, a referral can be created from a pre-configured bundle, an ad-hoc list of tests, or both. At least one of bundleId or tests must be provided — sending neither will return a 400 error.

ProvidedBehaviour
tests onlyThe referral is created with exactly the tests you listed.
bundleId onlyThe referral is created with the full set of tests defined on that bundle. The bundle's productId / productName will be attached to the referral.
bundleId and testsThe referral includes every test in the bundle plus any additional tests you pass in tests. Use this when you want to extend a standard bundle on a per-patient basis (e.g. add vitamin-d to a "Men's Health" bundle). Duplicate tests are de-duplicated server-side.

Notes:

  • bundleId is only accepted on v1.1.0 and above. Sending a bundleId against v1.0.0 will return a 400 error directing you to upgrade the version header.
  • The response's tests array reflects the fully-resolved list of tests on the referral, regardless of whether they came from a bundle, the tests field, or both.

Response (200 OK):

{
"uuid": "254fa374-6d05-4a41-bfd8-254ba2039049",
"status": "ISSUED",
"object": "referral",
"tests": ["tft", "free-testosterone"],
"metadata": {
"internalId": "1234"
},
"productId": null,
"productName": null,
"origin": "API",
"person": {
"firstName": "John",
"lastName": "Vein",
"email": "john.vein@eirly.health",
"address": {
"addressLine1": "123 Example Way",
"addressLine2": null,
"postCode": "4000",
"city": "Brisbane",
"country": "Australia",
"state": "QLD"
},
"phone": "0412345678",
"dob": "1980-01-01",
"gender": "male"
},
"referralType": "blood",
"referenceNumber": "12345678",
"referralAttachment": "https://api.eirly.health/download/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmaWxlVXVpZCI6IjJhNGRkYjALTk5MItNDUxMy1iMTAxLTMzMjBmZmYzMzAwMSIsInByb2ZpbGVVdWlkIjoiMTQxZjQ5NTgtjYzJkYi00NDY1LIwMTEtODc3MmZmZjQzMzU3IiwicmFuZG9tVmsdWUiOiJBTHJrOXNYM01iWnFXcGc4UFNRdGZmS3Fd6dGRzZ24iLCJvcmdhbmljzYXRpb25VdWlkIjoiNWQ0NDkxOTQtYzVjMS00DUzLWIyNjTQtZGRhNzg0MjdkZjllIiwiZm9y2VEb3dubG9hZCI6dHJ1ZSwiaWF0IjjoxNzc5NDI2MjExLCJleHAiOjdE3Nzk0MjcxMTF9.x7Hj2vP9aQmLZc5dRngK4tUyB1eF6oI3wJxN8sVrTYg",
"emailSentAt": "2024-06-04T05:29:09.385Z",
"createdAt": "2024-06-04T05:29:06.508Z",
"updatedAt": "2024-06-04T05:29:09.385Z",
"deletedAt": null,
"resultsUuid": null
}

Notable response fields:

FieldTypeDescription
referralAttachmentstring (url) | nullSigned URL to the referral PDF. null until the PDF has been generated (e.g. while status is CREATED or SCHEDULED_REISSUE), and null for deleted referrals. URLs are time-limited — re-fetch the referral to get a fresh URL.
updatedAtstring (ISO 8601)Time the referral record was last modified. Updated whenever the referral status changes or fields are edited via PATCH.
deletedAtstring (ISO 8601) | nullSet when the referral has been soft-deleted via DELETE; null otherwise.
emailSentAtstring (ISO 8601) | nullTime the referral email was dispatched to the customer. null if emailReferralToCustomer was false, or before delivery has occurred.
resultsUuidstring (uuid) | nullUUID of the associated result once results are available (i.e. once status reaches PARTIAL_RESULTS or COMPLETE).

Get Referral

GET /v1/referrals/{uuid}

Retrieves a specific referral by UUID.

Response (200 OK): Same structure as Create Referral response

List Referrals

GET /v1/referrals

Returns all referrals for your organisation with pagination support.

Query Parameters:

  • count (integer, optional) - Number of results to return (max 20, default 20)
  • cursor (string, optional) - Cursor for pagination
  • sort (string, optional) - Sort order: asc or desc (default: asc)

Response (200 OK):

{
"cursor": {
"cursor": "MjAyNC0wNi0wNFQxMjo1OTowMS44MDJafGNyZWF0ZWRBdHxhc2M=",
"count": 20,
"resultCount": 5
},
"referrals": [
{
"uuid": "254fa374-6d05-4a41-bfd8-254ba2039049",
"status": "COMPLETE",
"object": "referral",
"tests": ["tft", "free-testosterone"],
"metadata": {
"internalId": "1234"
},
"productId": "prod_abc123",
"productName": "Comprehensive Health Check",
"origin": "API",
"person": {
"firstName": "John",
"lastName": "Vein",
"email": "john.vein@eirly.health",
"address": {
"addressLine1": "123 Example Way",
"postCode": "4000",
"city": "Brisbane",
"state": "QLD"
},
"phone": "0412345678",
"dob": "1980-01-01",
"gender": "male"
},
"referralType": "blood",
"referenceNumber": "12345678",
"emailSentAt": "2024-06-04T05:29:09.385Z",
"createdAt": "2024-06-04T05:29:06.508Z",
"resultsUuid": "d9d820a4-72e1-41bc-9fac-ffb23f18dfb4"
}
]
}

Update Referral

PATCH /v1/referrals/{uuid}

Updates person details and/or metadata on an existing referral. A new referral PDF will be generated after the update.

Status Restriction

Only referrals with a status of CREATED or ISSUED can be updated. Attempting to update a referral with any other status (e.g. COMPLETE, PARTIAL_RESULTS, REFUNDED) will return an error.

All fields are optional — only the fields you include in the request body will be updated. Omitted fields remain unchanged.

Request Body:

FieldTypeDescription
firstNamestringPatient's first name (min 2 chars)
lastNamestringPatient's last name (min 2 chars)
emailstringPatient's email address
dobstringDate of birth (format: YYYY-MM-DD)
genderstringmale or female
phonestringPhone number (min 6 chars)
addressobjectAddress object (see Create Referral)
metadataobjectKey-value pairs (see Metadata Merging)

Metadata Merging:

Metadata is merged with the existing metadata on the referral rather than replaced. To remove a key, set its value to null:

{
"metadata": {
"newKey": "new-value",
"existingKey": "updated-value",
"keyToRemove": null
}
}

Example — update name and email:

{
"firstName": "Jane",
"lastName": "Doe",
"email": "jane.doe@example.com"
}

Example — update address:

{
"address": {
"addressLine1": "456 New Street",
"addressLine2": "Unit 3",
"postCode": "2000",
"city": "Sydney",
"country": "Australia",
"state": "NSW"
}
}

Response (200 OK):

{
"uuid": "254fa374-6d05-4a41-bfd8-254ba2039049",
"status": "SCHEDULED_REISSUE",
"object": "referral",
"tests": ["tft", "free-testosterone"],
"metadata": {
"internalId": "5678"
},
"productId": "prod_abc123",
"productName": "Comprehensive Health Check",
"origin": "API",
"person": {
"firstName": "Jane",
"lastName": "Doe",
"email": "jane.doe@example.com",
"address": {
"addressLine1": "123 Example Way",
"addressLine2": null,
"postCode": "4000",
"city": "Brisbane",
"country": "Australia",
"state": "QLD"
},
"phone": "0412345678",
"dob": "1980-01-01",
"gender": "male"
},
"referralType": "blood",
"referenceNumber": "12345678",
"emailSentAt": "2024-06-04T05:29:09.385Z",
"createdAt": "2024-06-04T05:29:06.508Z",
"updatedAt": "2024-06-04T06:15:00.000Z",
"resultsUuid": null
}
tip

After a successful update, the referral status will change to SCHEDULED_REISSUE while a new PDF is generated. Once the PDF is ready, the status will return to ISSUED.

Delete Referral

DELETE /v1/referrals/{uuid}

Soft-deletes a referral. The referral will be marked as deleted but not permanently removed. The referralAttachment URL is cleared on deletion.

Response (200 OK):

{
"uuid": "254fa374-6d05-4a41-bfd8-254ba2039049",
"status": "COMPLETE",
"object": "referral",
"tests": ["tft", "free-testosterone"],
"metadata": {
"internalId": "1234"
},
"productId": "prod_abc123",
"productName": "Comprehensive Health Check",
"origin": "API",
"person": {
"firstName": "John",
"lastName": "Vein",
"email": "john.vein@eirly.health",
"address": {
"addressLine1": "123 Example Way",
"addressLine2": null,
"postCode": "4000",
"city": "Brisbane",
"country": "Australia",
"state": "QLD"
},
"phone": "0412345678",
"dob": "1980-01-01",
"gender": "male"
},
"referralType": "blood",
"referenceNumber": "12345678",
"referralAttachment": null,
"emailSentAt": "2024-06-04T05:29:09.385Z",
"createdAt": "2024-06-04T05:29:06.508Z",
"updatedAt": "2024-06-04T07:00:00.000Z",
"deletedAt": "2024-06-04T07:00:00.000Z",
"resultsUuid": "d9d820a4-72e1-41bc-9fac-ffb23f18dfb4"
}

Simulate Results (Staging Only)

PUT /v1/referrals/{uuid}
Staging only

This endpoint is only available in the staging environment and will return 404 in production. It is intended for integrators testing end-to-end flows without waiting for a real lab to return results.

Generates a set of random dummy results for the referral, allowing you to exercise the result-related endpoints, webhooks, and your downstream handling code without involving a real pathology lab.

Query Parameters:

  • partial (flag, optional) — if present (e.g. ?partial), only a partial set of results is generated and the referral transitions to PARTIAL_RESULTS instead of COMPLETE. Useful for testing how your integration handles PARTIAL_RESULTSCOMPLETE transitions and the associated webhooks.

Examples:

PUT /v1/referrals/254fa374-6d05-4a41-bfd8-254ba2039049
PUT /v1/referrals/254fa374-6d05-4a41-bfd8-254ba2039049?partial

Response (200 OK): Returns the updated referral. Once results have been generated, resultsUuid will be populated and the corresponding result can be fetched via GET /v1/results/{resultsUuid}.

Results

Results contain biomarker data and test outcomes for completed referrals.

Get Result

GET /v1/results/{uuid}

Retrieves detailed results for a specific result UUID.

Response (200 OK):

{
"uuid": "d9d820a4-72e1-41bc-9fac-ffb23f18dfb4",
"referralUuid": "254fa374-6d05-4a41-bfd8-254ba2039049",
"status": "COMPLETE",
"object": "result",
"referenceNumber": "12345678",
"productId": "prod_abc123",
"productName": "Comprehensive Health Check",
"origin": "API",
"resultAttachment": "https://api.eirly.health/download/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmaWxlVXVpZCI6IjNiNmVjYzA4LTE0gmEtNDk4Ni1iYjYzLTdkgDJiZGZjNzU3ZSIsInByb2ZpbGVVdWlkIjoiMTQxZjQ5NTgtYzJkYi00NDY1LWIwMTEtODc3MmZmZjQzMzU3IiwicmFuZG9tVmFsdWUiOiJJWk5vN2VKOEFmcWM4bFpjS0lRcmt3YXlzZ1o2RjMiLCJvcmdhbmlzYXRpb25VdWlkIjoiNWQ0NDkxOTQtYzVjMS00NDUgLWIyNTQtZGRhNzg0MjdkZjllIiwiZm9yY2VEb3dubG9hZCI6dHJ1ZSwiaWF0IjoxNzc5NDI2MjExLCJleHAiOjE3Nzk0MjcxMTF9.A5jHeOt7W71IqN5sbxnK7jsYiZ9LO6NB7wK42F5aTCw",
"createdAt": "2024-06-04T05:30:08.699Z",
"updatedAt": "2024-06-04T05:30:08.699Z",
"deletedAt": null,
"resultDate": "2024-05-29T15:29:00.000Z",
"reviewedBy": null,
"person": {
"firstName": "John",
"lastName": "Vein",
"email": "john.vein@eirly.health",
"address": {
"addressLine1": "123 Example Way",
"postCode": "4000",
"city": "Brisbane",
"state": "QLD"
},
"phone": "0412345678",
"dob": "1980-01-01",
"gender": "male"
},
"metadata": {
"internalId": "1234"
},
"biomarkerSummary": {
"normal": 18,
"abnormal": 2,
"critical": 0,
"total": 20
},
"biomarkers": [
{
"commonName": "Active Vitamin B12",
"description": "Active Vitamin B12 (Holotranscobalamin) is the bioavailable portion...",
"formattedValue": "2 pmol/L",
"id": "active-vitamin-b12",
"isAbnormal": false,
"name": "Active Vitamin B12",
"object": "biomarker",
"unit": "pmol/L",
"sampleType": "serum",
"notes": "Sample was collected fasting. Serum separator tube used.",
"category": {
"id": "vitamins-and-minerals",
"name": "Vitamins & Minerals",
"description": "Vitamins and minerals are important for the body...",
"object": "biomarker-category"
},
"valueType": "numeric",
"value": "2",
"subValueType": null,
"refIntervalHigh": 4,
"refIntervalLow": 1,
"additionalRanges": null
}
]
}

Notable fields:

FieldTypeDescription
referralUuidstring (uuid)UUID of the referral this result was generated from.
resultAttachmentstring (url) | nullSigned URL to the result PDF. May be null if a PDF has not yet been generated. URLs are time-limited — re-fetch the result to obtain a fresh URL.
originstring | nullWhere the originating referral came from (e.g. API).
createdAtstring (ISO 8601)Time the result record was created.
deletedAtstring (ISO 8601) | nullSet if the result has been soft-deleted.
biomarkerSummaryobject | nullAggregated counts of normal, abnormal, critical, and total biomarkers on the result.
biomarkers[].sampleTypestring | nullThe sample type used for this biomarker (e.g. serum, whole-blood).
biomarkers[].notesstring | nullLab-provided notes for the individual biomarker, if any.
biomarkers[].additionalRangesarray | nullAdditional reference ranges for numeric biomarkers (e.g. menstrual cycle-phase bands for female hormones, or lipid risk targets). null for string-valued biomarkers, and null (or omitted) on numeric biomarkers that have no extra ranges. See below for the entry shape and examples.

additionalRanges entry shape:

Each entry in additionalRanges describes one alternative reference interval that applies in a specific context (cycle phase, lipid risk target, etc.). The biomarker's top-level refIntervalLow / refIntervalHigh remain the default range — additionalRanges are supplementary and consumers should continue to use the primary range for the default in/out-of-range determination.

FieldTypeDescription
idstringIdentifier for the range (e.g. cycle phase key, "high-risk").
namestringHuman-readable name for the range (e.g. "Follicular phase", "Lipid risk target").
categorystringCategory the range belongs to (e.g. "female-hormone", "lipid-risk-target").
lowRangenumber | nullLower bound of the range. null means open-ended on the low side (e.g. < highRange).
highRangenumber | nullUpper bound of the range. null means open-ended on the high side (e.g. > lowRange).

Example — female sex hormone with cycle-phase ranges (e.g. Oestradiol, FSH, LH, Progesterone):

For female hormone biomarkers, the lab cannot determine the patient's cycle phase, so the primary refIntervalLow / refIntervalHigh are typically null and all phase-specific ranges are returned via additionalRanges:

"additionalRanges": [
{ "id": "follicular", "name": "Follicular phase", "category": "female-hormone", "lowRange": 46, "highRange": 607 },
{ "id": "ovulation", "name": "Ovulation", "category": "female-hormone", "lowRange": 315, "highRange": 1828 },
{ "id": "luteal", "name": "Luteal phase", "category": "female-hormone", "lowRange": 161, "highRange": 774 },
{ "id": "post-menopause", "name": "Post-menopausal", "category": "female-hormone", "lowRange": null, "highRange": 201 }
]

Example — lipid risk targets (e.g. Total Cholesterol, LDL, HDL, Triglycerides, Non-HDL):

Some lipid panels include a separate cardiovascular risk target (e.g. NVDPA high-risk targets) alongside the standard reference range. The standard range is reported as the primary refIntervalLow / refIntervalHigh, and the risk target is exposed as a "high-risk" entry under additionalRanges:

// LDL Cholesterol — primary range is the lab's standard reference, additional
// entry is the high-cardiovascular-risk target (< 2.0 mmol/L)
"refIntervalLow": null,
"refIntervalHigh": 3.4,
"additionalRanges": [
{ "id": "high-risk", "name": "Lipid risk target", "category": "lipid-risk-target", "lowRange": null, "highRange": 2.0 }
]
// HDL Cholesterol — high-risk target is a *minimum* (> 1.0 mmol/L), so
// highRange is null
"refIntervalLow": 1.0,
"refIntervalHigh": null,
"additionalRanges": [
{ "id": "high-risk", "name": "Lipid risk target", "category": "lipid-risk-target", "lowRange": 1.0, "highRange": null }
]

Most biomarkers will return "additionalRanges": null — only those with clinically meaningful contextual ranges (female sex hormones, lipid risk targets) populate the array.

List Results

GET /v1/results

Returns all results for your organisation with pagination support.

Query Parameters:

  • count (integer, optional) - Number of results to return (max 20, default 20)
  • cursor (string, optional) - Cursor for pagination
  • sort (string, optional) - Sort order: asc or desc (default: asc)

Response (200 OK): Array of results with cursor metadata

Tests

Tests represent available blood tests and their pricing.

List Tests

GET /v1/tests

Returns all available tests for your organisation.

Response (200 OK):

[
{
"id": "cortisol",
"name": "Cortisol",
"shortName": "Cortisol",
"price": 356,
"object": "test",
"turnAroundTimeAverage": {
"maximumDays": 7,
"minimumDays": 7,
"object": "turnaroundTime"
},
"turnAroundTimes": [
{
"maximumDays": null,
"minimumDays": null,
"providerId": "4cyte",
"providerName": "4Cyte Pathology",
"object": "providerTurnaroundTime"
}
]
}
]

Notes:

  • Prices are in cents (divide by 100 for dollar amount)
  • v1.0.0 returns blood tests only
  • v1.1.0 returns all available test types

Bundles

Bundles are pre-configured groups of tests that can be purchased together (v1.1.0+ only).

List Bundles

GET /v1/bundles

Headers Required:

Accept: application/vnd.bgt.v1.1.0+json

Query Parameters:

  • count (integer, optional) - Number of results to return (max 20, default 20)
  • cursor (string, optional) - Cursor for pagination
  • sort (string, optional) - Sort order: asc or desc (default: asc)

Response (200 OK):

{
"cursor": {
"cursor": "MjAyNC0wNi0wNFQxMjo1OTowMS44MDJafGNyZWF0ZWRBdHxhc2M=",
"count": 20,
"resultCount": 5
},
"bundles": [
{
"id": "254fa374-6d05-4a41-bfd8-254ba2039049",
"name": "Comprehensive Health Panel",
"object": "bundle",
"tests": [
{
"id": "tft",
"name": "Thyroid Function Test",
"object": "test"
}
],
"createdAt": "2024-06-04T05:29:06.508Z"
}
]
}

Common Response Codes

CodeDescription
200Success
400Bad Request - Invalid parameters or payload
401Unauthorized - Missing or invalid access token
404Not Found - Resource does not exist
500Internal Server Error

Error Response Format

All error responses follow this structure:

{
"error": true,
"code": "ERROR_CODE",
"message": "Human readable error message",
"errorList": ["Additional error details"]
}

Common Error Codes

CodeMessage
MISSING_AUTHORIZATION_HEADERMissing Authorization header
INVALID_JWTInvalid access token
INVALID_JWT_SIGNATUREInvalid JWT Signature
INVALID_PARAMETERThe parameter provided is invalid
INVALID_PAYLOADThe payload provided is invalid
REFERRAL_NOT_FOUNDUnable to find the specified referral
RESULT_NOT_FOUNDUnable to find the specified result

Pagination

List endpoints support cursor-based pagination:

  1. Make initial request without cursor
  2. Response includes cursor.cursor value
  3. Pass this value as cursor query parameter in next request
  4. Repeat until cursor.resultCount is less than requested count

Metadata

Custom metadata can be attached to referrals for correlation purposes:

{
"metadata": {
"internalId": "your-internal-id",
"customField": "custom-value"
}
}

Metadata is returned with the referral and results objects, allowing you to correlate Eirly records with your internal systems.

Rate Limiting

API rate limits apply per organisation. Contact Eirly if you require higher limits.

Support

For API support:

  • Review the Swagger Documentation for interactive examples
  • See Webhooks for real-time notifications
  • Contact the Eirly API team for integration assistance