Receive callbacks
Outgoing APIs are callbacks you receive from Nabla when providers export content from the app. Expose a public HTTPS endpoint that accepts POST requests, and configure its URL in Nabla Connect Admin.
Payload schemas live in the callback reference.
Respond quickly. Nabla waits for your response before showing a success message in the app. A slow or failed response surfaces an error to the provider.
Verify HMAC signatures
Every callback includes:
x-nabla-connect-timestamp— ISO 8601 timestamp of when the request was generatedx-nabla-connect-signature— one or more HMAC-SHA256 signatures of the request body
Retrieve the signature secret from Nabla Connect Admin.
On each POST:
- Extract the timestamp and signature headers.
- Reject if the timestamp is older than 60 seconds (replay protection).
- Concatenate the timestamp and the raw request body.
- Compute HMAC-SHA256 with the shared signature secret.
- Compare your digest with each comma-separated signature in the header.
- Reject with HTTP 401 if none match.
- Reject if you have already processed this callback's
request_uuid(idempotency).
const bodyParser = require("body-parser");
const crypto = require("crypto");
const express = require("express");
const app = express();
app.use(
bodyParser.json({
type: "application/json",
verify: function (req, res, buf) {
const webhookSecretKey = "<SIGNATURE_SECRET>";
const timestamp = req.headers["x-nabla-connect-timestamp"];
const receivedSignatures = req.headers["x-nabla-connect-signature"];
const computedSignature = crypto
.createHmac("sha256", webhookSecretKey)
.update(timestamp + buf)
.digest("hex");
const signatureMatch = receivedSignatures
.split(",")
.some((sig) => sig.trim() === computedSignature);
if (!signatureMatch) {
const error = new Error("Signature invalid");
error.status = 401;
throw error;
}
},
})
);
Support multiple signatures in the header so key rotation can overlap. See RFC 2104 and RFC 4231.
Optional OAuth on callbacks
Nabla can also send a bearer access token on each callback, using the OAuth 2.0 client credentials grant against your authorization server. Configure this under Callback URL in Nabla Connect Admin.
Nabla caches and reuses access tokens; it does not request a new token for every callback.
| Field | Description |
|---|---|
| Authorization server endpoint | URL where Nabla requests access tokens |
| Authentication method | How credentials are sent (see below) |
| Client ID | Sent as client_id |
| Client secret | Sent as client_secret |
-
Form URL-encoded (
application/x-www-form-urlencoded) — default, matching RFC 6749 §4.4.2:POST /oauth/tokenContent-Type: application/x-www-form-urlencodedgrant_type=client_credentials&client_id=xxx&client_secret=yyy -
JSON body (
application/json):{"grant_type": "client_credentials","client_id": "xxx","client_secret": "yyy"}
Response protocol
All callbacks share the same envelope. The type field selects the payload shape.
{
"request_uuid": "<uuid>",
"type": "NOTE_EXPORT | PATIENT_INSTRUCTIONS_EXPORT",
"data": {}
}
| Status | When to use |
|---|---|
200 | Request recognized and processed |
400 | Unrecognized type |
401 | Signature verification failed |
For every 200, echo request_uuid:
{ "request_uuid": "<uuid>" }
NOTE_EXPORT
Triggered when the provider clicks Export Note.
Read each section's structured_content, discriminated by type:
{ "type": "TEXT", "text": "..." }— most sections{ "type": "SUBSECTIONS", "subsections": [ ... ] }— Assessment & Plan on A&P-merged templates, one subsection per problem, in note order
Each subsection has title (may be null, for example content inserted from a dot phrase), text, and icd10_codes / snomed_codes. Those code lists are empty when codes are not available at export time (for example when code extraction is disabled).
Section-level content is deprecated: it is the same text, flattened. Use structured_content instead.
Optional fields, when enabled or available:
visit_diagnoses— ICD-10 items withsystem,code,display,is_hcc,is_mcctranscript— conversation items (text,speaker_type,locale,start_offset_ms,end_offset_ms). Enable this in Admin.
Section category values include CHIEF_COMPLAINT, HISTORY_OF_PRESENT_ILLNESS, PAST_HISTORY, CURRENT_MEDICATIONS, VITALS, IMMUNIZATIONS, ASSESSMENT_AND_PLAN, EXAMINATION, RESULTS, PRESCRIPTIONS, and APPOINTMENTS. Several sections can share a category (for example separate Assessment and Plan sections both use ASSESSMENT_AND_PLAN). category: null means the section does not fit an existing category.
See the callback reference for the full schema.
PATIENT_INSTRUCTIONS_EXPORT
Triggered when the provider clicks Export patient instructions. data.patient_instructions.instructions is the patient-facing text.