Skip to main content

TPA Integration Guide

End-to-end guide for Third-Party Administrators (TPAs/Trading Partners) to integrate with the Turquoise Direct Contract platform.

Overview: TPAs as Trading Partners

In the Turquoise ecosystem, a TPA (Third-Party Administrator) is a "Trading Partner" that facilitates contract lookups and claims processing between plans and providers. Your role:

  1. Contract Verification: Look up guaranteed rates before service delivery
  2. Claims Processing: Submit FHIR claims and manage adjudication
  3. Settlement Management: Authorize fund releases and reconcile payments
  4. Reporting: Monitor ROI and contract utilization
info

"Trading Partner" is the internal term for any organization processing claims through Turquoise APIs. This includes TPAs, TPAs-lite, and third-party platforms.

Architecture Overview

Two-Stage Contract Verification

Turquoise uses a two-stage verification process to ensure contract accuracy and speed:

Stage 1: Blind Lookup (< 200ms)

Request contract rates without member-specific information:

curl -X POST \
https://api.turquoise.health/tpa-api/v1/contracts/lookup \
-H "X-API-Key: $TURQUOISE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"provider_npi": "1234567890",
"plan_id": "SHARP-HMO-2024",
"service_code": "43235",
"lookup_type": "blind"
}'

Response (service fee not charged):

{
"contract_id": "DIR-2024-001",
"lookup_type": "blind",
"service_code": "43235",
"negotiated_rate": 1200.00,
"member_responsibility": 100.00,
"plan_pays": 1100.00,
"valid_for": 3600,
"expires_at": "2024-03-10T12:00:00Z",
"status": "available"
}
tip

Use blind lookups at the front desk to provide immediate pricing guarantees. No member authentication required.

Stage 2: Full Lookup (with Member)

Verify member eligibility and deductible status:

curl -X POST \
https://api.turquoise.health/tpa-api/v1/contracts/lookup \
-H "X-API-Key: $TURQUOISE_API_KEY" \
-d '{
"provider_npi": "1234567890",
"plan_id": "SHARP-HMO-2024",
"service_code": "43235",
"member_id": "SHP00123456",
"lookup_type": "full"
}'

Response (includes member-specific details):

{
"contract_id": "DIR-2024-001",
"lookup_type": "full",
"service_code": "43235",
"negotiated_rate": 1200.00,
"deductible_remaining": 500.00,
"member_responsibility": 100.00,
"plan_pays": 1100.00,
"member_status": "active",
"effective_date": "2024-01-01",
"term_date": "2024-12-31",
"valid_for": 3600
}

Claims Processing Flow

Step 1: Prepare FHIR Claim

Structure your claim using Fast FHIR:

{
"resourceType": "Claim",
"id": "CLM-2024-001",
"status": "active",
"type": { "coding": [{ "code": "institutional" }] },
"use": "claim",
"patient": { "identifier": { "value": "SHP00123456" } },
"provider": { "identifier": { "value": "1234567890" } },
"insurer": { "identifier": { "value": "SHARP-HMO-2024" } },
"created": "2024-03-10T10:00:00Z",
"servicedDate": "2024-03-10",
"item": [{
"sequence": 1,
"productOrService": { "coding": [{ "code": "43235" }] },
"servicedDate": "2024-03-10",
"unitPrice": { "value": 1200.00, "currency": "USD" },
"net": { "value": 1200.00, "currency": "USD" }
}]
}

Step 2: Submit Claim

curl -X POST \
https://api.turquoise.health/tpa-api/v1/claims/submit \
-H "X-API-Key: $TURQUOISE_API_KEY" \
-H "Content-Type: application/fhir+json" \
-d @claim.json

Response (202 Accepted):

{
"resourceType": "Bundle",
"type": "transaction-response",
"entry": [{
"response": {
"status": "202 Accepted",
"location": "ClaimResponse/CLMR-2024-001"
}
}]
}

Step 3: Poll for Adjudication

Claims are adjudicated asynchronously. Poll for results:

curl -X GET \
https://api.turquoise.health/tpa-api/v1/claims/CLM-2024-001/response \
-H "X-API-Key: $TURQUOISE_API_KEY"

Response:

{
"resourceType": "ClaimResponse",
"id": "CLMR-2024-001",
"status": "active",
"outcome": "complete",
"adjudication": [{
"category": { "coding": [{ "code": "allowedamount" }] },
"amount": { "value": 1200.00, "currency": "USD" }
}],
"extension": [{
"url": "https://turquoise.health/stripe-trace-id",
"valueString": "trace_0324_abc123xyz"
}]
}

Step 4: Authorize Settlement

Once adjudicated, authorize the fund release:

curl -X POST \
https://api.turquoise.health/tpa-api/v1/settlements/authorize \
-H "X-API-Key: $TURQUOISE_API_KEY" \
-d '{
"claim_response_id": "CLMR-2024-001",
"authorization_code": "AUTH-20240310",
"approver": "john.smith@tpa.com"
}'

