curl --request POST \
--url https://api.dev.purplelabelmd.com/v1/instrument/abandon \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'X-Brand-Id: <x-brand-id>' \
--data '
{
"session_id": "<string>"
}
'import requests
url = "https://api.dev.purplelabelmd.com/v1/instrument/abandon"
payload = { "session_id": "<string>" }
headers = {
"X-Brand-Id": "<x-brand-id>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-Brand-Id': '<x-brand-id>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({session_id: '<string>'})
};
fetch('https://api.dev.purplelabelmd.com/v1/instrument/abandon', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.dev.purplelabelmd.com/v1/instrument/abandon",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'session_id' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"X-Brand-Id: <x-brand-id>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.dev.purplelabelmd.com/v1/instrument/abandon"
payload := strings.NewReader("{\n \"session_id\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Brand-Id", "<x-brand-id>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.dev.purplelabelmd.com/v1/instrument/abandon")
.header("X-Brand-Id", "<x-brand-id>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"session_id\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.dev.purplelabelmd.com/v1/instrument/abandon")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Brand-Id"] = '<x-brand-id>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"session_id\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"journey_id": "<string>",
"session_id": "<string>",
"status": "active",
"blocked": {
"code": "<string>",
"node_id": "<string>",
"support_route": "<string>",
"ungranted_scopes": [
"<string>"
]
},
"flags": [
"<string>"
],
"handoff": {
"promo": "<string>",
"redirect": "<string>",
"test": true
},
"issues": [
{
"code": "<string>",
"message": "<string>",
"conflicting_codes": [
"<string>"
],
"exclusive_codes": [
"<string>"
]
}
],
"node": {
"kind": "question",
"node_id": "<string>",
"section_id": "<string>",
"computed_stub": true,
"consent_version": "<string>",
"content": {},
"control": "<string>",
"copy": "<string>",
"display": "static",
"fact": "<string>",
"grants": [
"<string>"
],
"interstitial": true,
"may_auto_advance": true,
"media": {
"kind": "image",
"accept": [
"<string>"
],
"capture_mode": "upload",
"consent_copy": "<string>",
"consent_fact": "<string>",
"consent_version": "<string>",
"facing": "user",
"max_bytes": 123,
"max_duration_s": 123,
"min_duration_s": 123,
"require_consent": true,
"resumable": true
},
"offering_refs": [
"<string>"
],
"option_codes": [
"<string>"
],
"options": [
{
"code": "<string>",
"classification_code": "<string>",
"exclusive": true,
"label": "<string>"
}
],
"prefill": "collect",
"prefilled_value": "<unknown>",
"reassurance": "<string>",
"required": true,
"theme": {},
"values": {},
"zone": {
"scale_max": 123,
"scale_min": 123,
"zone_label": "<string>",
"zone_max": 123,
"zone_min": 123
}
},
"progress": {
"position_estimate": 0.5,
"scope": "<string>",
"section_label": "<string>"
}
}{
"status": 123,
"title": "<string>",
"type": "<string>",
"detail": "<string>"
}{
"status": 123,
"title": "<string>",
"type": "<string>",
"detail": "<string>"
}Record that your patient dropped off the questionnaire
Marks the intake session as dropped-off. Call this when a patient leaves without finishing so the drop-off is recorded against the session.
curl --request POST \
--url https://api.dev.purplelabelmd.com/v1/instrument/abandon \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'X-Brand-Id: <x-brand-id>' \
--data '
{
"session_id": "<string>"
}
'import requests
url = "https://api.dev.purplelabelmd.com/v1/instrument/abandon"
payload = { "session_id": "<string>" }
headers = {
"X-Brand-Id": "<x-brand-id>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-Brand-Id': '<x-brand-id>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({session_id: '<string>'})
};
fetch('https://api.dev.purplelabelmd.com/v1/instrument/abandon', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.dev.purplelabelmd.com/v1/instrument/abandon",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'session_id' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"X-Brand-Id: <x-brand-id>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.dev.purplelabelmd.com/v1/instrument/abandon"
payload := strings.NewReader("{\n \"session_id\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Brand-Id", "<x-brand-id>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.dev.purplelabelmd.com/v1/instrument/abandon")
.header("X-Brand-Id", "<x-brand-id>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"session_id\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.dev.purplelabelmd.com/v1/instrument/abandon")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Brand-Id"] = '<x-brand-id>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"session_id\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"journey_id": "<string>",
"session_id": "<string>",
"status": "active",
"blocked": {
"code": "<string>",
"node_id": "<string>",
"support_route": "<string>",
"ungranted_scopes": [
"<string>"
]
},
"flags": [
"<string>"
],
"handoff": {
"promo": "<string>",
"redirect": "<string>",
"test": true
},
"issues": [
{
"code": "<string>",
"message": "<string>",
"conflicting_codes": [
"<string>"
],
"exclusive_codes": [
"<string>"
]
}
],
"node": {
"kind": "question",
"node_id": "<string>",
"section_id": "<string>",
"computed_stub": true,
"consent_version": "<string>",
"content": {},
"control": "<string>",
"copy": "<string>",
"display": "static",
"fact": "<string>",
"grants": [
"<string>"
],
"interstitial": true,
"may_auto_advance": true,
"media": {
"kind": "image",
"accept": [
"<string>"
],
"capture_mode": "upload",
"consent_copy": "<string>",
"consent_fact": "<string>",
"consent_version": "<string>",
"facing": "user",
"max_bytes": 123,
"max_duration_s": 123,
"min_duration_s": 123,
"require_consent": true,
"resumable": true
},
"offering_refs": [
"<string>"
],
"option_codes": [
"<string>"
],
"options": [
{
"code": "<string>",
"classification_code": "<string>",
"exclusive": true,
"label": "<string>"
}
],
"prefill": "collect",
"prefilled_value": "<unknown>",
"reassurance": "<string>",
"required": true,
"theme": {},
"values": {},
"zone": {
"scale_max": 123,
"scale_min": 123,
"zone_label": "<string>",
"zone_max": 123,
"zone_min": 123
}
},
"progress": {
"position_estimate": 0.5,
"scope": "<string>",
"section_label": "<string>"
}
}{
"status": 123,
"title": "<string>",
"type": "<string>",
"detail": "<string>"
}{
"status": 123,
"title": "<string>",
"type": "<string>",
"detail": "<string>"
}Authorizations
Per-client API key (M2M). Presented as Authorization: Bearer <key>.
Headers
An optional id you send to tie this request to your own logs. Send one and it is echoed back unchanged; omit it and one is assigned for you. Either way the id is returned in the X-Correlation-Id response header on every response, including errors, so you can match a response to the request that produced it.
128^[A-Za-z0-9][A-Za-z0-9._:-]*$Opaque brand id (brd_...). Validated to belong to the resolved client (§2).
^brd_[A-Za-z0-9][A-Za-z0-9_-]*$Body
Response
abandonment recorded
The result of a resolve, next, or abandon call — the session identity, the current question (or null when finished), the status, any flags (e.g. ship_state_mismatch), and any validation issues. On completion it may carry the entry-link hand-off.
^jny_[A-Za-z0-9][A-Za-z0-9_-]*$active (a node is presented), complete (server-authoritative completion), abandoned (patient drop-off), or blocked — a terminal, server-authoritative refusal to proceed (a required consent was declined or could not be affirmed). On blocked, node is null and blocked carries the honest stop-screen outcome.
active, complete, abandoned, blocked The honest stop-screen outcome. Present only when status is blocked. Carries the machine-readable reason, the node at which the block occurred, the consent scopes that were not granted (codes, never patient data), and a support-routing hint. The stop-screen copy is a presentation concern (the intake kit renders it); no patient data ever rides here. No order lock ever forms without a positive affirmation where one is required.
Show child attributes
Show child attributes
Post-completion hand-off carried when a session that began from an entry link completes. Present only when status is complete and the session carried a validated entry context. redirect holds a brand-allowlisted https URL; promo is an opaque pass-through token validated downstream; test is the per-client test-mode flag. Never carries patient data.
Show child attributes
Show child attributes
Show child attributes
Show child attributes
A node as presented to the client — PRESENTATION ONLY. The client never owns the sequence, controls, or option order (those come from the compiled bundle; a brand theme cannot alter them). Brand theme/copy, when applied, ride alongside as presentation overlay.
Show child attributes
Show child attributes
Server-computed progress metadata, present on every resolve/next step: computed from the live effective plan — never client-guessed. position_estimate is the honest fraction of the plan completed (0..1); display nodes participate in the fraction. Whether and how it renders (thin persistent bar, step ring, interstitial pacing, none) is brand-theme presentation.
Show child attributes
Show child attributes