REST API
The BGT 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.bloodygoodtests.com.au
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, Medicare ordering, 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@bloodygoodtests.com.au",
"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"
},
"reference": "48213907",
"referenceNumber": "12345678",
"emailReferralToCustomer": true
}
Optional Fields:
| Field | Type | Default | Description |
|---|---|---|---|
emailReferralToCustomer | boolean | true | Controls whether BGT emails the referral PDF directly to the customer. Set to false if you want to deliver the referral to the customer yourself — when disabled, BGT 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@bloodygoodtests.com.au",
"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 tests, bundleId, or medicareTests must be provided — sending none 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.
For v1.1.0 - Medicare ordering:
A single request can also order Medicare tests by passing medicareTests. These tests are ordered under a doctor's provider number and claimed against Medicare — they are not billed to your organisation. Commercial tests (tests / bundleId) continue to be billed exactly as before.
medicareTests is not a guarantee that the patient pays nothingThe field name says how the test is ordered — under Medicare, with the practitioner's provider number. Whether Medicare covers a given test in full is determined by the collecting laboratory and the patient's Medicare eligibility at the time of collection, and the patient may still be charged a gap or the full fee. Do not present these tests to your customers as guaranteed to be free.
When medicareTests is provided, the request produces two separate referrals — one commercial referral for tests/bundleId and one Medicare referral for medicareTests (issued on a Medicare request form). The response is therefore an array of referrals, and the customer receives a single email with both referral PDFs attached.
orderingPractitioner.providerNumber is not accepted as a free-form value. Before it can be used in an API request, the provider must be configured on the BGT platform:
- The provider number must be registered against the organisation that owns your API credentials. All API access is scoped to a single organisation, and the provider number you send must belong to a practitioner registered in that organisation. A provider number that isn't registered for your organisation is rejected with
INVALID_PROVIDER_NUMBER. - That practitioner must have a signature on file for the organisation. The signature is drawn and stored on the platform (Settings → Provider Numbers) — it cannot be supplied through the API — and it is what gets printed on the Medicare referral. If no signature is on file for the provider number, the request is rejected with
MISSING_PROVIDER_SIGNATURE.
This is a one-time, per-practitioner, per-organisation setup done in the app, not via the API. See the Practitioners → Medicare guide for the full setup flow.
{
"firstName": "Jane",
"lastName": "Doe",
"email": "john.vein@bloodygoodtests.com.au",
"address": {
"addressLine1": "456 Sample Street",
"postCode": "2000",
"city": "Sydney",
"country": "Australia",
"state": "NSW"
},
"dob": "1992-05-15",
"gender": "female",
"phone": "0498765432",
"tests": ["free-testosterone"],
"medicareTests": ["vitamin-d", "iron-studies"],
"orderingPractitioner": {
"name": "Dr Bill Smith",
"address": "123 Example St, Sydney NSW 2000",
"providerNumber": "2426621B"
},
"medicareCardNumber": "1234567890",
"dvaNumber": "QX123456",
"clinicalNotes": "Fatigue, ?anaemia",
"referenceNumber": "55667788"
}
Medicare fields:
| Field | Type | Required | Description |
|---|---|---|---|
medicareTests | string[] | — | Tests to order under Medicare using the practitioner's provider number. Produces a separate Medicare referral. Not a guarantee that the patient pays nothing. |
orderingPractitioner | object | when medicareTests is present | The ordering doctor: name, address, and providerNumber (all required). The providerNumber must be registered — with a signature — against your organisation (see prerequisite above). |
medicareCardNumber | string | when medicareTests is present | Patient's Medicare card number — 10 digits (optionally followed by a 1-digit IRN). |
dvaNumber | string | — | Patient's DVA file number, if applicable. |
clinicalNotes | string | — | The ordering doctor's clinical notes for the Medicare referral. Kept separate from BGT's auto-generated clinical notes. |
Notes:
- Medicare ordering requires v1.1.0 and above. Sending
medicareTestsagainstv1.0.0returns a400error directing you to upgrade the version header (thev1.0.0single-referral response cannot represent two referrals). - The provider number must be registered against your organisation. The organisation is determined by the API credentials used for the request, and the
providerNumberyou send must belong to a practitioner registered in that organisation. If it isn't, the request is rejected withINVALID_PROVIDER_NUMBER. - A signature must be on file for that provider number. Signatures are captured on the platform (Settings → Provider Numbers), not via the API. A provider number with no signature on file is rejected with
MISSING_PROVIDER_SIGNATURE. OmittingorderingPractitionerentirely returnsMISSING_PROVIDER_NUMBER. orderingPractitioner.providerNumbermust also be a valid 8-character Medicare provider number, andmedicareCardNumbermust be 10 digits (optionally + IRN). Malformed identifiers return a400.- Only pathology (blood) tests can be ordered under Medicare. Including a non-eligible test in
medicareTestsis rejected withINVALID_MEDICARE_TEST. - The same test id may appear in both
testsandmedicareTests— ordering the same test as both commercial and Medicare is valid and yields it on both referrals. Duplicates within a single list are de-duplicated. - You may send
medicareTestson its own (notests/bundleId) to create a Medicare referral only. - Result routing is advisory, not a prerequisite. The Medicare referral is always created regardless of whether the provider number has result routing configured. The Medicare referral in the response carries a
routingMessagedescribing whether (and from which labs) the practitioner's Medicare results will route back to them automatically, and — when routing isn't set up — how to configure it. See theroutingMessagefield in the response table below.
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@bloodygoodtests.com.au",
"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",
"reference": "48213907",
"referenceNumber": "12345678",
"referralAttachment": "https://api.bloodygoodtests.com.au/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,
"medicare": false,
"orderingPractitioner": null,
"medicareCardNumber": null,
"dvaNumber": null,
"orderingPractitionerClinicalNotes": null,
"routingMessage": null
}
Notable response fields:
| Field | Type | Description |
|---|---|---|
reference | string | Our unique reference for this referral (8 digits). Distinct from referenceNumber, which is the value you supplied on create. |
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). |
medicare | boolean | true if this referral was ordered under Medicare, false for a commercial referral. Not a statement about what the patient was ultimately charged. |
orderingPractitioner | object | null | The ordering doctor (name, address, providerNumber). Present on Medicare referrals only. |
medicareCardNumber | string | null | Patient's Medicare card number. Present on Medicare referrals only. |
dvaNumber | string | null | Patient's DVA file number. Present on Medicare referrals only. |
orderingPractitionerClinicalNotes | string | null | The ordering doctor's clinical notes. Present on Medicare referrals only. |
routingMessage | string | null | Advisory, human-readable summary of whether (and from which labs) the Medicare results will route back to the practitioner automatically. Advisory only — never blocks the order. Populated on the Medicare referral returned from Create; null on commercial referrals and on all other endpoints. |
Note: When a request includes
medicareTests, this endpoint returns an array of referrals (one commercial, one Medicare) rather than a single object.
Response (200 OK) — Medicare request (array):
[
{
"uuid": "254fa374-6d05-4a41-bfd8-254ba2039049",
"status": "ISSUED",
"object": "referral",
"tests": ["free-testosterone"],
"metadata": null,
"productId": null,
"productName": null,
"origin": "API",
"person": {
"firstName": "Jane",
"lastName": "Doe",
"email": "john.vein@bloodygoodtests.com.au",
"address": {
"addressLine1": "456 Sample Street",
"addressLine2": null,
"postCode": "2000",
"city": "Sydney",
"country": "Australia",
"state": "NSW"
},
"phone": "0498765432",
"dob": "1992-05-15",
"gender": "female"
},
"referralType": "blood",
"reference": "48213907",
"referenceNumber": "55667788",
"referralAttachment": "https://api.bloodygoodtests.com.au/download/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"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,
"medicare": false,
"orderingPractitioner": null,
"medicareCardNumber": null,
"dvaNumber": null,
"orderingPractitionerClinicalNotes": null,
"routingMessage": null
},
{
"uuid": "9b1f3c7a-2e54-4d0b-8a61-1c2d3e4f5a6b",
"status": "ISSUED",
"object": "referral",
"tests": ["vitamin-d", "iron-studies"],
"metadata": null,
"productId": null,
"productName": null,
"origin": "API",
"person": {
"firstName": "Jane",
"lastName": "Doe",
"email": "john.vein@bloodygoodtests.com.au",
"address": {
"addressLine1": "456 Sample Street",
"addressLine2": null,
"postCode": "2000",
"city": "Sydney",
"country": "Australia",
"state": "NSW"
},
"phone": "0498765432",
"dob": "1992-05-15",
"gender": "female"
},
"referralType": "blood",
"reference": "48213907",
"referenceNumber": "55667788",
"referralAttachment": "https://api.bloodygoodtests.com.au/download/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"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,
"medicare": true,
"orderingPractitioner": {
"name": "Dr Bill Smith",
"address": "123 Example St, Sydney NSW 2000",
"providerNumber": "2426621B"
},
"medicareCardNumber": "1234567890",
"dvaNumber": "QX123456",
"orderingPractitionerClinicalNotes": "Fatigue, ?anaemia",
"routingMessage": "Result routing isn't set up for provider number 2426621B, so Medicare results won't route back to you automatically. Set up result routing at https://app.bloodygoodtests.com.au/org/your-org/settings/result-routing."
}
]
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@bloodygoodtests.com.au",
"address": {
"addressLine1": "123 Example Way",
"postCode": "4000",
"city": "Brisbane",
"state": "QLD"
},
"phone": "0412345678",
"dob": "1980-01-01",
"gender": "male"
},
"referralType": "blood",
"reference": "48213907",
"referenceNumber": "12345678",
"referralAttachment": "https://api.bloodygoodtests.com.au/download/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"emailSentAt": "2024-06-04T05:29:09.385Z",
"createdAt": "2024-06-04T05:29:06.508Z",
"updatedAt": "2024-06-04T05:29:09.385Z",
"deletedAt": null,
"resultsUuid": "d9d820a4-72e1-41bc-9fac-ffb23f18dfb4",
"medicare": false,
"orderingPractitioner": null,
"medicareCardNumber": null,
"dvaNumber": null,
"orderingPractitionerClinicalNotes": null,
"routingMessage": null
}
]
}
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",
"reference": "48213907",
"referenceNumber": "12345678",
"referralAttachment": "https://api.bloodygoodtests.com.au/download/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"emailSentAt": "2024-06-04T05:29:09.385Z",
"createdAt": "2024-06-04T05:29:06.508Z",
"updatedAt": "2024-06-04T06:15:00.000Z",
"deletedAt": null,
"resultsUuid": null,
"medicare": false,
"orderingPractitioner": null,
"medicareCardNumber": null,
"dvaNumber": null,
"orderingPractitionerClinicalNotes": null,
"routingMessage": 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@bloodygoodtests.com.au",
"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",
"reference": "48213907",
"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",
"medicare": false,
"orderingPractitioner": null,
"medicareCardNumber": null,
"dvaNumber": null,
"orderingPractitionerClinicalNotes": null,
"routingMessage": null
}
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",
"reference": "48213907",
"referenceNumber": "12345678",
"productId": "prod_abc123",
"productName": "Comprehensive Health Check",
"origin": "API",
"resultAttachment": "https://api.bloodygoodtests.com.au/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@bloodygoodtests.com.au",
"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:
{
"refIntervalLow": null,
"refIntervalHigh": null,
"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 — the primary range is the lab's standard reference; the 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 — the 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 |
| MISSING_PROVIDER_NUMBER | An ordering practitioner is required for Medicare tests |
| INVALID_PROVIDER_NUMBER | Provider number is not registered for your organisation (or is malformed) |
| MISSING_PROVIDER_SIGNATURE | No Medicare signature on file for the provided provider number |
| INVALID_MEDICARE_TEST | Only pathology (blood) tests can be ordered under Medicare |
| INVALID_MEDICARE_NUMBER | The patient's Medicare card number is missing or invalid |
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 BGT records with your internal systems.
Rate Limiting
API rate limits apply per organisation. Contact BGT if you require higher limits.
Support
For API support:
- Review the Swagger Documentation for interactive examples
- See Webhooks for real-time notifications
- Contact the BGT API team for integration assistance