/** * Rx-Bridge API — TypeScript type definitions * * These types mirror the actual API request/response shapes. * Import or copy them into your integration code. The complete, generated * reference (every endpoint, field and error code) is /openapi.json. * * Naming convention: * - Script-related fields → camelCase (matches the database column names) * - Account / contract / webhook fields → snake_case * - Pagination envelope → snake_case */ // --------------------------------------------------------------------------- // Shared // --------------------------------------------------------------------------- /** Standard paginated-list envelope (GET /scripts, GET /pharmacies) */ export interface PaginatedResponse { data: T[] pagination: { page: number limit: number total: number total_pages: number has_more: boolean } } /** Standard error body */ export interface ApiError { error: string /** Stable machine-readable identifier (see "Error codes" in /openapi.json). Branch on this, not on `error`. */ code?: string /** The request field the error refers to (onboarding endpoints), e.g. `licenses[0].state` */ field?: string /** Field-level validation errors (present on POST /scripts 400 validation failures) */ details?: Record /** Only on POST /scripts 400 `prescriber_required`: the active prescribers to choose from */ active_prescribers?: { prescriber_id: string; npi: string }[] } // --------------------------------------------------------------------------- // Script // --------------------------------------------------------------------------- export type ScriptStatus = | 'draft' | 'pending' | 'processing' | 'on_hold_pending_pa' | 'verified' | 'ready' | 'completed' | 'cancelled' | 'rejected' | 'awaiting_payment' /** Full script object (returned by POST /scripts and GET /scripts/:id) */ export interface Script { id: string providerOrgId: string pharmacyOrgId: string createdByUserId: string // Patient patientName: string patientPhone: string | null patientEmail: string | null patientDateOfBirth: string | null patientAddressLine1: string | null patientAddressLine2: string | null patientCity: string | null patientState: string | null patientZip: string | null patientGender: string | null patientAllergies: string[] | null // Insurance insuranceProvider: string | null insurancePolicyId: string | null insuranceGroupNumber: string | null insuranceRxBin: string | null insuranceRxPCN: string | null insuranceCardholderName: string | null insuranceRelationship: string | null // Prescriber (auto-populated from onboarding data) prescriberId: string | null prescriberNpi: string | null prescriberDeaNumber: string | null prescriberLicenseNumber: string | null prescriberLicenseState: string | null // Medication medicationName: string ndc: string | null strength: string | null quantity: string | null directions: string | null refills: number prescriptionDate: string | null prescriptionExpirationDate: string | null substitutionAllowed: boolean dawCode: number | null priorAuthRequired: boolean priorAuthNumber: string | null controlledSubstanceSchedule: string | null quantityWritten: string | null daysSupply: number | null diagnosisCodes: string[] | null specialInstructions: string | null pharmacyNotes: string | null // Fulfillment orderValue: number | null status: ScriptStatus priorityProcessing: boolean deliveryTrackingEnabled: boolean autoRefillRemindersEnabled: boolean // Shipping shippingCarrier: string | null trackingNumber: string | null shippingStatus: string | null // External system cross-reference externalSystem: string | null externalSystemScriptId: string | null // Cancellation cancellationReason: string | null cancellationNotes: string | null // Timestamps createdAt: string updatedAt: string // Prescriber approval approvalStatus: 'not_required' | 'pending' | 'approved' | 'rejected' prescriberRejectionReason: string | null // Clinical context /** Free-text clinical note sent with the script (max 2000 characters), or null. Returned only to the provider organization's keys; always null for the pharmacy organization. */ clinicalNote: string | null // Attribution and decision timestamps /** Display name of the submitter, as you sent it on create */ submittedByName: string | null /** Your own id for the submitter */ submittedByExternalId: string | null /** ISO timestamp of the prescriber's approval, or null */ approvedAt: string | null /** ISO timestamp of the prescriber's rejection, or null */ rejectedAt: string | null /** Absolute URL of this script in the Rx-Bridge provider dashboard */ portalUrl: string } /** POST /api/v1/scripts — request body */ export interface CreateScriptRequest { pharmacyOrgId: string patientName: string medicationName: string patientPhone?: string patientEmail?: string patientDateOfBirth?: string patientAddressLine1?: string patientAddressLine2?: string patientCity?: string patientState?: string patientZip?: string patientGender?: string patientAllergies?: string[] insuranceProvider?: string insurancePolicyId?: string insuranceGroupNumber?: string insuranceRxBin?: string insuranceRxPCN?: string insuranceCardholderName?: string insuranceRelationship?: string ndc?: string strength?: string quantity?: string directions?: string refills?: number prescriptionDate?: string substitutionAllowed?: boolean dawCode?: number priorAuthRequired?: boolean priorAuthNumber?: string controlledSubstanceSchedule?: string quantityWritten?: string daysSupply?: number diagnosisCodes?: string[] specialInstructions?: string pharmacyNotes?: string priorityProcessing?: boolean deliveryTrackingEnabled?: boolean autoRefillRemindersEnabled?: boolean externalSystem?: string externalSystemScriptId?: string // Which prescriber signs the script /** Prescriber that signs this script. Optional when the org has exactly one active prescriber; send this or prescriber_npi when it has several. */ prescriber_id?: string /** 10-digit NPI of the prescriber that signs this script (alternative to prescriber_id). */ prescriber_npi?: string // Delegated submission / prescriber approval /** Set true when the submitter is not the assigned prescriber — routes the script through prescriber sign-off before it reaches the pharmacy. */ requiresPrescriberApproval?: boolean /** Display name of the actual submitter, shown to the prescriber in the approval-request email and dashboard. */ submittedByName?: string | null /** Your own opaque id for the submitter, stored for audit purposes only — never resolved to a Rx-Bridge user. */ submittedByExternalId?: string | null /** Optional clinical context from the submitter, intended for the approving prescriber. Trimmed; max 2000 characters; empty is stored as null. Returned only to the provider organization's keys. */ clinicalNote?: string | null } /** PATCH /api/v1/scripts/:id/status — request body */ export interface UpdateScriptStatusRequest { status: 'processing' | 'on_hold_pending_pa' | 'verified' | 'ready' | 'completed' | 'cancelled' | 'rejected' /** Required when status is "completed" (for commission calculation) */ orderValue?: number /** Required (with reviewedByUserId) when moving a controlled-substance script to "verified" */ redFlagReviewConfirmed?: boolean /** The reviewing pharmacist's user ID — required when redFlagReviewConfirmed is true and status is "verified"; must be a pharmacist or admin member of your organization */ reviewedByUserId?: string /** Optional free-text notes from the red-flag review */ reviewNotes?: string /** The ID type checked at pickup — required (with idVerifiedByUserId and idVerificationLast4) when moving a controlled-substance script (controlledSubstanceSchedule set) to "completed". One of: drivers_license, state_id, passport, military_id, other. */ idVerificationType?: string /** Last 4 characters of the ID number checked at pickup — never the full number. Required alongside idVerificationType. */ idVerificationLast4?: string /** The verifying pharmacist's user ID — required when idVerificationType is set and status is "completed"; must be a pharmacist or admin member of your organization. */ idVerifiedByUserId?: string } /** GET /api/v1/scripts/:id/shipment — response */ export interface ShipmentInfo { carrier: string | null trackingNumber: string | null shippingStatus: string | null } /** POST /api/v1/scripts/:id/shipment — request body */ export interface UpdateShipmentRequest { carrier?: string trackingNumber?: string shippingStatus?: string } /** One entry of GET /api/v1/scripts/:id/events */ export interface ScriptEvent { id: string /** ISO timestamp */ occurredAt: string type: 'submitted' | 'approval_requested' | 'approved' | 'rejected' | 'status_changed' | 'shipment_updated' /** Title Case display text */ label: string source: 'medoura' | 'praxis' | 'rxbridge' | 'pharmacy' /** The submitter or assigned prescriber where known; null otherwise */ actorName: string | null /** For example the previous status, the rejection reason, or carrier and shipping status */ detail: string | null } /** GET /api/v1/scripts/:id/events — response (oldest first) */ export interface ScriptEventsResponse { events: ScriptEvent[] } // --------------------------------------------------------------------------- // Pharmacy // --------------------------------------------------------------------------- export interface Pharmacy { id: string name: string city: string state: string servicesOffered: string[] | null phone: string email: string } /** One pharmacy in a GET /api/v1/pharmacies/recommend response. `id` is the pharmacy organization id (use it as `pharmacyOrgId`). */ export interface PharmacyRecommendationItem { id: string name: string city: string state: string servicesOffered: string[] } /** GET /api/v1/pharmacies/recommend?patient_state=TX&medication_id=... — response */ export interface PharmacyRecommendationResponse { recommendation: { pharmacy: PharmacyRecommendationItem; reason: string } | null alternatives: PharmacyRecommendationItem[] } // --------------------------------------------------------------------------- // Medication // --------------------------------------------------------------------------- /** Returned by GET /api/v1/medications */ export interface Medication { id: string name: string genericName: string | null ndc: string | null strength: string | null form: string | null schedule: string | null isControlled: boolean } // --------------------------------------------------------------------------- // Contract // --------------------------------------------------------------------------- export type ContractStatus = 'pending' | 'active' | 'terminated' | 'rejected' /** Returned by all contract endpoints */ export interface Contract { id: string provider_org_name: string | null pharmacy_org_name: string | null status: ContractStatus requested_by_org_name: string | null start_date: string | null end_date: string | null notes: string | null created_at: string updated_at: string } /** POST /api/v1/contracts — request body */ export interface CreateContractRequest { pharmacy_org_id: string notes?: string } /** PATCH /api/v1/contracts/:id — request body */ export interface UpdateContractRequest { action: 'accept' | 'reject' | 'terminate' start_date?: string end_date?: string notes?: string } // --------------------------------------------------------------------------- // Pricing // --------------------------------------------------------------------------- /** POST /api/v1/pricing/estimate — request body */ export interface PricingEstimateRequest { addOns?: { priorityProcessing?: boolean deliveryTracking?: boolean autoRefillReminders?: boolean } orderValue?: number } /** POST /api/v1/pricing/estimate — response */ export interface PricingEstimate { providerFee: number | null providerFeeBreakdown: { baseFee: number priorityProcessingFee: number deliveryTrackingFee: number autoRefillRemindersFee: number totalFee: number } pharmacyCommission: number | null } // --------------------------------------------------------------------------- // Webhook // --------------------------------------------------------------------------- // contract.* events are reserved: subscribable, but nothing emits them yet. export type WebhookEvent = | 'script.created' | 'script.status_changed' | 'script.shipment_updated' | 'script.approval_requested' | 'script.approved' | 'script.rejected' | 'contract.created' | 'contract.accepted' | 'contract.rejected' | 'contract.terminated' | 'prescriber.onboarded' | 'prescriber.activated' | 'prescriber.rejected' | 'prescriber.deactivated' | 'onboarding_session.completed' | '*' /** Body POSTed to your webhook URL. Verify `X-RxBridge-Signature` over the raw body first. */ export interface WebhookPayload> { event: Exclude /** Unique per event (a UUID). Identical on every delivery retry: dedupe on it. */ event_id: string /** ISO time Rx-Bridge recorded the change (for changes detected by LifeFile polling, the poll time) */ occurred_at: string timestamp: string /** false when the event was caused by a test-mode API key or concerns a test script */ livemode: boolean data: T } /** `data` of prescriber.onboarded | prescriber.activated | prescriber.rejected | prescriber.deactivated */ export interface PrescriberEventData { prescriber_id: string npi: string status: PrescriberStatus /** Present on prescriber.rejected and prescriber.deactivated */ reason?: string /** false for a prescriber created with a test-mode API key */ livemode: boolean } /** `data` of onboarding_session.completed. Prescriber data only; `status` is the prescriber's status at completion (pending_review, never approval). */ export interface OnboardingSessionCompletedData { session_id: string external_ref: string prescriber_id: string npi: string status: PrescriberStatus /** false for a session created with a test-mode API key */ livemode: boolean } /** `data` of script.approval_requested | script.approved | script.rejected */ export interface ScriptApprovalEventData { script_id: string approval_status: 'pending' | 'approved' | 'rejected' /** script.approval_requested only */ prescriber_id?: string /** script.approval_requested only */ submitted_by_name?: string | null /** script.approved only: ISO timestamp of the approval */ approved_at?: string /** script.rejected only: ISO timestamp of the rejection */ rejected_at?: string /** script.rejected only */ rejection_reason?: string } /** Returned by GET /webhooks and GET /webhooks/:id */ export interface Webhook { id: string url: string events: string[] description: string | null is_active: boolean created_at: string updated_at: string } /** Returned only by POST /webhooks (includes the secret) */ export interface WebhookCreated extends Webhook { /** HMAC-SHA256 signing secret — only returned once at creation time */ secret: string } /** POST /api/v1/webhooks — request body */ export interface CreateWebhookRequest { url: string events: WebhookEvent[] description?: string } /** PATCH /api/v1/webhooks/:id — request body */ export interface UpdateWebhookRequest { url?: string events?: WebhookEvent[] description?: string is_active?: boolean } /** Incoming webhook delivery payload (what your receiver gets). Same shape as WebhookPayload. */ export interface WebhookDelivery { event: string /** Unique per event (a UUID). Identical on every delivery retry: dedupe on it. */ event_id: string /** ISO time Rx-Bridge recorded the change (for changes detected by LifeFile polling, the poll time) */ occurred_at: string timestamp: string /** false when the event was caused by a test-mode API key or concerns a test script */ livemode: boolean data: Record } /** Headers included in every webhook delivery */ export interface WebhookDeliveryHeaders { 'x-rxbridge-signature': string // "sha256=" 'x-rxbridge-event': string 'x-rxbridge-delivery': string // Unique delivery UUID } // --------------------------------------------------------------------------- // Provision // --------------------------------------------------------------------------- /** POST /api/v1/provision — request body */ export interface ProvisionRequest { email: string full_name: string organization_name?: string organization_type?: 'provider' | 'pharmacy' external_source?: string external_user_id?: string /** * Your own id for the practice (1-200 chars). The first call creates the practice's organization and key; later * calls with the same id add the person to it and return no key. Requires a partner-specific provisioning key, * organization_name, and organization_type "provider". Unique per partner. */ external_org_id?: string /** Role for a NEW member when external_org_id is sent: "admin" (default for the first user) or "prescriber" (default after). Existing members are never changed. */ role?: 'admin' | 'prescriber' /** Create a test-mode key (scripts are never sent to a pharmacy). Default false */ test_mode?: boolean } /** POST /api/v1/provision — response */ export interface ProvisionResponse { /** 'member_added' and 'already_member' only occur with external_org_id */ status: 'created' | 'existing' | 'member_added' | 'already_member' organization_id: string organization_name?: string organization_type?: 'provider' | 'pharmacy' user_id: string /** Only returned once — store securely. null for 'member_added' / 'already_member' (use the practice's existing key). */ api_key: string | null api_key_id: string | null isTestKey: boolean is_test_key: boolean needs_onboarding?: boolean onboarding_url?: string message: string } // --------------------------------------------------------------------------- // Onboarding // --------------------------------------------------------------------------- export type PrescriberStatus = 'pending_review' | 'active' | 'rejected' | 'deactivated' export type PrescriberReviewStatus = 'pending' | 'approved' | 'rejected' export interface LicenseInput { /** Two-letter code: 50 states, DC or PR. Stored uppercase. */ state: string license_number: string /** physician | aprn | pa | pharmd. Aliases accepted: MD, DO -> physician; NP, APRN, FNP -> aprn; PA, PA-C -> pa; PharmD -> pharmd. */ license_type: string /** YYYY-MM-DD. Required; must not be in the past. */ expiration_date: string } /** POST /api/v1/onboarding/prescriber — request body */ export interface PrescriberOnboardingRequest { full_legal_name: string date_of_birth?: string mobile_phone: string professional_email: string npi: string degree?: string primary_specialty?: string licenses: LicenseInput[] will_prescribe_controlled_substances?: boolean dea_number?: string dea_expiration_date?: string dea_schedules?: string dea_registration_address?: { line1?: string line2?: string city?: string state?: string zip?: string } attestations: { informationAccurate: boolean licensedAndInGoodStanding: boolean willComplyWithLaws: boolean willPrescribeWithinScope: boolean } typed_signature: string } /** POST /api/v1/onboarding/prescriber — response (201 for a new NPI, 200 when an existing prescriber was updated) */ export interface PrescriberOnboardingResponse { prescriber_id: string onboarding_completed: true /** false for a new prescriber until a platform admin approves it */ is_active: boolean status: PrescriberStatus review_status: PrescriberReviewStatus message: string } /** One prescriber in GET /api/v1/onboarding/prescriber */ export interface PrescriberSummary { prescriber_id: string full_legal_name: string npi: string npi_verified: boolean /** Registry name differs from full_legal_name; reviewers see it */ npi_name_mismatch: boolean degree: string | null primary_specialty: string | null onboarding_completed: boolean is_active: boolean status: PrescriberStatus review_status: PrescriberReviewStatus licenses: { state: string; license_number: string; license_type: string | null; expiration_date: string | null }[] dea_registrations: { dea_number: string; expiration_date: string | null; schedules: unknown }[] } /** GET /api/v1/onboarding/prescriber — response (optional filters: ?npi= and ?prescriber_id=) */ export interface PrescriberOnboardingStatusResponse { organization_id: string prescribers: PrescriberSummary[] } /** PATCH /api/v1/onboarding/licenses — request body */ export interface UpdateLicensesRequest { prescriber_id: string licenses?: LicenseInput[] dea?: { dea_number: string expiration_date?: string schedules?: string registration_address?: { line1?: string city?: string state?: string zip?: string } } } /** PATCH /api/v1/onboarding/licenses — response */ export interface UpdateLicensesResponse { success: boolean licenses_updated: number dea_updated: boolean } // --------------------------------------------------------------------------- // Hosted onboarding sessions // --------------------------------------------------------------------------- /** Effective session status. Terminal states: completed, expired, canceled. */ export type OnboardingSessionStatus = 'created' | 'opened' | 'completed' | 'expired' | 'canceled' /** POST /api/v1/onboarding/sessions — request body. Provider organizations only. */ export interface CreateOnboardingSessionRequest { /** Absolute https URL (at most 2000 characters) on an origin an RxBridge admin registered for your organization or its partner. http is accepted only for loopback (localhost, 127.0.0.1, [::1]) origins registered test-only, with a test-mode key. */ return_url: string /** Your identifier for the prescriber; at most one open session per external_ref */ external_ref: string /** Opaque value echoed back on the redirect */ state?: string /** Seconds the link stays valid: 300 to 604800, default 1800 */ expires_in?: number /** Cancel an open session for the same external_ref and mint a new one */ replace?: boolean /** Advisory and editable; never verified. `attestations` and `typed_signature` are rejected. */ prefill?: { full_legal_name?: string professional_email?: string mobile_phone?: string date_of_birth?: string npi?: string degree?: string primary_specialty?: string licenses?: LicenseInput[] will_prescribe_controlled_substances?: boolean dea_number?: string dea_expiration_date?: string dea_registration_address?: { line1?: string; line2?: string; city?: string; state?: string; zip?: string } dea_schedules?: string | string[] } } /** POST /api/v1/onboarding/sessions — response (201). `url` is returned once and cannot be recovered. */ export interface CreateOnboardingSessionResponse { id: string url: string expires_at: string } /** GET /api/v1/onboarding/sessions/:id — response */ export interface OnboardingSession { id: string status: OnboardingSessionStatus livemode: boolean external_ref: string state: string | null return_url: string prescriber_id: string | null prescriber_status: PrescriberStatus | null review_status: PrescriberReviewStatus | null /** License summary once completed (empty before). No license numbers. */ licenses: { state: string; license_type: string | null; expiration_date: string | null }[] created_at: string expires_at: string opened_at: string | null completed_at: string | null canceled_at: string | null } /** DELETE /api/v1/onboarding/sessions/:id — response (200). `expired` when the session had already expired. */ export interface CancelOnboardingSessionResponse { id: string status: 'canceled' | 'expired' } // --------------------------------------------------------------------------- // Organization // --------------------------------------------------------------------------- /** GET /api/v1/me/organization — response */ export interface Organization { id: string name: string type: 'provider' | 'pharmacy' slug: string }