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
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:
| Field | Type | Default | Description |
|---|---|---|---|
emailReferralToCustomer | boolean | true | Controls 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.
| Provided | Behaviour |
|---|---|
tests only | The referral is created with exactly the tests you listed. |
bundleId only | The 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 tests | The 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:
bundleIdis only accepted on v1.1.0 and above. Sending abundleIdagainstv1.0.0will return a400error directing you to upgrade the version header.- The response's
testsarray reflects the fully-resolved list of tests on the referral, regardless of whether they came from a bundle, thetestsfield, 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:
| Field | Type | Description |
|---|---|---|
referralAttachment | string (url) | null | Signed 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. |
updatedAt | string (ISO 8601) | Time the referral record was last modified. Updated whenever the referral status changes or fields are edited via PATCH. |
deletedAt | string (ISO 8601) | null | Set when the referral has been soft-deleted via DELETE; null otherwise. |
emailSentAt | string (ISO 8601) | null | Time the referral email was dispatched to the customer. null if emailReferralToCustomer was false, or before delivery has occurred. |
resultsUuid | string (uuid) | null | UUID 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 paginationsort(string, optional) - Sort order:ascordesc(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.
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:
| Field | Type | Description |
|---|---|---|
firstName | string | Patient's first name (min 2 chars) |
lastName | string | Patient's last name (min 2 chars) |
email | string | Patient's email address |
dob | string | Date of birth (format: YYYY-MM-DD) |
gender | string | male or female |
phone | string | Phone number (min 6 chars) |
address | object | Address object (see Create Referral) |
metadata | object | Key-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
}
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}
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 toPARTIAL_RESULTSinstead ofCOMPLETE. Useful for testing how your integration handlesPARTIAL_RESULTS→COMPLETEtransitions 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:
| Field | Type | Description |
|---|---|---|
referralUuid | string (uuid) | UUID of the referral this result was generated from. |
resultAttachment | string (url) | null | Signed 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. |
origin | string | null | Where the originating referral came from (e.g. API). |
createdAt | string (ISO 8601) | Time the result record was created. |
deletedAt | string (ISO 8601) | null | Set if the result has been soft-deleted. |
biomarkerSummary | object | null | Aggregated counts of normal, abnormal, critical, and total biomarkers on the result. |
biomarkers[].sampleType | string | null | The sample type used for this biomarker (e.g. serum, whole-blood). |
biomarkers[].notes | string | null | Lab-provided notes for the individual biomarker, if any. |
biomarkers[].additionalRanges | array | null | Additional 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.
| Field | Type | Description |
|---|---|---|
id | string | Identifier for the range (e.g. cycle phase key, "high-risk"). |
name | string | Human-readable name for the range (e.g. "Follicular phase", "Lipid risk target"). |
category | string | Category the range belongs to (e.g. "female-hormone", "lipid-risk-target"). |
lowRange | number | null | Lower bound of the range. null means open-ended on the low side (e.g. < highRange). |
highRange | number | null | Upper 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 paginationsort(string, optional) - Sort order:ascordesc(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 paginationsort(string, optional) - Sort order:ascordesc(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
| Code | Description |
|---|---|
| 200 | Success |
| 400 | Bad Request - Invalid parameters or payload |
| 401 | Unauthorized - Missing or invalid access token |
| 404 | Not Found - Resource does not exist |
| 500 | Internal 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
| Code | Message |
|---|---|
| MISSING_AUTHORIZATION_HEADER | Missing Authorization header |
| INVALID_JWT | Invalid access token |
| INVALID_JWT_SIGNATURE | Invalid JWT Signature |
| INVALID_PARAMETER | The parameter provided is invalid |
| INVALID_PAYLOAD | The payload provided is invalid |
| REFERRAL_NOT_FOUND | Unable to find the specified referral |
| RESULT_NOT_FOUND | Unable to find the specified result |
Pagination
List endpoints support cursor-based pagination:
- Make initial request without cursor
- Response includes
cursor.cursorvalue - Pass this value as
cursorquery parameter in next request - Repeat until
cursor.resultCountis less than requestedcount
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