Subscription (FHIR R4)

FHIR You're viewing the FHIR R4 reference.Only in R4

FHIR R4 Subscription resource.

This reference is generated from the canonical Huli Public API OpenAPI specification and the server's FHIR R4 CapabilityStatement — do not edit it directly.

FHIR R4 Specification

Official spec: Subscription — HL7 FHIR R4

Supported Interactions

  • read — Read a single resource by ID (GET /fhir/R4/{Resource}/{id})
  • search-type — Search resources with query parameters (GET /fhir/R4/{Resource}?...)
  • create — Create a new resource (POST /fhir/R4/{Resource})
  • update — Update an existing resource (PUT /fhir/R4/{Resource}/{id})
  • delete — delete
  • $replay — operation
  • $stats — operation
  • $deliveries — operation

Scopes

Scopes are shared across FHIR releases — the same system/Subscription.* scope grants Subscription access on both /fhir/R4 and /fhir/R5.

Search Parameters

ParameterTypeNotes
_idtokenExact match. For identifiers use `system
statustokenExact match. For identifiers use `system
_countnumberInteger. For _count: default 20, max 100.
_offsetnumberInteger. For _count: default 20, max 100.

Endpoints

Read Subscription

Retrieve a single outbound-webhook Subscription by its ID. The response NEVER includes the signing secret — the secret is returned exactly once, on create.

GET/fhir/R4/Subscription/{id}

Required scope: system/Subscription.rs

Code Samples

TOKEN=$(curl -s -X POST https://api.huli.ai/auth/token \
  -d "grant_type=client_credentials" \
  -d "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \
  -d "client_assertion=${CLIENT_ASSERTION}" \
  -d "scope=system/Subscription.rs" \
  | jq -r .access_token)

curl -X GET https://api.huli.ai/fhir/R4/Subscription/${RESOURCE_ID} \
  -H "Authorization: Bearer ${TOKEN}"
const token = process.env.HULI_ACCESS_TOKEN ?? "";

const response = await fetch(
  `https://api.huli.ai/fhir/R4/Subscription/${id}`,
  {
    method: "GET",
    headers: {
      "Authorization": `Bearer ${token}`,
    },

  }
);

if (!response.ok) throw new Error(`HTTP ${String(response.status)}`);
const data: unknown = await response.json();
import os
import requests

token = os.environ["HULI_ACCESS_TOKEN"]
headers = {"Authorization": f"Bearer {token}"}

resp = requests.get(
    f"https://api.huli.ai/fhir/R4/Subscription/{resource_id}",
    headers=headers,
)
resp.raise_for_status()
print(resp.json())
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class getSubscriptionExample {
    public static void main(String[] args) throws Exception {
        String token = System.getenv("HULI_ACCESS_TOKEN");
        String resourceId = "RESOURCE_ID";

        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://api.huli.ai/fhir/R4/Subscription/" + resourceId))
        .header("Authorization", "Bearer " + token)
        .header("Accept", "application/fhir+json")
        .method("GET", HttpRequest.BodyPublishers.noBody())
        .build();

        HttpResponse<String> response =
        client.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println("status: " + response.statusCode());
        System.out.println(response.body());
    }
}
import (
    "fmt"
    "net/http"
    "os"
)

func getSubscriptionExample() {
    token := os.Getenv("HULI_ACCESS_TOKEN")
    req, _ := http.NewRequest("GET", "https://api.huli.ai/fhir/R4/Subscription/"+resourceID+"", nil)
    req.Header.Set("Authorization", "Bearer "+token)

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        fmt.Println("error:", err)
        return
    }
    defer resp.Body.Close()
    fmt.Println("status:", resp.Status)
}

Errors

CodeStatusDescription
HPB-00106401Authentication failed
HPB-00104403Insufficient scope
HPB-00102404Resource not found
HPB-00105429Rate limit exceeded

Update Subscription

Update an existing outbound-webhook Subscription. The mutable fields are status, criteria, and the channel target/payload/headers. The signing secret is PRESERVED (never rotated or returned here). The endpoint is re-validated (https-only, SSRF-safe) on every update. channel.type must remain rest-hook and channel.payload must remain application/fhir+json.

