AHPRA Registration Verification
This comprehensive guide shows you how to integrate AHPRA (Australian Health Practitioner Regulation Agency) registration verification using the Oho API.
Overview
The /api/scan endpoint provides a unified interface for validating AHPRA health practitioner registrations across all regulated professions. Validations are processed asynchronously - the endpoint queues the request and returns immediately with a correlation_id for tracking. Results are delivered later via webhook.
AHPRA maintains the national register of health practitioners, and Oho provides real-time verification against this public register to confirm current registration status, conditions, and endorsements.
Base URL: POST /api/scan
Authentication: Required (Bearer token)
Content-Type: application/json
Key Benefits:
- ✅ Real-time verification against AHPRA's national register
- ✅ Instant status confirmation (typically less than 5 seconds)
- ✅ Automatic detection of registration conditions and restrictions
- ✅ Support for all 16 regulated health professions
- ✅ Asynchronous processing for high performance
- ✅ Built-in retry logic and webhook delivery
What is AHPRA?
AHPRA (Australian Health Practitioner Regulation Agency) is the organization responsible for regulating health practitioners across Australia. AHPRA works with 15 National Boards to implement the National Registration and Accreditation Scheme (NRAS).
Regulated Professions:
- Medical Practitioners (Doctors)
- Nursing and Midwifery
- Pharmacy
- Physiotherapy
- Psychology
- Dentistry (including Dental Hygienists, Dental Prosthetists, Dental Therapists)
- Chiropractic
- Optometry
- Osteopathy
- Paramedicine
- Podiatry
- Aboriginal and Torres Strait Islander Health Practice
- Chinese Medicine
- Medical Radiation Practice
- Occupational Therapy
Understanding AHPRA Registration
How to Interpret Results
Oho provides a simplified verification interface using two key indicators:
1. Status Color - Your primary decision point:
- Green ✅ - Registration is valid, practitioner may work
- Yellow ⚠️ - Registration needs attention (expiring soon, renewal pending)
- Red ❌ - Registration is invalid, expired, or suspended
2. Is Conditional - Compliance requirement:
- false - Normal registration with no restrictions
- true - Registration has conditions that must be reviewed
When to Allow Practice
IF status_color = "green" AND is_conditional = false:
✅ Practitioner is cleared to work
IF status_color = "green" AND is_conditional = true:
⚠️ Practitioner is registered BUT review conditions first
(check meta.ahpra.sections for condition details)
IF status_color = "yellow":
⚠️ REVIEW REQUIRED - Common reasons:
- Non-practising registration (ahpra_non_practising flag)
- Registration expiring soon
- Renewal pending
Check status_flags:
- If "ahpra_non_practising" is present → ❌ Cannot practice
- If "expiring" is present → ⚠️ Can practice but monitor renewal
- Review meta.ahpra.is_non_practising and registration_types
IF status_color = "red":
❌ Do not allow practice - Common reasons:
- Registration expired (status_flags: ["expired"])
- Registration not current (status_flags: ["not_current"])
* Name mismatch
* Details don't match AHPRA records
* Registration suspended or cancelled
- Not found in AHPRA register (meta.status.found: false)
Check meta.status.found and meta.status.current for details
Detailed Information: Full registration details (registration type, specialties, endorsements, qualifications, etc.) are available in the meta.ahpra object for deeper analysis when needed.
Getting Started
Prerequisites
Before submitting AHPRA validations, ensure:
- Active organization account - Your organization must be active and in good standing
- Verified user status - Your API user must have completed email verification
- Constituents created (optional) - If linking to existing constituents, they must exist in your organization first
Payload Structure
The AHPRA verification endpoint uses a simple, consistent payload structure:
{
"type": "ahpra",
"identifier": "AHPRA_REGISTRATION_NUMBER",
"first_name": "First",
"middle_name": "Middle (optional)",
"surname": "Last",
"profession": "MED|NUR|PHA|etc (optional)",
"constituent": {
"id": 123
}
}
Field Descriptions
| Field | Type | Description | Required |
|---|---|---|---|
type | string | Must be "ahpra" | Yes |
identifier | string | AHPRA registration number | Yes |
first_name | string | First/given name | Yes |
middle_name | string | Middle name(s) | No |
surname | string | Surname/family name | Yes |
profession | string | Profession code (see table below) | No |
constituent.id | integer | Link to existing constituent | No |
Profession Codes
When submitting AHPRA verification requests, you can optionally specify the profession type. This can improve matching accuracy when practitioners have registrations in multiple professions.
| Profession | Code | Common Titles |
|---|---|---|
| Medical Practitioner | MED | Doctor, GP, Specialist |
| Nursing and Midwifery | NUR | Registered Nurse, Enrolled Nurse, Midwife |
| Pharmacy | PHA | Pharmacist |
| Physiotherapy | PHY | Physiotherapist |
| Psychology | PSY | Psychologist |
| Dentistry | DEN | Dentist |
| Dental Hygienist | DHY | Dental Hygienist |
| Dental Prosthetist | DPR | Dental Prosthetist |
| Dental Therapist | DTH | Dental Therapist |
| Chiropractic | CHI | Chiropractor |
| Optometry | OPT | Optometrist |
| Osteopathy | OST | Osteopath |
| Paramedicine | PAR | Paramedic |
| Podiatry | POD | Podiatrist |
| Aboriginal and Torres Strait Islander Health Practice | ATS | Aboriginal Health Practitioner |
| Chinese Medicine | CHM | Chinese Medicine Practitioner, Acupuncturist |
| Medical Radiation Practice | MRP | Radiographer, Radiation Therapist |
| Occupational Therapy | OCC | Occupational Therapist |
Note: If profession is not specified, Oho will search across all professions for the registration number.
AHPRA Registration Number Format
AHPRA registration numbers follow a standardized format:
Format: 3 letters + 10 digits (e.g., MED0001234567)
Examples:
MED0001234567- Medical PractitionerNMW0001234567- Nursing and MidwiferyPHA0001234567- PharmacyPHY0001234567- PhysiotherapyPSY0001234567- Psychology
Common Variations:
- May include spaces:
MED 0001234567 - May include dashes:
MED-0001234567 - Oho automatically normalizes these formats
Finding Registration Numbers: Practitioners can find their AHPRA registration number:
- On their registration certificate
- In the AHPRA portal at ahpra.gov.au
- On the public register search results
Tracking Requests
Correlation ID
When you submit a scan request, the API returns a correlation_id:
{
"correlation_id": "d591aa45-64fa-46b9-8eab-423075ee66cb"
}
Important: The correlation_id does not persist from the initial request to the webhook response. You cannot rely on it to match webhook results back to your original requests.
Matching Webhook Results
To match webhook results back to your original requests, use the AHPRA registration number (identifier):
Your tracking approach should be:
- Store the
identifier(AHPRA number) with your internal records when submitting a scan - When you receive a webhook, match it using
content.current.identifier - Use
content.current.id(the accreditation ID) for long-term references
Example tracking pattern:
// When submitting scan
await database.savePendingScan({
ahpra_number: 'MED0001234567',
constituent_id: 12345,
status: 'pending',
submitted_at: new Date()
});
// When receiving webhook
async function handleWebhook(webhookData) {
const identifier = webhookData.content.current.identifier;
// Find your record by the AHPRA number
const scan = await database.findByIdentifier(identifier);
// Update with results
await database.updateScan(scan.id, {
accreditation_id: webhookData.content.current.id,
status: webhookData.content.current.status,
registry_response: webhookData.content.current.registry_response
});
}
---
## Quick Start Examples
### Basic AHPRA Check
```bash
curl -X POST https://app.weareoho.com/api/scan \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "ahpra",
"identifier": "MED0001234567",
"first_name": "Sarah",
"middle_name": "Jane",
"surname": "Johnson"
}'
Success Response:
{
"correlation_id": "d591aa45-64fa-46b9-8eab-423075ee66cb"
}
Medical Practitioner Verification
curl -X POST https://app.weareoho.com/api/scan \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "ahpra",
"identifier": "MED0001234567",
"first_name": "Sarah",
"middle_name": "Jane",
"surname": "Johnson",
"profession": "MED",
"constituent": {
"id": 12345
}
}'
Registered Nurse Verification
curl -X POST https://app.weareoho.com/api/scan \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "ahpra",
"identifier": "NMW0001234567",
"first_name": "Michael",
"surname": "Chen",
"profession": "NUR",
"constituent": {
"id": 12346
}
}'
Pharmacist Verification
curl -X POST https://app.weareoho.com/api/scan \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "ahpra",
"identifier": "PHA0001234567",
"first_name": "Emma",
"middle_name": "Rose",
"surname": "Williams",
"profession": "PHA",
"constituent": {
"id": 12347
}
}'
Physiotherapist Verification
curl -X POST https://app.weareoho.com/api/scan \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "ahpra",
"identifier": "PHY0001234567",
"first_name": "David",
"surname": "Smith",
"profession": "PHY",
"constituent": {
"id": 12348
}
}'
Linking to Existing Constituents
The API supports three workflows for managing AHPRA registrations:
Scenario 1: Link to Existing Constituent (Recommended)
When you want to associate the AHPRA registration with a person already in your system:
{
"type": "ahpra",
"identifier": "MED0001234567",
"first_name": "Sarah",
"surname": "Johnson",
"profession": "MED",
"constituent": {
"id": 12345
}
}
Behavior:
- ✅ Links accreditation to constituent ID
12345 - ✅ Accreditation appears in constituent's profile
- ✅ Auto-updates constituent with additional details if fields are null
- ❌ Returns
400error if constituent ID doesn't exist in your organization
When to use:
- You have a constituent database and want to track AHPRA registrations against people
- You need to see all accreditations for a specific person
- You want centralized compliance tracking
Scenario 2: Standalone Accreditation (No Constituent)
When you only want to validate credentials without linking to a person record:
{
"type": "ahpra",
"identifier": "MED0001234567",
"first_name": "Sarah",
"surname": "Johnson",
"profession": "MED"
}
Behavior:
- ✅ Creates standalone accreditation record
- ✅ Validates credentials against AHPRA register
- ✅ Stores result in your organization
- ⚠️ Not linked to any constituent profile
- ⚠️ Can be linked later via the UI or API
When to use:
- Quick one-off validations
- You don't maintain a constituent database
- Validating external contractors or locum staff
- Testing/development
Scenario 3: Invalid Constituent ID (Error)
When you provide a constituent ID that doesn't exist:
{
"type": "ahpra",
"identifier": "MED0001234567",
"first_name": "Sarah",
"surname": "Johnson",
"constituent": {
"id": 999999
}
}
Response (400 Bad Request):
{
"status": 400,
"message": "Validation error",
"errors": {
"constituent": {
"id": ["Constituent doesn't exist in your organization"]
}
}
}
How to avoid:
- Create the constituent first using
POST /api/constituents - Then submit the scan with the returned constituent ID
- Or omit
constituententirely for standalone accreditation
Webhook Configuration
Since the /api/scan endpoint processes requests asynchronously, results are delivered to your webhook endpoint when validation completes.
For detailed instructions on setting up webhooks, configuring endpoints, and security best practices, see the Webhook Integration Guide.
Webhook Payload Structure
When an AHPRA scan completes, we POST the following JSON to your webhook:
Example 1: Valid Registration (Green)
{
"event": "accreditation_validation",
"correlation_id": "d591aa45-64fa-46b9-8eab-423075ee66cb",
"message_id": 54321,
"content": {
"notification_type": "accreditation-result",
"org_id": 123,
"previous": null,
"current": {
"id": 8765,
"identifier": "NMW0001234567",
"type": "ahpra",
"status": "active",
"status_color": "green",
"status_flags": ["current"],
"registry_response": {
"status": "Registered",
"profession": "General - Nurse",
"is_conditional": false
},
"meta": {
"ahpra": {
"status": "Registered",
"sections": [
{
"label": "Registration details",
"conditions": "None",
"profession": "Nurse",
"reprimands": "None",
"undertakings": "None",
"registration_number": "NMW0001234567",
"registration_status": "Registered",
"registration_expiry_date": "31/05/2026",
"date_of_first_registration_in_profession": "15/03/2020"
},
{
"label": "Registration Type - Registered nurse",
"notations": "None",
"conditions": "None",
"endorsements": "None",
"registration_expiry_date": "31/05/2026",
"registration_requirements": "None"
},
{
"label": "Personal details",
"sex": "Female",
"qualifications": "Bachelor of Nursing, Example University, Australia, 2019",
"languages_in_addition_to_english": ""
},
{
"label": "Principal place of practice",
"state": "VIC",
"suburb": "MELBOURNE",
"country": "Australia",
"postcode": "3000"
}
],
"registration_types": ["General"]
},
"status": {
"found": true,
"current": true,
"messages": []
}
}
},
"constituent": {
"id": 12345,
"first_name": "Sarah",
"surname": "Johnson",
"email": "sarah.johnson@example.com"
}
}
}
Example 2: Non-Practising Registration (Yellow - Review Required)
{
"event": "accreditation_validation",
"correlation_id": "e782cd67-86fc-68db-0gbc-645297gg88ed",
"message_id": 54324,
"content": {
"notification_type": "accreditation-result",
"org_id": 123,
"previous": null,
"current": {
"id": 8766,
"identifier": "DEN0001234567",
"type": "ahpra",
"status": "active",
"status_color": "yellow",
"status_flags": ["is_conditional", "ahpra_non_practising"],
"registry_response": {
"status": "Registered",
"profession": "Non Practising - Dental Practitioner",
"supplement": "With Non Practising Registration",
"is_conditional": true
},
"meta": {
"ahpra": {
"status": "Registered",
"sections": [
{
"label": "Registration details",
"conditions": "None",
"profession": "Dental Practitioner",
"reprimands": "None",
"undertakings": "None",
"registration_number": "DEN0001234567",
"registration_status": "Registered",
"registration_expiry_date": "The registration expiry date is the end date for the annual registration period. Sometimes a practitioner will appear on the register with a registration expiry date that is in the past. This may be because their renewal application is still being finalised, or during a one month \"late period\" after the expiry date. However, they are still able to practise.",
"date_of_first_registration_in_profession": "22/12/2010"
},
{
"label": "Division/Registration Type - Dentist, Non Practising",
"notations": "None",
"conditions": "None",
"endorsements": "None",
"registration_expiry_date": "30/11/2026",
"registration_requirements": "None"
},
{
"label": "Personal details",
"sex": "Female",
"qualifications": "Bachelor of Dental Science, BDentSc, Example University, Australia, 2010",
"languages_in_addition_to_english": ""
},
{
"label": "Principal place of practice",
"state": "VIC",
"suburb": "RICHMOND",
"country": "Australia",
"postcode": "3121"
}
],
"is_non_practising": true,
"registration_types": ["Non Practising"]
},
"status": {
"found": true,
"current": true,
"messages": []
}
}
},
"constituent": {
"id": 12346,
"first_name": "Jane",
"surname": "Smith",
"email": "jane.smith@example.com"
}
}
}
Example 3: Not Current Registration (Red - Cannot Practice)
{
"event": "accreditation_validation",
"correlation_id": "f893de78-97hd-80fd-2ide-867419ii00gf",
"message_id": 54325,
"content": {
"notification_type": "accreditation-result",
"org_id": 123,
"previous": null,
"current": {
"id": 8767,
"identifier": "NMW0002234567",
"type": "ahpra",
"status": "inactive",
"status_color": "red",
"status_flags": ["not_current"],
"registry_response": {
"status": "Registered",
"profession": "Nurse",
"is_conditional": false
},
"meta": {
"ahpra": {
"status": "Registered",
"sections": [
{
"label": "Registration details",
"conditions": "None",
"profession": "Nurse",
"reprimands": "None",
"undertakings": "None",
"registration_number": "NMW0002234567",
"registration_status": "Registered",
"registration_expiry_date": "The registration expiry date is the end date for the annual registration period. Sometimes a practitioner will appear on the register with a registration expiry date that is in the past. This may be because their renewal application is still being finalised, or during a one month \"late period\" after the expiry date. However, they are still able to practise.",
"date_of_first_registration_in_profession": "27/03/2023"
},
{
"label": "Registration Type - Enrolled nurse",
"notations": "None",
"conditions": "None",
"endorsements": "None",
"registration_expiry_date": "31/05/2025",
"registration_requirements": "None"
},
{
"label": "Personal details",
"sex": "Female",
"qualifications": "Diploma of Nursing, Example College, Australia, 2022",
"languages_in_addition_to_english": "Gujarati, Hindi"
},
{
"label": "Principal place of practice",
"state": "SA",
"suburb": "ADELAIDE",
"country": "Australia",
"postcode": "5000"
}
],
"registration_types": ["General"]
},
"status": {
"found": false,
"current": false,
"messages": []
}
}
},
"constituent": {
"id": 12347,
"first_name": "Maria",
"surname": "Garcia",
"email": "maria.garcia@example.com"
}
}
}
Important: Even though registry_response.status shows "Registered", the critical indicators are:
status_color: "red"- Cannot practicestatus_flags: ["not_current"]- Registration not currentmeta.status.found: false- Validation failed (possible name mismatch or other issue)meta.status.current: false- Not current for practice
Key webhook fields:
content.current.status_color- Primary indicator:"green"(valid),"yellow"(review required),"red"(invalid/expired)content.current.status_flags- Array of flags indicating specific conditions:"current"- Registration is current and valid"not_current"- Critical: Registration is not current (cannot practice - name mismatch, expired, or validation failed)"is_conditional"- Has conditions/restrictions"ahpra_non_practising"- Non-practising registration (cannot practice)"expiring"- Registration expiring soon"expired"- Registration has expired
content.current.registry_response- AHPRA registration summarystatus- Registration status (e.g., "Registered", "Not registered")profession- The registered health profession (e.g., "General - Nurse", "Non Practising - Dental Practitioner")supplement- Additional context (e.g., "With Non Practising Registration") - present when applicableis_conditional- Critical:trueif conditions or non-practising,falseif normal registration
content.current.meta.ahpra- Complete AHPRA registry data including detailed sectionsis_non_practising-trueif non-practising registration (cannot practice)registration_types- Array of registration types (e.g.,["General"],["Non Practising"])
content.current.meta.status- Validation result from Oho's verificationfound-trueif registration validated successfully,falseif validation failedcurrent-trueif registration is current for practice,falseif not currentmessages- Array of validation messages (usually empty)
content.previous- Previous state (null for new checks, populated for updates)content.constituent- Details about the person checked
Understanding the Response
Primary Indicators
Use these fields to determine registration validity:
-
status_color- The primary indicator (check this first!)"green"- Registration is valid and current"yellow"- Registration needs attention (expiring soon, pending renewal)"red"- Registration is invalid, expired, or suspended
-
is_conditional- Critical compliance flagtrue- Practitioner has conditions on their registration (review required)false- No conditions (normal registration)
Registry Response Fields
The registry_response object provides a summary:
{
"status": "Registered",
"profession": "General - Nurse",
"is_conditional": false
}
Fields:
status- Registration status text (e.g., "Registered", "Not registered")profession- Full profession name and type (e.g., "General - Nurse", "Medical Practitioner")is_conditional- Whether conditions exist on the registration
Detailed AHPRA Data (meta.ahpra)
For complete registration details, use meta.ahpra.sections:
{
"ahpra": {
"status": "Registered",
"sections": [
{
"label": "Registration details",
"conditions": "None",
"profession": "Nurse",
"registration_status": "Registered",
"registration_expiry_date": "31/05/2026",
"reprimands": "None",
"undertakings": "None"
},
{
"label": "Registration Type - Registered nurse",
"conditions": "None",
"endorsements": "None",
"notations": "None"
}
],
"registration_types": ["General"]
}
}
Key sections:
- Registration details - Core registration info, conditions, expiry
- Registration Type - Specific type details, endorsements, requirements
- Personal details - Qualifications, languages (optional)
- Principal place of practice - Location information (optional)
Registration with Conditions Example
When a practitioner has conditions on their registration, is_conditional will be true:
{
"event": "accreditation_validation",
"correlation_id": "c782bd56-75eb-57ca-9fab-534186ff77dc",
"message_id": 54322,
"content": {
"notification_type": "accreditation-result",
"org_id": 123,
"previous": null,
"current": {
"id": 8766,
"identifier": "MED0001234568",
"type": "ahpra",
"status": "active",
"status_color": "green",
"status_flags": {
"current": true,
"may_engage": true,
"expired": false,
"expiring": false
},
"registry_response": {
"status": "Registered",
"profession": "Medical Practitioner",
"is_conditional": true
},
"meta": {
"ahpra": {
"status": "Registered",
"sections": [
{
"label": "Registration details",
"conditions": "Must practice under supervision of a registered medical practitioner. Limited to employment at Example Hospital. Must not prescribe Schedule 8 medicines.",
"profession": "Medical Practitioner",
"registration_status": "Registered",
"registration_expiry_date": "31/12/2025",
"reprimands": "None",
"undertakings": "None"
},
{
"label": "Registration Type - Limited",
"conditions": "Must practice under supervision",
"endorsements": "None",
"notations": "Conditional registration"
}
],
"registration_types": ["Limited"]
}
}
},
"constituent": {
"id": 12346,
"first_name": "John",
"surname": "Doe",
"email": "john.doe@example.com"
}
}
}
Important: When is_conditional is true, always review the detailed conditions in meta.ahpra.sections[].conditions to determine if the practitioner can work in your specific setting.
Error Webhook Example
When validation fails, the webhook contains error details:
{
"event": "accreditation_validation",
"correlation_id": "e893ce67-86fc-68db-0gbc-645297gg88ed",
"message_id": 54323,
"content": {
"notification_type": "accreditation-result",
"org_id": 123,
"previous": null,
"current": {
"id": null,
"identifier": "MED0001234999",
"type": "ahpra",
"status": "error",
"error": {
"message": "Registration not found or details do not match",
"code": "REGISTRATION_NOT_FOUND"
}
},
"constituent": {
"id": 12347,
"first_name": "Test",
"surname": "User"
},
"entity_type_id": 3,
"event_type_id": 2,
"changed_fields": null
}
}
Webhook Security & Retry Logic
For information on:
- Verifying webhook signatures
- Implementing security best practices
- Understanding retry behavior
- Handling failed webhooks
See the Webhook Integration Guide for complete details.
Response Time Expectations
AHPRA verification typically completes very quickly:
| Check Type | Typical Response Time |
|---|---|
| AHPRA Registration | 2-5 seconds |
Note: Times may vary based on registry availability. Maximum timeout is 30 seconds before we return a timeout status.
Error Responses
Invalid Registration Number (400)
{
"status": 400,
"message": "Validation error",
"errors": {
"identifier": ["Invalid AHPRA registration number format"]
}
}
Registration Not Found (via webhook)
When the registration number is valid but not found in AHPRA's register:
{
"status": "error",
"error": {
"message": "Registration not found or details do not match",
"code": "REGISTRATION_NOT_FOUND"
}
}
Name Mismatch (via webhook)
When the registration exists but the name doesn't match:
{
"status": "error",
"error": {
"message": "Name does not match AHPRA records",
"code": "NAME_MISMATCH"
}
}
Invalid Constituent (400)
{
"status": 400,
"message": "Validation error",
"errors": {
"constituent": {
"id": ["Constituent doesn't exist in your organization"]
}
}
}
Authentication Error (401)
{
"status": 401,
"message": "You are not authorized to view this resource",
"field": "authentication"
}
Service Unavailable (503)
{
"status": 503,
"message": "The target resource is currently unavailable"
}
Best Practices
1. Always Include Complete Names
For best matching results, include the practitioner's full name as it appears on their AHPRA registration:
{
"type": "ahpra",
"identifier": "MED0001234567",
"first_name": "Sarah",
"middle_name": "Jane",
"surname": "Johnson",
"profession": "MED"
}
2. Specify Profession When Known
While optional, specifying the profession code improves matching accuracy:
{
"type": "ahpra",
"identifier": "MED0001234567",
"first_name": "Sarah",
"surname": "Johnson",
"profession": "MED" // Improves matching
}
3. Check Status Color and Flags
Always check status_color and status_flags as your primary validation:
const statusColor = webhookData.content.current.status_color;
const statusFlags = webhookData.content.current.status_flags || [];
if (statusColor === 'green' && !statusFlags.includes('is_conditional')) {
// Registration is valid and unrestricted
console.log('✅ Registration is valid - approved to practice');
} else if (statusColor === 'green' && statusFlags.includes('is_conditional')) {
// Valid but has conditions - review required
console.warn('⚠️ Registration is valid but has conditions - review required');
} else if (statusColor === 'yellow') {
// Needs review - could be non-practising, expiring, etc.
console.warn('⚠️ Registration requires review');
if (statusFlags.includes('ahpra_non_practising')) {
console.error('❌ Non-practising registration - cannot practice');
return; // Do not approve for work
}
if (statusFlags.includes('expiring')) {
console.warn('⚠️ Registration expiring soon - monitor renewal');
}
} else if (statusColor === 'red') {
// Invalid, expired, or suspended
console.error('❌ Registration is not valid');
if (statusFlags.includes('not_current')) {
// Check meta for more details
const metaStatus = webhookData.content.current.meta?.status;
if (!metaStatus?.found) {
console.error('Registration validation failed - possible name mismatch or not found');
} else if (!metaStatus?.current) {
console.error('Registration is not current - may be expired or suspended');
}
}
return; // Do not approve for work
}
4. Review Conditional Registrations
Always check is_conditional and review conditions if present:
const isConditional = webhookData.content.current.registry_response.is_conditional;
if (isConditional) {
// Extract conditions from meta
const sections = webhookData.content.current.meta.ahpra.sections;
const registrationDetails = sections.find(s => s.label === 'Registration details');
console.warn('⚠️ Practitioner has conditions:');
console.warn(registrationDetails.conditions);
// Review conditions with compliance team before approving
await notifyComplianceTeam({
practitioner: webhookData.content.constituent,
conditions: registrationDetails.conditions
});
}
5. Monitor Expiry Dates
Extract and track registration expiry dates from the detailed sections:
const sections = webhookData.content.current.meta.ahpra.sections;
const registrationDetails = sections.find(s => s.label === 'Registration details');
const expiryDateStr = registrationDetails.registration_expiry_date;
// Parse date (format: DD/MM/YYYY)
const [day, month, year] = expiryDateStr.split('/');
const expiryDate = new Date(year, month - 1, day);
const daysUntilExpiry = Math.floor((expiryDate - new Date()) / (1000 * 60 * 60 * 24));
if (daysUntilExpiry < 60) {
// Send renewal reminder
console.log(`Registration expires in ${daysUntilExpiry} days`);
await scheduleRenewalReminder(webhookData.content.constituent);
}
6. Prevent Duplicate Scans
Use the AHPRA registration number (identifier) to track and prevent duplicate scans:
// Check if already scanned before submitting
const existing = await database.findByIdentifier('MED0001234567');
if (existing && existing.scanned_recently) {
// Skip scan or use cached result
return existing;
}
// Submit new scan
await submitAHPRAVerification({
type: 'ahpra',
identifier: 'MED0001234567',
first_name: 'Sarah',
surname: 'Johnson'
});
7. Handle Webhooks Reliably
- Return
200 OKquickly (within 10 seconds) - Process webhook data asynchronously in your application
- Store correlation_id with your records for matching
- Implement webhook signature verification
Complete Integration Example
Step 1: Submit AHPRA Verification
curl -X POST https://app.weareoho.com/api/scan \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "ahpra",
"identifier": "MED0001234567",
"first_name": "Sarah",
"middle_name": "Jane",
"surname": "Johnson",
"profession": "MED",
"constituent": {
"id": 12345
}
}'
Step 2: Receive Response
{
"correlation_id": "d591aa45-64fa-46b9-8eab-423075ee66cb"
}
Step 3: Store Request Details
// Store the AHPRA identifier and request details
await database.createVerificationRequest({
identifier: 'MED0001234567',
constituent_id: 12345,
profession: 'MED',
status: 'pending',
submitted_at: new Date()
});
Step 4: Receive Webhook (2-5 seconds later)
{
"event": "accreditation_validation",
"correlation_id": "e891df78-97gd-79ec-1hcd-756308hh99fe",
"content": {
"current": {
"id": 8765,
"identifier": "MED0001234567",
"type": "ahpra",
"status": "active",
"status_color": "green",
"registry_response": {
"status": "Registered",
"profession": "Medical Practitioner",
"is_conditional": false
},
"meta": {
"ahpra": {
"status": "Registered",
"sections": [
{
"label": "Registration details",
"conditions": "None",
"profession": "Medical Practitioner",
"registration_status": "Registered",
"registration_expiry_date": "31/05/2026"
}
],
"registration_types": ["General"]
}
}
},
"constituent": {
"id": 12345,
"first_name": "Sarah",
"surname": "Johnson"
}
}
}
Note: The correlation_id in the webhook may differ from the one returned in Step 2. Use the identifier to match results.
Step 5: Process Webhook
async function handleAHPRAWebhook(req, res) {
// 1. Verify signature
const signature = req.headers['x-hub-signature'];
if (!verifyWebhook(req.body, signature, process.env.OHO_SECRET)) {
return res.status(403).send('Invalid signature');
}
const payload = JSON.parse(req.body);
// 2. Match to your records using the identifier
const identifier = payload.content.current.identifier;
const verificationRequest = await database.findByIdentifier(identifier);
// 3. Check registration validity using status_color and flags
const statusColor = payload.content.current.status_color;
const statusFlags = payload.content.current.status_flags || [];
const registryResponse = payload.content.current.registry_response;
// Determine if practitioner can practice
const isNonPractising = statusFlags.includes('ahpra_non_practising');
const isValid = statusColor === 'green' && !isNonPractising;
// Extract detailed information from meta
const ahpraData = payload.content.current.meta?.ahpra;
const registrationDetails = ahpraData?.sections?.find(
s => s.label === 'Registration details'
);
// 4. Update your records
await database.updateVerificationRequest(verificationRequest.id, {
status: payload.content.current.status,
status_color: statusColor,
status_flags: statusFlags,
accreditation_id: payload.content.current.id,
registration_status: registryResponse.status,
profession: registryResponse.profession,
is_conditional: registryResponse.is_conditional,
is_non_practising: isNonPractising,
conditions: registrationDetails?.conditions || 'None',
expiry_date: registrationDetails?.registration_expiry_date,
registration_types: ahpraData?.registration_types || [],
is_valid: isValid
});
// 5. Respond quickly
res.status(200).send('OK');
// 6. Process asynchronously (after response sent)
if (registryResponse.is_conditional) {
await notifyComplianceTeam(verificationRequest, {
conditions: registrationDetails.conditions,
profession: registryResponse.profession
});
}
if (isExpiringWithin60Days(registrationDetails?.registration_expiry_date)) {
await scheduleRenewalReminder(verificationRequest);
}
}
function isExpiringWithin60Days(expiryDateStr) {
if (!expiryDateStr) return false;
// Parse DD/MM/YYYY format
const [day, month, year] = expiryDateStr.split('/');
const expiry = new Date(year, month - 1, day);
const daysUntilExpiry = Math.floor((expiry - new Date()) / (1000 * 60 * 60 * 24));
return daysUntilExpiry < 60;
}
Common Use Cases
Healthcare Onboarding
Verify AHPRA registration during employee onboarding:
async function onboardHealthcareProfessional(employeeData) {
// 1. Create constituent
const constituent = await createConstituent({
first_name: employeeData.firstName,
surname: employeeData.surname,
email: employeeData.email,
mobile_number: employeeData.mobile
});
// 2. Submit AHPRA verification
const ahpraCheck = await submitAHPRAVerification({
type: 'ahpra',
identifier: employeeData.ahpraNumber,
first_name: employeeData.firstName,
surname: employeeData.surname,
profession: employeeData.profession,
constituent: { id: constituent.id },
correlation_id: `onboard-${constituent.id}-ahpra`
});
return {
constituent_id: constituent.id,
correlation_id: ahpraCheck.correlation_id
};
}
Bulk Registration Verification
Verify multiple practitioners simultaneously:
async function bulkVerifyRegistrations(practitioners) {
const results = [];
for (const practitioner of practitioners) {
const response = await submitAHPRAVerification({
type: 'ahpra',
identifier: practitioner.ahpraNumber,
first_name: practitioner.firstName,
surname: practitioner.surname,
profession: practitioner.profession,
constituent: { id: practitioner.constituentId },
correlation_id: `bulk-verify-${practitioner.id}`
});
results.push({
practitioner_id: practitioner.id,
correlation_id: response.correlation_id
});
// Rate limiting: wait 100ms between requests
await sleep(100);
}
return results;
}
Periodic Re-verification
Set up periodic checks to monitor ongoing registration status:
async function schedulePeriodicReVerification(constituentId, ahpraNumber) {
// Check every 30 days
setInterval(async () => {
await submitAHPRAVerification({
type: 'ahpra',
identifier: ahpraNumber,
first_name: constituent.first_name,
surname: constituent.surname,
constituent: { id: constituentId },
correlation_id: `periodic-${constituentId}-${Date.now()}`
});
}, 30 * 24 * 60 * 60 * 1000); // 30 days
}
FAQ
Q: How often should I verify AHPRA registrations?
A:
- Initial verification: Always verify before employment commences
- Ongoing monitoring: Monthly or quarterly checks recommended
- Pre-expiry verification: 60 days before expiry date
- Ad-hoc verification: After any reported incidents or concerns
Q: What happens if a registration is expired?
A: The webhook will return status_color: "red" and registry_response.status will indicate the expired state. The practitioner cannot legally practice until registration is renewed.
Q: What is a Non-Practising registration?
A: A Non-Practising registration means the practitioner is registered with AHPRA but is not authorized to practice. This shows as:
status_color: "yellow"status_flagsincludes"ahpra_non_practising"registry_response.professionincludes "Non Practising"meta.ahpra.is_non_practising: true
Important: Even though the registration status is "Registered", a non-practising practitioner cannot legally practice their profession. They must convert to a practising registration type before being approved for work.
Q: Can I verify registrations for all health professions?
A: Yes, Oho supports verification for all 16 AHPRA-regulated professions. Simply specify the appropriate profession code or omit it to search across all professions.
Q: How do I handle practitioners with multiple registrations?
A: Some practitioners (e.g., a doctor who is also a registered nurse) may have multiple AHPRA registrations. Submit separate verification requests for each registration number.
Q: What should I do if a practitioner has conditions on their registration?
A: When is_conditional is true, review the detailed conditions in meta.ahpra.sections[].conditions. Consult with your compliance team to determine if the conditions affect the practitioner's ability to work in your specific setting. Common conditions include:
- Must practice under supervision
- Limited to specific practice settings
- Cannot prescribe certain medications
- Must report regularly to AHPRA
- Geographic or employer restrictions
Q: Can I verify international practitioners?
A: AHPRA only verifies registrations for practitioners registered in Australia. International practitioners must first obtain AHPRA registration before you can verify their credentials through Oho.
Q: How do I verify a practitioner's registration type and specialty?
A: Detailed registration type information is available in meta.ahpra.registration_types (e.g., ["General"], ["Specialist"], ["Limited"]). For practitioners with specialist recognition, review the registration sections in meta.ahpra.sections for specialty details and endorsements.
Q: What if I submit the same AHPRA check twice?
A: Each request creates a new scan. To prevent duplicates, check your database for existing scans of the same AHPRA number before submitting. Track scans using the identifier field (AHPRA registration number) rather than relying on correlation_id.
Troubleshooting
Common Issues and Solutions
1. 401 Unauthorized Error
Problem: {"status": 401, "message": "You are not authorized to view this resource"}
Solutions:
- ✅ Verify your API token is correct and hasn't expired
- ✅ Check the
Authorizationheader format:Bearer YOUR_TOKEN - ✅ Ensure your user account is verified (check email)
- ✅ Confirm your organization is active and in good standing
2. Registration Not Found Error
Problem: Webhook returns REGISTRATION_NOT_FOUND error
Solutions:
- ✅ Verify the AHPRA registration number is correct
- ✅ Check the number format (should be 3 letters + 10 digits)
- ✅ Confirm the practitioner's name matches exactly as registered
- ✅ Ask the practitioner to verify their registration on the AHPRA public register
3. Name Mismatch Error
Problem: Webhook returns NAME_MISMATCH error
Solutions:
- ✅ Check spelling of first name and surname
- ✅ Verify the name matches the practitioner's AHPRA registration exactly
- ✅ Include middle name if it appears on the registration
- ✅ Check for name changes (marriage, etc.) - practitioner may need to update AHPRA records
4. 400 Constituent Not Found
Problem: {"errors": {"constituent": {"id": ["Constituent doesn't exist in your organization"]}}}
Solutions:
- ✅ Create the constituent first:
POST /api/constituents - ✅ Verify you're using the correct constituent ID
- ✅ Or omit
constituentfield entirely for standalone verification
5. Webhook Not Receiving Results
Problem: Scan submitted successfully but no webhook callback received
Solutions:
- ✅ Verify webhook URL is configured in Settings → Webhooks
- ✅ Ensure webhook endpoint is publicly accessible via HTTPS
- ✅ Check webhook endpoint returns
200 OKwithin 10 seconds - ✅ Verify no firewall blocking incoming requests
- ✅ Look for failed webhooks in your dashboard
6. Registration Shows as Expired but Practitioner Claims It's Current
Problem: Webhook shows status_color: "red" but practitioner says registration is current
Solutions:
- ✅ Ask practitioner to check their AHPRA portal for registration status
- ✅ Verify they've paid their annual registration fee
- ✅ Check if they've completed mandatory CPD requirements
- ✅ Confirm they haven't received any correspondence from AHPRA
- ⚠️ Do not allow practice if status_color is "red"
Note: Sometimes AHPRA shows a past expiry date while renewal is being processed. Check meta.ahpra.sections for the latest status information.
Quick Reference
Endpoint Summary
Endpoint: POST /api/scan
Content-Type: application/json
Authentication: Authorization: Bearer YOUR_TOKEN
Type Code: ahpra
Field Requirements
Always required:
type- Must be"ahpra"identifier- AHPRA registration numberfirst_name- First/given namesurname- Surname/family name
Optional but recommended:
profession- Profession code (MED, NUR, PHA, etc.)middle_name- Middle name(s)constituent.id- Link to existing constituent
Common HTTP Status Codes
| Code | Meaning | Common Cause |
|---|---|---|
| 200 | Success | Request queued successfully |
| 400 | Bad Request | Validation error (missing/invalid field) |
| 401 | Unauthorized | Invalid/missing API token |
| 429 | Too Many Requests | Rate limit exceeded |
| 503 | Service Unavailable | Registry temporarily unavailable |
Status Color Values (Primary Indicator)
| Color | Description | Common Reasons | Action Required |
|---|---|---|---|
green | Registration is valid | Normal registration | ✅ Check is_conditional |
yellow | Needs review | Non-practising, expiring soon | ⚠️ Check status_flags |
red | Invalid | Expired, suspended, not found | ❌ Cannot practice |
Status Flags (Detailed Indicators)
| Flag | Meaning | Action Required |
|---|---|---|
current | Registration is current and valid | ✅ Valid registration |
not_current | Registration is not current | ❌ Cannot practice - Check meta.status |
is_conditional | Has conditions/restrictions | ⚠️ Review conditions in meta |
ahpra_non_practising | Non-practising registration | ❌ Cannot practice |
expiring | Expiring soon | ⚠️ Monitor renewal |
expired | Registration has expired | ❌ Cannot practice |
Conditional Registration Flag
| Value | Description | Action Required |
|---|---|---|
false | No conditions, normal registration | ✅ Normal practice allowed |
true | Has conditions OR non-practising | ⚠️ Check status_flags and meta |
Critical: is_conditional: true can mean either:
- Registration has conditions → Review
meta.ahpra.sections[].conditions - Non-practising registration → Check for
ahpra_non_practisingflag → Cannot practice
Meta Status Fields
| Field | Description | When to Check |
|---|---|---|
meta.status.found | Whether validation succeeded | When status_color: "red" |
meta.status.current | Whether registration is current | When status_color: "red" |
When red status: If meta.status.found: false, the validation failed (name mismatch, not found, etc.). If meta.status.current: false, registration is not current (expired, suspended, etc.).
Related Documentation
- WWC Integration Guide - Working With Children Check verification
- Constituent Management Guide - Managing people in your organization
- Webhook Integration Guide - Setting up webhooks for all check types
- API Documentation - Auto-generated API reference
- Glossary - Comprehensive terminology reference
External Resources
- AHPRA Public Register - Official public register search
- AHPRA Guidelines - Registration standards and guidelines
- National Boards - Information about each health profession board
Document Version
Version: 1.0
Last Updated: 2025-02-05
Endpoint: POST /api/scan (Universal with type: "ahpra")
Status: Production Ready