Response:

{
"settlement_id": "SETTLE-2024-001",
"status": "pending",
"claim_response_id": "CLMR-2024-001",
"authorized_at": "2024-03-10T10:15:00Z",
"expected_arrival": "2024-03-12T09:00:00Z"
}
warning

Once authorized, settlements cannot be reversed. Ensure claim adjudication is verified before authorization.

Step 5: Monitor Settlement

Listen for settlement completion webhook:

# You'll receive this webhook:
POST /webhooks/settlements
{
"event": "settlement.completed",
"settlement_id": "SETTLE-2024-001",
"claim_response_id": "CLMR-2024-001",
"stripe_trace_id": "trace_0324_abc123xyz",
"provider_npi": "1234567890",
"amount": 1100.00,
"arrived_at": "2024-03-12T09:00:00Z"
}

Crawl-Walk-Run: Batch to Real-Time Transition

Turquoise supports a phased integration approach:

Phase 1: Crawl (Batch Processing - Weeks 1-4)

Submit daily batch files via SFTP or API:

# Daily batch submission
curl -X POST \
https://api.turquoise.health/tpa-api/v1/claims/batch-submit \
-H "X-API-Key: $TURQUOISE_API_KEY" \
-H "Content-Type: application/fhir+json" \
-d @daily-claims.ndjson

Phase 2: Walk (Mixed Processing - Weeks 5-8)

Hybrid approach: batch for high-volume, real-time for urgent cases:

# Continue batch submissions
curl -X POST https://api.turquoise.health/tpa-api/v1/claims/batch-submit ...

# Add real-time for critical procedures
curl -X POST https://api.turquoise.health/tpa-api/v1/claims/submit \
-H "Priority: high" ...

Phase 3: Run (Real-Time Processing - Week 9+)

Full real-time integration with guaranteed sub-200ms contract lookups:

# All claims submitted in real-time
curl -X POST \
https://api.turquoise.health/tpa-api/v1/claims/submit \
-H "X-API-Key: $TURQUOISE_API_KEY" \
--data @claim.json

Security Handshake Setup

Option 1: VPN-Based

Establish a dedicated VPN tunnel for API requests:

# Configure VPN
export TURQUOISE_VPN_ENDPOINT="vpn.turquoise.health"
export TURQUOISE_VPN_CERT="./vpn-client.crt"

# Traffic flows through VPN only
# No requirement for TLS 1.3 on public internet

Use mutual TLS with client certificates:

# Install certificates
cp client.crt /etc/turquoise/certs/
cp client.key /etc/turquoise/certs/
chmod 600 /etc/turquoise/certs/client.key

# All requests use mTLS
curl -X GET \
https://api.turquoise.health/tpa-api/v1/health \
--cert /etc/turquoise/certs/client.crt \
--key /etc/turquoise/certs/client.key
info

mTLS is required for production. VPN is optional for additional security layers.

Error Handling & Retry Strategy

Idempotency Keys

All claim submissions should include an idempotency key:

curl -X POST \
https://api.turquoise.health/tpa-api/v1/claims/submit \
-H "Idempotency-Key: CLM-20240310-001" \
-H "X-API-Key: $TURQUOISE_API_KEY" \
-d @claim.json

This ensures duplicate submissions don't create duplicate claims.

Retry Logic

Implement exponential backoff for transient errors:

import time

def submit_claim_with_retry(claim, max_retries=3):
for attempt in range(max_retries):
try:
response = turquoise_client.claims.submit(claim)
return response
except TurquoiseError as e:
if e.status_code in [408, 429, 500, 502, 503, 504]:
wait_time = 2 ** attempt + random.uniform(0, 1)
time.sleep(wait_time)
else:
raise
raise Exception("Max retries exceeded")

Common Error Codes

CodeMeaningAction
400Invalid claim formatFix claim structure, retry once
401UnauthorizedCheck API key, refresh OAuth token
429Rate limitedWait and retry with backoff
500Server errorRetry with exponential backoff
503Service unavailableRetry after checking status page

Monitoring & Observability

Key Metrics to Track

{
"metrics": {
"daily_claims_submitted": 1250,
"claims_adjudicated_percent": 98.5,
"average_adjudication_time_ms": 1200,
"settlement_success_rate_percent": 99.8,
"average_settlement_delay_hours": 48,
"contract_lookup_success_rate_percent": 100.0,
"api_error_rate_percent": 0.2
}
}

Logging Example

{
"timestamp": "2024-03-10T10:30:00Z",
"claim_id": "CLM-2024-001",
"action": "submit",
"status": "success",
"response_time_ms": 145,
"stripe_trace_id": "trace_0324_abc123xyz"
}

Next Steps