PUT/fhir/R4/Subscription/{id}

Required scope: system/Subscription.crud

Request Body

nametyperequireddescription
resourceTypestringrequired
idstring(uuid)optional
metaobjectoptional
statusstringrequiredSubscription status. On write accept `requested` (default), `active`, or `off`. `error` is server-owned (set by the delivery circuit breaker) and is rejected on write.
reasonstringrequiredRequired free-text reason for the subscription. Accepted and validated non-empty, but NOT persisted — reads echo a fixed reason.
criteriastringrequiredThe FHIR resource type to notify on — one of `Patient`, `Appointment`, `Encounter`, `Observation`, `MedicationRequest`, `ServiceRequest`. v1 matches on resource type only: query-parameter filtering (e.g. `Encounter?status=finished`) is not yet supported and is rejected, so subscribe to the bare resource type.
channelobjectrequired
extensionarrayoptionalOn the create (`201`) response ONLY, carries the one-time plaintext signing secret under the `https://huli.io/fhir/StructureDefinition/subscription-signing-secret` extension (`valueString`). Never present on read / search / update.

Request Example

{
  "resourceType": "Subscription",
  "status": "active",
  "reason": "Notify our EHR mirror of encounter changes",
  "criteria": "Encounter",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://example.org/webhooks/huli",
    "payload": "application/fhir+json",
    "header": [
      "X-Source-System: acme-ehr"
    ]
  }
}

Code Samples

TOKEN=$(curl -s -X POST https://api.huli.ai/auth/token \
  -d "grant_type=client_credentials" \
  -d "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \
  -d "client_assertion=${CLIENT_ASSERTION}" \
  -d "scope=system/Subscription.crud" \
  | jq -r .access_token)

curl -X PUT https://api.huli.ai/fhir/R4/Subscription/${RESOURCE_ID} \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Content-Type: application/fhir+json" \
  -d @resource.json
const token = process.env.HULI_ACCESS_TOKEN ?? "";

const response = await fetch(
  `https://api.huli.ai/fhir/R4/Subscription/${id}`,
  {
    method: "PUT",
    headers: {
      "Authorization": `Bearer ${token}`,
      "Content-Type": "application/fhir+json",
    },
    body: JSON.stringify(payload),
  }
);

if (!response.ok) throw new Error(`HTTP ${String(response.status)}`);
const data: unknown = await response.json();
import os
import requests

token = os.environ["HULI_ACCESS_TOKEN"]
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/fhir+json"}

resp = requests.put(
    f"https://api.huli.ai/fhir/R4/Subscription/{resource_id}",
    headers=headers,
    json=payload,
)
resp.raise_for_status()
print(resp.json())
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class updateSubscriptionExample {
    public static void main(String[] args) throws Exception {
        String token = System.getenv("HULI_ACCESS_TOKEN");
        String resourceId = "RESOURCE_ID";
        String payload = "{}"; // your serialized FHIR resource

        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://api.huli.ai/fhir/R4/Subscription/" + resourceId))
        .header("Authorization", "Bearer " + token)
        .header("Accept", "application/fhir+json")
        .header("Content-Type", "application/fhir+json")
        .method("PUT", HttpRequest.BodyPublishers.ofString(payload))
        .build();

        HttpResponse<String> response =
        client.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println("status: " + response.statusCode());
        System.out.println(response.body());
    }
}
import (
    "fmt"
    "net/http"
    "os"
)

func updateSubscriptionExample() {
    token := os.Getenv("HULI_ACCESS_TOKEN")
    req, _ := http.NewRequest("PUT", "https://api.huli.ai/fhir/R4/Subscription/"+resourceID+"", body)
    req.Header.Set("Authorization", "Bearer "+token)
    req.Header.Set("Content-Type", "application/fhir+json")
    // set req.Body to your serialized resource
    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        fmt.Println("error:", err)
        return
    }
    defer resp.Body.Close()
    fmt.Println("status:", resp.Status)
}

Errors

CodeStatusDescription
HPB-00101400Validation error
HPB-00106401Authentication failed
HPB-00104403Insufficient scope
HPB-00102404Resource not found
HPB-00105429Rate limit exceeded

