API Reference
Complete reference for the Talon API. Base URL: https://talonapi.dev
Authentication
Most endpoints require an API key passed via the X-API-Key header. Get your key from the developer dashboard.
curl -H "X-API-Key: tln_live_abc123..." \
"https://talonapi.dev/api/v1/rules?payer=aetna&cpt_code=27447"Key format: Production keys start with tln_live_, sandbox keys with tln_test_.
Public endpoints (no authentication required): /api/v1/health, /api/v1/metrics, /api/v1/rules/payers, /api/v1/rules/cpt-codes, /api/v1/formulary, and /api/v1/openapi.
Rate Limits
All authenticated endpoints are rate-limited to 100 requests per minute per API key using a sliding window.
When you exceed the limit, the API returns 429 Too Many Requests with a Retry-After header indicating when to retry (in seconds).
Retry Safety
GET endpoints are safe to retry on timeout or network failure. POST endpoints (analyze-gaps, appeals/generate, rules/check, formulary/check) are NOT idempotent — retrying may consume additional credits. If a POST request times out, check your credit balance in the dashboard before retrying.
Sandbox Environment
API keys starting with tln_test_ operate in sandbox mode. Sandbox keys are designed for integration development and testing.
What sandbox keys do
- Return realistic mock responses for all endpoints including gap analysis
- Accept outcome reports (but do not affect intelligence signals)
- Log usage to your dashboard
- Enforce the same validation rules as production
- Apply the same payer normalization as production
What sandbox keys do not do
- Consume credits
- Call the AI analysis engine (gap analysis returns mock data)
- Trigger real Bedrock API calls
- Affect production intelligence signals
Sandbox gap analysis behavior
Mock responses vary based on the length and apparent completeness of the clinical_text you submit. Longer, more detailed notes return higher scores and fewer flagged requirements. This lets you test how your application handles different result states without using live credits.
To test specific scenarios, use notes of these approximate lengths:
| Note length | Score | Traffic light |
|---|---|---|
| Short incomplete (<200 chars) | ~40 | red |
| Medium (200–500 chars) | ~65 | yellow |
| Detailed (500–1000 chars) | ~78 | yellow |
| Comprehensive (>1000 chars) | ~91 | green |
Sandbox mode enforces the same payer normalization as production. Submitting an unknown payer name will return a payer_not_found error, just like production. PHI scanning is skipped for sandbox requests, making it safe to test with sample clinical notes.
Data Trust
Talon API sources data from official payer policy documents and public CMS datasets. All rule data used in calculations, approval rates, and readiness checks comes from verified, authoritative sources.
Every API response that returns rule data includes a metadata object so you always know where the data came from and when it was last verified.
"metadata": {
"source": "Aetna Clinical Policy Bulletin",
"last_verified": "2026-02-15T00:00:00.000Z"
}Errors & Handling
All errors follow a consistent JSON structure with an error code, message, and optional fix suggestion.
{
"error": {
"code": "invalid_api_key",
"message": "The provided API key is invalid or has been revoked.",
"request_id": "req_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"suggestion": "Check that your API key is correct. Keys start with tln_live_ or tln_test_."
}
}| Code | Status | Description |
|---|---|---|
| invalid_api_key | 401 | API key is missing, invalid, or revoked |
| api_key_expired | 401 | API key has expired — generate a new one from the dashboard |
| insufficient_credits | 402 | Not enough credits for this request |
| not_found | 404 | Requested resource not found |
| payer_not_found | 404 | Unknown or unsupported payer name — check /v1/rules/payers |
| validation_failed | 422 | Missing or invalid parameters |
| phi_detected | 422 | Request contains HIPAA identifiers (appeals and analyze-gaps endpoints) |
| rate_limit_exceeded | 429 | Too many requests — check Retry-After header |
| internal_error | 500 | Unexpected server error |
PHI Detection
The appeals and gap analysis endpoints scan clinical_text and clinical_summary fields for HIPAA identifiers before processing. Detected identifiers cause an immediate 422 rejection — no credits are charged.
- Patient names (first, last, full)
- Dates of birth
- Social Security numbers
- Medical record numbers (MRN)
- Health plan beneficiary numbers
- Phone numbers and email addresses
- Street addresses
To test your de-identification pipeline, use sandbox mode (tln_test_ keys). Sandbox requests skip PHI scanning, so you can verify your workflow end-to-end before switching to live keys.
Handling Errors in Code
Always check the HTTP status code before parsing the response body. Here are patterns for common error scenarios:
async function callTalon(path, apiKey) {
const res = await fetch(`https://talonapi.dev${path}`, {
headers: { "X-API-Key": apiKey }
});
if (!res.ok) {
const body = await res.json();
const err = body.error;
switch (res.status) {
case 401:
throw new Error(`Auth failed: ${err.message}`);
case 402:
// Redirect user to purchase credits
throw new Error("Insufficient credits");
case 429:
// Retry after the specified delay
const retryAfter = res.headers.get("Retry-After") || "60";
await new Promise(r => setTimeout(r, parseInt(retryAfter) * 1000));
return callTalon(path, apiKey); // retry once
default:
throw new Error(`Talon API error: ${err.code} — ${err.message}`);
}
}
return res.json();
}import requests
import time
def call_talon(path, api_key, retry=True):
res = requests.get(
f"https://talonapi.dev{path}",
headers={"X-API-Key": api_key}
)
if res.status_code == 429 and retry:
wait = int(res.headers.get("Retry-After", 60))
time.sleep(wait)
return call_talon(path, api_key, retry=False)
if not res.ok:
err = res.json().get("error", {})
raise Exception(f"Talon API {err.get('code')}: {err.get('message')}")
return res.json()Rate limit headers: Every authenticated response includes these headers:
| Header | Description |
|---|---|
| X-RateLimit-Limit | Max requests per window (100) |
| X-RateLimit-Remaining | Requests remaining in current window |
| X-RateLimit-Reset | Unix timestamp when the window resets |
| Retry-After | Seconds to wait (only on 429 responses) |
Endpoints
GET/api/v1/health
Returns API status. No authentication required.
curl https://talonapi.dev/api/v1/healthconst res = await fetch("https://talonapi.dev/api/v1/health");
const data = await res.json();
console.log(data.status); // "ok"import requests
res = requests.get("https://talonapi.dev/api/v1/health")
print(res.json()["status"]) # "ok"{
"status": "ok",
"version": "1.0.0",
"timestamp": "2026-02-28T12:00:00.000Z"
}GET/api/v1/rules
Look up payer requirements for a specific CPT code. Returns documentation requirements, blocking rules, approval rates, and denial patterns.
| Parameter | Type | Required | Description |
|---|---|---|---|
| payer | string | Required | Payer name (e.g. "aetna", "unitedhealthcare") |
| cpt_code | string | Required | CPT procedure code (e.g. "27447"). Also accepts "cpt" as a backward-compatible alias. |
| clinical_context | string | Optional | One of "elective" (default), "urgent", or "emergency". Urgent/emergency may suppress blocking requirements for exempt procedures. |
curl -H "X-API-Key: tln_live_abc123..." \
"https://talonapi.dev/api/v1/rules?payer=aetna&cpt_code=27447"curl -H "X-API-Key: tln_live_abc123..." \
"https://talonapi.dev/api/v1/rules?payer=aetna&cpt_code=29877&clinical_context=emergency"const res = await fetch(
"https://talonapi.dev/api/v1/rules?payer=aetna&cpt_code=27447",
{ headers: { "X-API-Key": "tln_live_abc123..." } }
);
const data = await res.json();
console.log(data.approval_rate); // 0.84
console.log(data.required_docs); // ["Clinical notes", ...]import requests
res = requests.get(
"https://talonapi.dev/api/v1/rules",
params={"payer": "aetna", "cpt_code": "27447"},
headers={"X-API-Key": "tln_live_abc123..."}
)
print(res.json()["required_docs"]) # ["Clinical notes", ...]{
"payer": "Aetna",
"cpt_code": "27447",
"description": "Total Knee Replacement",
"required_docs": [
"Clinical notes",
"Conservative treatment history",
"Imaging reports"
],
"blocking_requirements": [
"6+ weeks documented conservative treatment",
"BMI documented",
"Functional limitation score"
],
"soft_requirements": [
"Physical therapy notes",
"Failed medication list"
],
"typical_turnaround_days": 5,
"approval_rate": 0.84,
"common_denial_reasons": [
{
"reason": "Insufficient conservative treatment documentation"
}
],
"last_updated": "2026-02-15T00:00:00.000Z",
"conservative_treatment_required": true,
"conservative_treatment_weeks": 6,
"clinical_context": "elective",
"emergency_exempt": false,
"urgent_exempt": false
}Context suppression: When clinical_context=emergency and the procedure is emergency-exempt, blocking_requirements and soft_requirements are cleared and typical_turnaround_days is set to 0. When clinical_context=urgent and the procedure is urgent-exempt, blocking_requirements are cleared and turnaround is capped at 2 days.
GET/api/v1/rules/payers
List all supported payer names. Public discovery endpoint — no authentication required.
curl "https://talonapi.dev/api/v1/rules/payers"const res = await fetch("https://talonapi.dev/api/v1/rules/payers");
const { payers, count } = await res.json();import requests
res = requests.get("https://talonapi.dev/api/v1/rules/payers")
payers = res.json()["payers"]{
"payers": ["Aetna", "Blue Cross Blue Shield", "Cigna", "Humana", "UnitedHealthcare"],
"count": 5
}GET/api/v1/rules/cpt-codes
List all supported CPT codes with descriptions. Public discovery endpoint — no authentication required.
curl "https://talonapi.dev/api/v1/rules/cpt-codes"const res = await fetch("https://talonapi.dev/api/v1/rules/cpt-codes");
const { cpt_codes } = await res.json();import requests
res = requests.get("https://talonapi.dev/api/v1/rules/cpt-codes")
codes = res.json()["cpt_codes"]{
"cpt_codes": [
{ "cpt_code": "27447", "description": "Total Knee Replacement" },
{ "cpt_code": "29881", "description": "Knee Arthroscopy with Meniscectomy" },
{ "cpt_code": "63030", "description": "Lumbar Discectomy" }
],
"count": 3
}GET/api/v1/compare
Compare approval rates across all payers for a specific CPT code.
| Parameter | Type | Required | Description |
|---|---|---|---|
| cpt_code | string | Required | CPT procedure code (e.g. "27447"). Also accepts "cpt" as a backward-compatible alias. |
curl -H "X-API-Key: tln_live_abc123..." \
"https://talonapi.dev/api/v1/compare?cpt_code=27447"const res = await fetch(
"https://talonapi.dev/api/v1/compare?cpt_code=27447",
{ headers: { "X-API-Key": "tln_live_abc123..." } }
);
const { payers } = await res.json();import requests
res = requests.get(
"https://talonapi.dev/api/v1/compare",
params={"cpt_code": "27447"},
headers={"X-API-Key": "tln_live_abc123..."}
)
payers = res.json()["payers"]{
"cpt_code": "27447",
"payers": [
{
"payer": "Aetna",
"approval_rate": 0.84,
"conservative_treatment_weeks": 6
},
{
"payer": "UnitedHealthcare",
"approval_rate": 0.78,
"conservative_treatment_weeks": 12
},
{
"payer": "Cigna",
"approval_rate": 0.81,
"conservative_treatment_weeks": 8
}
],
"count": 3
}GET/api/v1/metrics
CMS-mandated payer prior authorization metrics. Public data, no authentication required, no credits charged.
| Parameter | Type | Required | Description |
|---|---|---|---|
| payer | string | Optional | Filter by payer name (partial match, case-insensitive) |
curl "https://talonapi.dev/api/v1/metrics?payer=aetna"const res = await fetch("https://talonapi.dev/api/v1/metrics?payer=aetna");
const { metrics } = await res.json();import requests
res = requests.get(
"https://talonapi.dev/api/v1/metrics",
params={"payer": "aetna"}
)
metrics = res.json()["metrics"]{
"metrics": [
{
"payer_name": "Aetna",
"reporting_year": 2025,
"pct_approved_standard": 85.3,
"pct_denied_standard": 14.7,
"pct_approved_after_appeal": 42.1,
"avg_days_to_decision": 4.8,
"source_url": "https://www.aetna.com/about-us/prior-authorization-metrics.html",
"scraped_at": "2026-02-28T00:00:00.000Z"
}
],
"count": 1
}POST/api/v1/appeals/generate
Generate an AI-powered appeal letter for a denied prior authorization. Uses historical denial pattern data for context.
PHI Policy: The clinical_summary must be de-identified. Requests containing patient names, dates of birth, SSNs, or member IDs will be rejected with a phi_detected error.
| Parameter | Type | Required | Description |
|---|---|---|---|
| payer | string | Required | Payer name (e.g. "UnitedHealthcare") |
| cpt_code | string | Required | CPT code of the denied procedure |
| denial_reason | string | Required | Reason for denial from the payer |
| denial_code | string | Optional | Payer denial code (e.g. "J1") |
| clinical_summary | string | Required | De-identified clinical summary |
curl -X POST "https://talonapi.dev/api/v1/appeals/generate" \
-H "X-API-Key: tln_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"payer": "UnitedHealthcare",
"cpt_code": "27447",
"denial_reason": "Insufficient documentation of conservative treatment",
"denial_code": "J1",
"clinical_summary": "Patient is 67yo female with severe bilateral knee OA, Kellgren-Lawrence Grade IV. Failed 6 months PT, NSAIDs, and corticosteroid injections."
}'const res = await fetch("https://talonapi.dev/api/v1/appeals/generate", {
method: "POST",
headers: {
"X-API-Key": "tln_live_abc123...",
"Content-Type": "application/json"
},
body: JSON.stringify({
payer: "UnitedHealthcare",
cpt_code: "27447",
denial_reason: "Insufficient documentation of conservative treatment",
denial_code: "J1",
clinical_summary: "Patient is 67yo female with severe bilateral knee OA..."
})
});
const data = await res.json();import requests
res = requests.post(
"https://talonapi.dev/api/v1/appeals/generate",
headers={"X-API-Key": "tln_live_abc123..."},
json={
"payer": "UnitedHealthcare",
"cpt_code": "27447",
"denial_reason": "Insufficient documentation of conservative treatment",
"denial_code": "J1",
"clinical_summary": "Patient is 67yo female with severe bilateral knee OA..."
}
)
letter = res.json()["appeal_letter"]{
"appeal_letter": "Dear Medical Director, I am writing to appeal the denial...",
"key_arguments": [
"6 months PT documented",
"Failed NSAID therapy",
"Kellgren-Lawrence Grade IV"
],
"success_probability": 0.72
}POST/api/v1/analyze-gaps
Send a clinical note and get a detailed gap analysis against payer-specific requirements. Returns a readiness status, flagged items with fix suggestions, and contraindication screens.
PHI Policy: The clinical_text must be de-identified. Requests containing patient names, dates of birth, Social Security numbers, medical record numbers, health plan beneficiary numbers, or other HIPAA identifiers will be rejected with a phi_detected error.
| Parameter | Type | Required | Description |
|---|---|---|---|
| clinical_text | string | Required | De-identified clinical note content (max 50,000 characters) |
| payer | string | Required | Payer name (e.g. "aetna", case-insensitive) |
| cpt_code | string | Required | CPT procedure code (e.g. "27447") |
| submission_date | string | Optional | ISO date (YYYY-MM-DD). Defaults to today. |
curl -X POST "https://talonapi.dev/api/v1/analyze-gaps" \
-H "X-API-Key: tln_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"clinical_text": "67yo female presenting with severe bilateral knee OA, Kellgren-Lawrence Grade IV. BMI 28.3. Failed 8 weeks physical therapy, 6 weeks NSAIDs (ibuprofen 800mg TID), and 2 corticosteroid injections. Functional limitation: unable to walk >1 block. VAS pain score 8/10.",
"payer": "aetna",
"cpt_code": "27447"
}'const res = await fetch("https://talonapi.dev/api/v1/analyze-gaps", {
method: "POST",
headers: {
"X-API-Key": "tln_live_abc123...",
"Content-Type": "application/json"
},
body: JSON.stringify({
clinical_text: "67yo female presenting with severe bilateral knee OA...",
payer: "aetna",
cpt_code: "27447"
})
});
const data = await res.json();
console.log(data.analysis.status); // readiness status
console.log(data.analysis.flagged_items); // items needing attentionimport requests
res = requests.post(
"https://talonapi.dev/api/v1/analyze-gaps",
headers={"X-API-Key": "tln_live_abc123..."},
json={
"clinical_text": "67yo female presenting with severe bilateral knee OA...",
"payer": "aetna",
"cpt_code": "27447"
}
)
analysis = res.json()["analysis"]
print(analysis["status"]) # readiness status{
"payer": "Aetna",
"cpt_code": "27447",
"procedure": "Total Knee Replacement",
"analysis": {
"status": "yellow",
"recommendation": "Most requirements met. Address 1 missing item before submission.",
"summary": {
"met": 5,
"missing": 1,
"partial": 1,
"not_applicable": 0
},
"flagged_items": [
{
"requirement": "Functional limitation score documented",
"status": "partial",
"found_instead": "VAS pain score 8/10, unable to walk >1 block",
"why_insufficient": "VAS is a pain scale, not a functional limitation instrument (e.g. WOMAC, KOOS)",
"fix": "Add a standardized functional assessment score (WOMAC, KOOS-JR, or similar)"
},
{
"requirement": "Failed medication list with dosages and durations",
"status": "missing",
"fix": "Document each failed medication with exact dosage, frequency, duration, and reason for discontinuation"
}
],
"full_analysis": [
{
"requirement": "Conservative treatment >= 6 weeks",
"status": "met",
"evidence": "Failed 8 weeks physical therapy",
"confidence": "high"
},
{
"requirement": "BMI documented",
"status": "met",
"evidence": "BMI 28.3",
"confidence": "high"
}
]
},
"requirements_count": 7,
"latency_ms": 2340
}Readiness status: The status field indicates overall submission readiness. Use the flagged_items array to show clinicians exactly what needs to be added or corrected, with specific fix suggestions.
POST/api/v1/rules/check
Moment 1 readiness check. Given a payer, CPT code, and available documentation, returns whether the submission is ready, what gaps exist, and approval probability.
| Parameter | Type | Required | Description |
|---|---|---|---|
| payer | string | Required | Payer name (e.g. "Aetna") |
| cpt_code | string | Required | CPT procedure code |
| available_documentation | object | Optional | Object with boolean/number fields: has_clinical_notes, has_imaging, has_conservative_treatment_docs, conservative_treatment_weeks, has_bmi, has_functional_score, has_failed_medication_list |
curl -X POST "https://talonapi.dev/api/v1/rules/check" \
-H "X-API-Key: tln_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"payer": "Aetna",
"cpt_code": "27447",
"available_documentation": {
"has_clinical_notes": true,
"has_imaging": true,
"has_conservative_treatment_docs": true,
"conservative_treatment_weeks": 8,
"has_bmi": false
}
}'const res = await fetch("https://talonapi.dev/api/v1/rules/check", {
method: "POST",
headers: {
"X-API-Key": "tln_live_abc123...",
"Content-Type": "application/json"
},
body: JSON.stringify({
payer: "Aetna",
cpt_code: "27447",
available_documentation: {
has_clinical_notes: true,
has_imaging: true,
has_conservative_treatment_docs: true,
conservative_treatment_weeks: 8
}
})
});
const data = await res.json();
console.log(data.ready_to_submit); // trueimport requests
res = requests.post(
"https://talonapi.dev/api/v1/rules/check",
headers={"X-API-Key": "tln_live_abc123..."},
json={
"payer": "Aetna",
"cpt_code": "27447",
"available_documentation": {
"has_clinical_notes": True,
"has_imaging": True,
"has_conservative_treatment_docs": True,
"conservative_treatment_weeks": 8
}
}
)
print(res.json()["ready_to_submit"]) # True{
"ready_to_submit": true,
"readiness_score": 0.75,
"blocking_gaps": [],
"satisfied_requirements": [
"Clinical notes included",
"Imaging documentation included",
"Conservative treatment documented (8 weeks)"
],
"recommended_additions": [
"Include functional limitation score",
"Include failed medication list"
],
"approval_probability": 0.84,
"estimated_turnaround_days": 5,
"common_denial_reasons": [
{ "reason": "Insufficient conservative treatment documentation" }
],
"metadata": {
"source": "Aetna Clinical Policy Bulletin",
"last_verified": "2026-02-15T00:00:00.000Z"
}
}GET/api/v1/formulary
Look up medication formulary data. Returns coverage tier, prior auth requirements, step therapy requirements, and quantity limits. Public endpoint, no authentication required.
| Parameter | Type | Required | Description |
|---|---|---|---|
| payer | string | Optional | Filter by payer name (partial match) |
| drug | string | Optional | Filter by drug or generic name (partial match) |
| ndc | string | Optional | Filter by exact NDC code |
curl "https://talonapi.dev/api/v1/formulary?payer=aetna&drug=humira"{
"formulary": [
{
"payer_name": "Aetna",
"drug_name": "Humira",
"ndc_code": "00074-4339-02",
"generic_name": "adalimumab",
"formulary_tier": "specialty",
"prior_auth_required": true,
"step_therapy_required": true,
"step_therapy_drugs": [
{ "drug": "methotrexate", "status": "must_have_tried" },
{ "drug": "sulfasalazine", "status": "must_have_tried" }
],
"quantity_limit": "2 pens per 28 days",
"clinical_criteria": "Diagnosis of RA, PsA, or Crohn disease with documented failure of conventional DMARDs",
"exception_process": "Submit exception request with clinical documentation",
"source_url": "https://www.aetna.com/formulary/2026",
"last_verified": "2026-02-20T00:00:00.000Z"
}
],
"count": 1
}POST/api/v1/formulary/check
Moment 1 formulary readiness check. Given a payer, drug, and patient medication history, returns whether the drug is ready to prescribe and what step therapy requirements remain.
| Parameter | Type | Required | Description |
|---|---|---|---|
| payer | string | Required | Payer name |
| drug_name | string | Optional | Drug name (required if no ndc_code) |
| ndc_code | string | Optional | NDC code (required if no drug_name) |
| patient_medication_history | array | Optional | Array of { drug, status, reason } objects |
curl -X POST "https://talonapi.dev/api/v1/formulary/check" \
-H "X-API-Key: tln_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"payer": "Aetna",
"drug_name": "Humira",
"patient_medication_history": [
{ "drug": "methotrexate", "status": "failed", "reason": "Inadequate response after 12 weeks" }
]
}'{
"covered": true,
"prior_auth_required": true,
"step_therapy_required": true,
"step_therapy_status": {
"steps_required": [
{ "drug": "methotrexate", "status": "must_have_tried" },
{ "drug": "sulfasalazine", "status": "must_have_tried" }
],
"steps_completed": ["methotrexate"],
"steps_remaining": [
{ "drug": "sulfasalazine", "action": "Trial of sulfasalazine required before Humira" }
]
},
"quantity_limits": "2 pens per 28 days",
"ready_to_prescribe": false,
"recommendation": "Step therapy required: complete trial of sulfasalazine before requesting Humira.",
"metadata": {
"source": "Aetna Formulary",
"last_verified": "2026-02-20T00:00:00.000Z"
}
}