Webhook & Event Catalog
Partner lifecycle, pipeline, ingest, identity, FHIR subscription, and specialty events — with payload schemas and signature verification requirements.
Delivery requirements
- HTTPS endpoint responding within 5 seconds with HTTP 2xx
- Verify
X-Apex-SignatureHMAC-SHA256 signature - Event type in
X-Apex-Event-Typeheader - Idempotent processing — retries use exponential backoff (max 72h)
Register webhook endpoint
Partner-signed HTTPS endpoints receive TEFCA exchange events. Requires sign-in and cms.partner.write scope on your OAuth client.
Event subscriptions
Your endpoints
Loading…
Webhook delivery log
Sign in to view delivery attempts and send a test.ping event to registered endpoints.
No deliveries logged yet.
Signature verification (HMAC-SHA256)
Signed payload format: {timestamp}.{raw JSON body}. Signature header value: sha256={hex}. Reject requests older than 300 seconds.
| Header | Required | Description |
|---|---|---|
| X-Apex-Signature | Yes | HMAC-SHA256 hex digest prefixed with sha256= |
| X-Apex-Event-Type | Yes | Dot-notation event type (e.g. pipeline.sync.completed) |
| X-Apex-Delivery-Id | Yes | Unique delivery ID — use for idempotent processing |
| X-Apex-Timestamp | Yes | Unix epoch seconds when the event was dispatched |
| Content-Type | Yes | application/json |
| User-Agent | No | Apex-Webhook/1.0 (+https://developers.parkerapex.com/webhooks) |
Node.js
import crypto from 'crypto';
const SIGNATURE_HEADER = 'X"text-cyan-300">-Apex-Signature';
const TIMESTAMP_HEADER = 'X"text-cyan-300">-Apex-Timestamp';
const TOLERANCE_SEC = 300;
"text">-amber-300 font">-semibold">export function verifyApexWebhook(rawBody: Buffer, headers: Record<string, string>, secret: string): boolean {
const signature = headers[SIGNATURE_HEADER.toLowerCase()] ?? headers[SIGNATURE_HEADER];
const timestamp = headers[TIMESTAMP_HEADER.toLowerCase()] ?? headers[TIMESTAMP_HEADER];
if (!signature?.startsWith('sha256=') || !timestamp) return false;
const ts = parseInt(timestamp, 10);
if (Math.abs(Date.now() / 1000 - ts) > TOLERANCE_SEC) return false;
const expected = crypto
.createHmac('sha256', secret)
.update(`${timestamp}.${rawBody.toString('utf8')}`)
.digest('hex');
const received = signature.slice('sha256='.length);
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received));
}Python
import hmac
import hashlib
import time
SIGNATURE_HEADER = "X">-Apex-Signature"
TIMESTAMP_HEADER = "X">-Apex-Timestamp"
TOLERANCE_SEC = 300
def verify_apex_webhook(raw_body: bytes, headers: dict, secret: str) -> bool:
signature = headers.get(SIGNATURE_HEADER) or headers.get(SIGNATURE_HEADER.lower())
timestamp = headers.get(TIMESTAMP_HEADER) or headers.get(TIMESTAMP_HEADER.lower())
if not signature or not signature.startswith("sha256=") or not timestamp:
return False
ts = int(timestamp)
if abs(time.time() - ts) > TOLERANCE_SEC:
return False
signed_payload = f"{timestamp}.{raw_body.decode('utf-8')}".encode("utf-8")
expected = hmac.new(secret.encode(), signed_payload, hashlib.sha256).hexdigest()
received = signature.removeprefix("sha256=")
return hmac.compare_digest(expected, received)Retry schedule (max 72h)
- Attempt 1: 1 minute
- Attempt 2: 5 minutes
- Attempt 3: 30 minutes
- Attempt 4: 2 hours
- Attempt 5: 6 hours
- Attempt 6: 24 hours
Idempotency
Store processed delivery IDs (X-Apex-Delivery-Id) for at least 72 hours. Retries reuse the same delivery ID — return HTTP 2xx only after durable processing.
X-Apex-Delivery-Id
pipeline.sync.completedPipelinePipeline Sync Completed
FHIR or batch sync job finished successfully.
{
-300">"event": -300">"pipeline.sync.completed",
-300">"job_id": -300">"job_abc123",
-300">"partner_gpid": -300">"CMS-00000001",
-300">"resource_types": [
"Patient",
"Observation"
],
-300">"records_processed": 1240,
-300">"completed_at": -300">"2026-06-13T20:00:00Z"
}pipeline.sync.failedPipelinePipeline Sync Failed
Sync job failed after retries.
{
-300">"event": -300">"pipeline.sync.failed",
-300">"job_id": -300">"job_abc123",
-300">"error_code": -300">"VALIDATION_ERROR",
-300">"message": -300">"Bundle entry 14 failed FHIR validation",
-300">"failed_at": -300">"2026-06-13T20:01:00Z"
}ingest.completeBeacon / IngestIngest Complete
Document or FHIR bundle ingest normalized and stored.
{
-300">"event": -300">"ingest.complete",
-300">"document_id": -300">"doc_xyz789",
-300">"gpid": -300">"APX-1A2B3C4D",
-300">"match_status": -300">"deterministic_match",
-300">"lake_resource_id": -300">"Patient/abc"
}ingest.rejectedBeacon / IngestIngest Rejected
Ingest rejected — virus scan, validation, or policy failure.
{
-300">"event": -300">"ingest.rejected",
-300">"document_id": -300">"doc_xyz789",
-300">"reason": -300">"MALWARE_DETECTED",
-300">"rejected_at": -300">"2026-06-13T19:55:00Z"
}identity.matchIdentity / GPIDIdentity Match Resolved
GPID match or merge completed for a subject.
{
-300">"event": -300">"identity.match",
-300">"gpid": -300">"APX-1A2B3C4D",
-300">"match_type": -300">"DETERMINISTIC",
-300">"identity_status": -300">"ACTIVE",
-300">"subject_gpid": -300">"APX-1A2B3C4D"
}identity.mergeIdentity / GPIDIdentity Merge
Two GPID records merged into golden record.
{
-300">"event": -300">"identity.merge",
-300">"survivor_gpid": -300">"APX-1A2B3C4D",
-300">"merged_gpids": [
"APX-OLD001"
],
-300">"merged_at": -300">"2026-06-13T18:00:00Z"
}prime.ingest.persistedPrime WearablesPrime Ingest Persisted
Wearable telemetry normalized to FHIR Observations.
{
-300">"event": -300">"prime.ingest.persisted",
-300">"ingestion_id": -300">"ing_def456",
-300">"observation_count": 4,
-300">"athlete_gpid": -300">"APX-1A2B3C4D",
-300">"source": -300">"oura"
}prime.readiness.alertPrime WearablesPrime Readiness Alert
Readiness flag triggered from biometric thresholds.
{
-300">"event": -300">"prime.readiness.alert",
-300">"flag": -300">"recovery_low",
-300">"severity": -300">"warning",
-300">"athlete_gpid": -300">"APX-1A2B3C4D",
-300">"metric": -300">"hrv_rmssd",
-300">"value": 28.5
}fhir.subscription.notificationFHIRFHIR Subscription Notification
R4 Subscription resource triggered — payload is FHIR Bundle.
{
-300">"resourceType": -300">"Bundle",
-300">"type": -300">"history",
-300">"entry": [
{
-300">"resource": {
-300">"resourceType": -300">"Observation",
-300">"id": -300">"obs-1"
}
}
]
}claim.adjudicatedVelocity RCMClaim Adjudicated
Payer claim response received and linked to Claim resource.
{
-300">"event": -300">"claim.adjudicated",
-300">"claim_id": -300">"clm_001",
-300">"claim_response_id": -300">"CR-99201",
-300">"status": -300">"active",
-300">"payer": -300">"Aetna",
-300">"paid_amount": 142.5
}partner.token.revokedCMS / PartnersPartner Token Revoked
API key or OAuth client revoked — rotate credentials.
{
-300">"event": -300">"partner.token.revoked",
-300">"token_id": -300">"tok_abc",
-300">"partner_gpid": -300">"CMS-00000001",
-300">"revoked_at": -300">"2026-06-13T17:00:00Z",
-300">"reason": -300">"admin_action"
}sightline.prescription.fulfilledSightlineVision Prescription Fulfilled
Optical order fulfilled — lenses/frames dispensed.
{
-300">"event": -300">"sightline.prescription.fulfilled",
-300">"vision_prescription_id": -300">"VP-001",
-300">"patient_gpid": -300">"APX-1A2B3C4D",
-300">"fulfillment_status": -300">"completed"
}odonto.treatment_plan.updatedOdontoDental Treatment Plan Updated
CarePlan or treatment plan modified in Odonto EHR.
{
-300">"event": -300">"odonto.treatment_plan.updated",
-300">"care_plan_id": -300">"CP-001",
-300">"patient_gpid": -300">"APX-1A2B3C4D",
-300">"procedures_added": 2
}tefca.exchange.completedTEFCA / KONZATEFCA Exchange Completed
Outbound or inbound XCPD/XCA exchange finished (success or empty result).
{
-300">"event": -300">"tefca.exchange.completed",
-300">"exchange_type": -300">"xcpd",
-300">"direction": -300">"outbound",
-300">"gpid": -300">"APX-1A2B3C4D",
-300">"target_organization_oid": -300">"2.16.840.1.113883.3.2791.1",
-300">"purpose_of_use": -300">"TREAT",
-300">"success": -300">true
}tefca.consent.deniedTEFCA / KONZATEFCA Consent Denied
Exchange blocked by patient consent or policy for the declared purpose of use.
{
-300">"event": -300">"tefca.consent.denied",
-300">"exchange_type": -300">"xca",
-300">"gpid": -300">"APX-1A2B3C4D",
-300">"purpose_of_use": -300">"TREAT",
-300">"reason": -300">"Patient consent does not permit this disclosure"
}velocity.claim.submittedVelocity / StediClaim Submitted via Stedi
837P professional claim accepted by the Stedi clearinghouse.
{
-300">"event": -300">"velocity.claim.submitted",
-300">"claim_id": -300">"CLM-2026-00412",
-300">"control_number": -300">"123456789",
-300">"trading_partner_service_id": -300">"PAYER_ID",
-300">"usage_indicator": -300">"T"
}velocity.eligibility.completedVelocity / StediEligibility Check Completed
270/271 eligibility inquiry returned from Stedi.
{
-300">"event": -300">"velocity.eligibility.completed",
-300">"member_id": -300">"MBR001",
-300">"active_coverage": -300">true,
-300">"trading_partner_service_id": -300">"PAYER_ID"
}test.pingSystemWebhook Test Ping
Synthetic test delivery from the developer portal Test button.
{
-300">"event": -300">"test.ping",
-300">"message": -300">"Parker Apex webhook test delivery",
-300">"webhook_id": 1
}