Delete Subscription

Soft-delete an outbound-webhook Subscription. The subscription is deactivated (no further deliveries fan out to it). Returns 204 on success.

DELETE/fhir/R4/Subscription/{id}

Required scope: system/Subscription.crud

Code Samples

TOKEN=$(curl -s -X POST https://api.huli.ai/auth/token \
  -d "grant_type=client_credentials" \
  -d "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \
  -d "client_assertion=${CLIENT_ASSERTION}" \
  -d "scope=system/Subscription.crud" \
  | jq -r .access_token)

curl -X DELETE https://api.huli.ai/fhir/R4/Subscription/${RESOURCE_ID} \
  -H "Authorization: Bearer ${TOKEN}"
const token = process.env.HULI_ACCESS_TOKEN ?? "";

const response = await fetch(
  `https://api.huli.ai/fhir/R4/Subscription/${id}`,
  {
    method: "DELETE",
    headers: {
      "Authorization": `Bearer ${token}`,
    },

  }
);

if (!response.ok) throw new Error(`HTTP ${String(response.status)}`);
const data: unknown = await response.json();
import os
import requests

token = os.environ["HULI_ACCESS_TOKEN"]
headers = {"Authorization": f"Bearer {token}"}

resp = requests.delete(
    f"https://api.huli.ai/fhir/R4/Subscription/{resource_id}",
    headers=headers,
)
resp.raise_for_status()
print(resp.json())
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class deleteSubscriptionExample {
    public static void main(String[] args) throws Exception {
        String token = System.getenv("HULI_ACCESS_TOKEN");
        String resourceId = "RESOURCE_ID";

        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://api.huli.ai/fhir/R4/Subscription/" + resourceId))
        .header("Authorization", "Bearer " + token)
        .header("Accept", "application/fhir+json")
        .method("DELETE", HttpRequest.BodyPublishers.noBody())
        .build();

        HttpResponse<String> response =
        client.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println("status: " + response.statusCode());
        System.out.println(response.body());
    }
}
import (
    "fmt"
    "net/http"
    "os"
)

func deleteSubscriptionExample() {
    token := os.Getenv("HULI_ACCESS_TOKEN")
    req, _ := http.NewRequest("DELETE", "https://api.huli.ai/fhir/R4/Subscription/"+resourceID+"", nil)
    req.Header.Set("Authorization", "Bearer "+token)

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        fmt.Println("error:", err)
        return
    }
    defer resp.Body.Close()
    fmt.Println("status:", resp.Status)
}

Errors

CodeStatusDescription
HPB-00106401Authentication failed
HPB-00104403Insufficient scope
HPB-00102404Resource not found
HPB-00105429Rate limit exceeded

Replay Subscription events

Re-scan the organization's event history for this subscription's criteria (resource type) over a time window and re-enqueue each matching event — for outage recovery / backfill. NOTE: the scan is by criteria + window, so it includes events that predate the subscription and events already delivered; dedupe on X-Huli-Event-Id. An event that already has an in-flight replay for this subscription is skipped, so repeated calls over the same window don't duplicate. Each newly matched event creates a fresh delivery carrying the SAME X-Huli-Event-Id as the original (so receivers dedup by event) plus X-Huli-Replay: true. The window is clamped to the 30-day retention horizon (from floored at now-30d, to capped at now) and a single call re-enqueues at most 500 events (for a larger backlog, call again with the same window — in-flight replays are skipped, so each call advances to older events — until truncated is false). Only an active subscription may replay. The from/to window is supplied as a FHIR Parameters body (or as from/to RFC3339 query params); from is required, to defaults to now.

POST/fhir/R4/Subscription/{id}/$replay

Required scope: system/Subscription.crud

Request Example

{
  "resourceType": "Parameters",
  "parameter": [
    {
      "name": "from",
      "valueInstant": "2026-06-01T00:00:00Z"
    },
    {
      "name": "to",
      "valueInstant": "2026-06-02T00:00:00Z"
    }
  ]
}

Code Samples

TOKEN=$(curl -s -X POST https://api.huli.ai/auth/token \
  -d "grant_type=client_credentials" \
  -d "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \
  -d "client_assertion=${CLIENT_ASSERTION}" \
  -d "scope=system/Subscription.crud" \
  | jq -r .access_token)

curl -X POST https://api.huli.ai/fhir/R4/Subscription/${RESOURCE_ID}/$replay \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Content-Type: application/fhir+json" \
  -d @$replay.json
const token = process.env.HULI_ACCESS_TOKEN ?? "";

const response = await fetch(
  `https://api.huli.ai/fhir/R4/Subscription/${id}/$replay`,
  {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${token}`,
      "Content-Type": "application/fhir+json",
    },
    body: JSON.stringify(payload),
  }
);

if (!response.ok) throw new Error(`HTTP ${String(response.status)}`);
const data: unknown = await response.json();
import os
import requests

token = os.environ["HULI_ACCESS_TOKEN"]
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/fhir+json"}

resp = requests.post(
    f"https://api.huli.ai/fhir/R4/Subscription/{resource_id}/$replay",
    headers=headers,
    json=payload,
)
resp.raise_for_status()
print(resp.json())
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class replaySubscriptionExample {
    public static void main(String[] args) throws Exception {
        String token = System.getenv("HULI_ACCESS_TOKEN");
        String resourceId = "RESOURCE_ID";
        String payload = "{}"; // your serialized FHIR resource

        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://api.huli.ai/fhir/R4/Subscription/" + resourceId + "/$replay"))
        .header("Authorization", "Bearer " + token)
        .header("Accept", "application/fhir+json")
        .header("Content-Type", "application/fhir+json")
        .method("POST", HttpRequest.BodyPublishers.ofString(payload))
        .build();

        HttpResponse<String> response =
        client.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println("status: " + response.statusCode());
        System.out.println(response.body());
    }
}
import (
    "fmt"
    "net/http"
    "os"
)

func replaySubscriptionExample() {
    token := os.Getenv("HULI_ACCESS_TOKEN")
    req, _ := http.NewRequest("POST", "https://api.huli.ai/fhir/R4/Subscription/"+resourceID+"/$replay", body)
    req.Header.Set("Authorization", "Bearer "+token)
    req.Header.Set("Content-Type", "application/fhir+json")
    // set req.Body to your serialized resource
    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        fmt.Println("error:", err)
        return
    }
    defer resp.Body.Close()
    fmt.Println("status:", resp.Status)
}

Errors

CodeStatusDescription
HPB-00101400Validation error
HPB-00106401Authentication failed
HPB-00104403Insufficient scope
HPB-00102404Resource not found
HPB-00101422Unprocessable entity
HPB-00105429Rate limit exceeded

Subscription delivery metrics

Per-subscription delivery observability. Returns a FHIR Parameters resource with the delivered / failed / pending / dead counts, the dead-letter depth, total attempts, the terminal success rate, and the enqueue-to-delivery latency p50/p95 (seconds). Never exposes payloads, endpoints, or signing secrets.

GET/fhir/R4/Subscription/{id}/$stats

Required scope: system/Subscription.rs

Code Samples

TOKEN=$(curl -s -X POST https://api.huli.ai/auth/token \
  -d "grant_type=client_credentials" \
  -d "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \
  -d "client_assertion=${CLIENT_ASSERTION}" \
  -d "scope=system/Subscription.rs" \
  | jq -r .access_token)

curl -X GET https://api.huli.ai/fhir/R4/Subscription/${RESOURCE_ID}/$stats \
  -H "Authorization: Bearer ${TOKEN}"
const token = process.env.HULI_ACCESS_TOKEN ?? "";

const response = await fetch(
  `https://api.huli.ai/fhir/R4/Subscription/${id}/$stats`,
  {
    method: "GET",
    headers: {
      "Authorization": `Bearer ${token}`,
    },

  }
);

if (!response.ok) throw new Error(`HTTP ${String(response.status)}`);
const data: unknown = await response.json();
import os
import requests

token = os.environ["HULI_ACCESS_TOKEN"]
headers = {"Authorization": f"Bearer {token}"}

resp = requests.get(
    f"https://api.huli.ai/fhir/R4/Subscription/{resource_id}/$stats",
    headers=headers,
)
resp.raise_for_status()
print(resp.json())
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class getSubscriptionStatsExample {
    public static void main(String[] args) throws Exception {
        String token = System.getenv("HULI_ACCESS_TOKEN");
        String resourceId = "RESOURCE_ID";

        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://api.huli.ai/fhir/R4/Subscription/" + resourceId + "/$stats"))
        .header("Authorization", "Bearer " + token)
        .header("Accept", "application/fhir+json")
        .method("GET", HttpRequest.BodyPublishers.noBody())
        .build();

        HttpResponse<String> response =
        client.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println("status: " + response.statusCode());
        System.out.println(response.body());
    }
}
import (
    "fmt"
    "net/http"
    "os"
)

func getSubscriptionStatsExample() {
    token := os.Getenv("HULI_ACCESS_TOKEN")
    req, _ := http.NewRequest("GET", "https://api.huli.ai/fhir/R4/Subscription/"+resourceID+"/$stats", nil)
    req.Header.Set("Authorization", "Bearer "+token)

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        fmt.Println("error:", err)
        return
    }
    defer resp.Body.Close()
    fmt.Println("status:", resp.Status)
}

Errors

CodeStatusDescription
HPB-00106401Authentication failed
HPB-00104403Insufficient scope
HPB-00102404Resource not found
HPB-00105429Rate limit exceeded

Subscription delivery-attempt trail

The delivery-level audit trail for one subscription: the recent delivery attempts (newest first, paged via _count, optionally filtered by status = pending | delivered | failed | dead), returned as a FHIR Parameters resource with one delivery group per attempt. Each group carries only sanitized metadata — delivery status, attempt count, last HTTP status code, queued/delivered timestamps, the replay flag, and the source event's type — never the payload, endpoint, signing secret, or error text.

GET/fhir/R4/Subscription/{id}/$deliveries

Required scope: system/Subscription.rs

Query Parameters

nametyperequireddescription
_countintegeroptionalMaximum number of delivery attempts to return.
statusstringoptionalNarrow the trail to a single delivery status.

Code Samples

TOKEN=$(curl -s -X POST https://api.huli.ai/auth/token \
  -d "grant_type=client_credentials" \
  -d "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \
  -d "client_assertion=${CLIENT_ASSERTION}" \
  -d "scope=system/Subscription.rs" \
  | jq -r .access_token)

curl -X GET https://api.huli.ai/fhir/R4/Subscription/${RESOURCE_ID}/$deliveries \
  -H "Authorization: Bearer ${TOKEN}"
const token = process.env.HULI_ACCESS_TOKEN ?? "";

const response = await fetch(
  `https://api.huli.ai/fhir/R4/Subscription/${id}/$deliveries`,
  {
    method: "GET",
    headers: {
      "Authorization": `Bearer ${token}`,
    },

  }
);

if (!response.ok) throw new Error(`HTTP ${String(response.status)}`);
const data: unknown = await response.json();
import os
import requests

token = os.environ["HULI_ACCESS_TOKEN"]
headers = {"Authorization": f"Bearer {token}"}

resp = requests.get(
    f"https://api.huli.ai/fhir/R4/Subscription/{resource_id}/$deliveries",
    headers=headers,
)
resp.raise_for_status()
print(resp.json())
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class getSubscriptionDeliveriesExample {
    public static void main(String[] args) throws Exception {
        String token = System.getenv("HULI_ACCESS_TOKEN");
        String resourceId = "RESOURCE_ID";

        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://api.huli.ai/fhir/R4/Subscription/" + resourceId + "/$deliveries"))
        .header("Authorization", "Bearer " + token)
        .header("Accept", "application/fhir+json")
        .method("GET", HttpRequest.BodyPublishers.noBody())
        .build();

        HttpResponse<String> response =
        client.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println("status: " + response.statusCode());
        System.out.println(response.body());
    }
}
import (
    "fmt"
    "net/http"
    "os"
)

func getSubscriptionDeliveriesExample() {
    token := os.Getenv("HULI_ACCESS_TOKEN")
    req, _ := http.NewRequest("GET", "https://api.huli.ai/fhir/R4/Subscription/"+resourceID+"/$deliveries", nil)
    req.Header.Set("Authorization", "Bearer "+token)

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        fmt.Println("error:", err)
        return
    }
    defer resp.Body.Close()
    fmt.Println("status:", resp.Status)
}

Errors

CodeStatusDescription
HPB-00101400Validation error
HPB-00106401Authentication failed
HPB-00104403Insufficient scope
HPB-00102404Resource not found
HPB-00105429Rate limit exceeded

Search Subscriptions

Search outbound-webhook Subscriptions for the authenticated organization. Supports _id and status filters plus offset pagination. Responses NEVER include the signing secret.

GET/fhir/R4/Subscription

Required scope: system/Subscription.rs

Query Parameters

nametyperequireddescription
_idstringoptionalFilter by Subscription ID (UUID).
statusstringoptionalFilter by status: `requested`, `active`, `error`, `off`.
_countintegeroptionalNumber of results per page (default: 20, max: 100).
_offsetintegeroptionalNumber of results to skip (offset-based pagination).

Code Samples

TOKEN=$(curl -s -X POST https://api.huli.ai/auth/token \
  -d "grant_type=client_credentials" \
  -d "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \
  -d "client_assertion=${CLIENT_ASSERTION}" \
  -d "scope=system/Subscription.rs" \
  | jq -r .access_token)

curl -X GET https://api.huli.ai/fhir/R4/Subscription \
  -H "Authorization: Bearer ${TOKEN}"
const token = process.env.HULI_ACCESS_TOKEN ?? "";

const response = await fetch(
  `https://api.huli.ai/fhir/R4/Subscription`,
  {
    method: "GET",
    headers: {
      "Authorization": `Bearer ${token}`,
    },

  }
);

if (!response.ok) throw new Error(`HTTP ${String(response.status)}`);
const data: unknown = await response.json();
import os
import requests

token = os.environ["HULI_ACCESS_TOKEN"]
headers = {"Authorization": f"Bearer {token}"}

resp = requests.get(
    f"https://api.huli.ai/fhir/R4/Subscription",
    headers=headers,
)
resp.raise_for_status()
print(resp.json())
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class searchSubscriptionsExample {
    public static void main(String[] args) throws Exception {
        String token = System.getenv("HULI_ACCESS_TOKEN");

        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://api.huli.ai/fhir/R4/Subscription"))
        .header("Authorization", "Bearer " + token)
        .header("Accept", "application/fhir+json")
        .method("GET", HttpRequest.BodyPublishers.noBody())
        .build();

        HttpResponse<String> response =
        client.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println("status: " + response.statusCode());
        System.out.println(response.body());
    }
}
import (
    "fmt"
    "net/http"
    "os"
)

func searchSubscriptionsExample() {
    token := os.Getenv("HULI_ACCESS_TOKEN")
    req, _ := http.NewRequest("GET", "https://api.huli.ai/fhir/R4/Subscription", nil)
    req.Header.Set("Authorization", "Bearer "+token)

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        fmt.Println("error:", err)
        return
    }
    defer resp.Body.Close()
    fmt.Println("status:", resp.Status)
}

Errors

CodeStatusDescription
HPB-00106401Authentication failed
HPB-00104403Insufficient scope
HPB-00105429Rate limit exceeded

Create Subscription

Create an outbound-webhook Subscription. The server assigns the resource ID and generates an HMAC signing secret, which is returned EXACTLY ONCE in the 201 response body as a valueString extension (https://huli.io/fhir/StructureDefinition/subscription-signing-secret) with a Cache-Control: no-store response header. The secret is never returned again — store it securely. Validation (all fail-closed, 400):

  • channel.type must be rest-hook.
  • channel.endpoint must be an https URL with no embedded credentials (SSRF-checked).
  • channel.payload, when set, must be application/fhir+json.
  • channel.header entries must be Name: value (no CR/LF, no duplicates).
  • criteria must be a bare resource type — one of Patient, Appointment, Encounter, Observation, MedicationRequest, ServiceRequest. Query-parameter filtering is not supported in v1 (fan-out matches on resource type only); a criteria carrying a query (e.g. Encounter?status=finished) is rejected.
  • reason is required. The 201 body also carries a non-blocking warning OperationOutcome (in contained) reminding the integrator of their BAA / PHI-handling responsibility for the configured endpoint.
POST/fhir/R4/Subscription

Required scope: system/Subscription.crud

Request Body

nametyperequireddescription
resourceTypestringrequired
idstring(uuid)optional
metaobjectoptional
statusstringrequiredSubscription status. On write accept `requested` (default), `active`, or `off`. `error` is server-owned (set by the delivery circuit breaker) and is rejected on write.
reasonstringrequiredRequired free-text reason for the subscription. Accepted and validated non-empty, but NOT persisted — reads echo a fixed reason.
criteriastringrequiredThe FHIR resource type to notify on — one of `Patient`, `Appointment`, `Encounter`, `Observation`, `MedicationRequest`, `ServiceRequest`. v1 matches on resource type only: query-parameter filtering (e.g. `Encounter?status=finished`) is not yet supported and is rejected, so subscribe to the bare resource type.
channelobjectrequired
extensionarrayoptionalOn the create (`201`) response ONLY, carries the one-time plaintext signing secret under the `https://huli.io/fhir/StructureDefinition/subscription-signing-secret` extension (`valueString`). Never present on read / search / update.

Request Example

{
  "resourceType": "Subscription",
  "status": "requested",
  "reason": "Notify our EHR mirror of encounter changes",
  "criteria": "Encounter",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://example.org/webhooks/huli",
    "payload": "application/fhir+json",
    "header": [
      "X-Source-System: acme-ehr"
    ]
  }
}

Code Samples

TOKEN=$(curl -s -X POST https://api.huli.ai/auth/token \
  -d "grant_type=client_credentials" \
  -d "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \
  -d "client_assertion=${CLIENT_ASSERTION}" \
  -d "scope=system/Subscription.crud" \
  | jq -r .access_token)

curl -X POST https://api.huli.ai/fhir/R4/Subscription \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Content-Type: application/fhir+json" \
  -d @subscription.json
const token = process.env.HULI_ACCESS_TOKEN ?? "";

const response = await fetch(
  `https://api.huli.ai/fhir/R4/Subscription`,
  {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${token}`,
      "Content-Type": "application/fhir+json",
    },
    body: JSON.stringify(payload),
  }
);

if (!response.ok) throw new Error(`HTTP ${String(response.status)}`);
const data: unknown = await response.json();
import os
import requests

token = os.environ["HULI_ACCESS_TOKEN"]
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/fhir+json"}

resp = requests.post(
    f"https://api.huli.ai/fhir/R4/Subscription",
    headers=headers,
    json=payload,
)
resp.raise_for_status()
print(resp.json())
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class createSubscriptionExample {
    public static void main(String[] args) throws Exception {
        String token = System.getenv("HULI_ACCESS_TOKEN");
        String payload = "{}"; // your serialized FHIR resource

        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://api.huli.ai/fhir/R4/Subscription"))
        .header("Authorization", "Bearer " + token)
        .header("Accept", "application/fhir+json")
        .header("Content-Type", "application/fhir+json")
        .method("POST", HttpRequest.BodyPublishers.ofString(payload))
        .build();

        HttpResponse<String> response =
        client.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println("status: " + response.statusCode());
        System.out.println(response.body());
    }
}
import (
    "fmt"
    "net/http"
    "os"
)

func createSubscriptionExample() {
    token := os.Getenv("HULI_ACCESS_TOKEN")
    req, _ := http.NewRequest("POST", "https://api.huli.ai/fhir/R4/Subscription", body)
    req.Header.Set("Authorization", "Bearer "+token)
    req.Header.Set("Content-Type", "application/fhir+json")
    // set req.Body to your serialized resource
    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        fmt.Println("error:", err)
        return
    }
    defer resp.Body.Close()
    fmt.Println("status:", resp.Status)
}

Errors

CodeStatusDescription
HPB-00101400Validation error
HPB-00106401Authentication failed
HPB-00104403Insufficient scope
HPB-00105429Rate limit exceeded