Skip to main content

Bind Flow

The bind flow starts on the Checkout page after the customer completes payment in the Hydra iframe. The gateway initiates bind asynchronously and returns 202 immediately; the frontend subscribes to SSE for real-time status.

Checkout Page

apps/fastlane-portal/src/app/pages/carriers/safeco/auto/checkout.tsx:

  1. Customer selects payment method (credit card or ACH)
  2. SafecoHydraPaymentBlock renders the Hydra iframe for secure payment collection
  3. On successful payment, Hydra calls onPaymentSuccess(instrumentId)
  4. handlePaymentSuccessbindPolicy(instrumentId)
  5. bindPolicy calls sessionApi.bindSafecoPolicy({ sessionId, paymentInstrumentId: instrumentId, selectedPlan })
  6. On success, sets sseListening = true to start SSE subscription

Bind API

POST /ghcms/safeco/bind

Request body:

FieldRequiredDescription
sessionIdYesSession UUID
paymentInstrumentIdYesHydra instrument ID from payment success
selectedPlanNoPayment plan code (e.g. monthly, annual)

Response: 202 Accepted with { success: true, data: { status: 'PENDING' } }

Backend Flow

apps/apis/fastlane-api-gateway/src/app/controllers/safeco.controller.ts:

  1. Validate sessionId, paymentInstrumentId
  2. Load session, Safeco quote, Hydra payment from session store
  3. Verify Hydra instrument matches paymentInstrumentId
  4. bindStatusService.setStatus(sessionId, 'PENDING')
  5. executeBindInBackground(sessionId, handler, context) — async, non-blocking
  6. Return 202 immediately

executeBindInBackground:

  1. Sets status to BINDING
  2. Runs SafecoBindHandler.execute(context)
  3. On success: stores bind response, sets status SUCCESS with { policyNumber }
  4. On failure: sets status FAILED with error message

SafecoBindHandler

apps/apis/fastlane-api-gateway/src/app/handlers/safeco-bind.handler.ts:

  • Resolves carrier session (quote/client IDs) via CarrierQuoteSessionService
  • Maps payment plan and coverages
  • Calls SafecoV3BindService.bindPolicy(bindSessionData, hydraInstrument)

RC3 Bind Service

libs/apis/carriers/safeco/src/v3/application/services/safeco-v3-bind.service.ts

Bind Preparation

  1. Check if safecoQuoteData has an ACORD envelope — if not, regenerate via fieldMapper.mapToAcordXml with a minimal session
  2. Prepare for RC3: set TransactionType = 'RateCall3', SubTransactionType = 'com.safeco_Bind', remove MsgStatus
  3. Inject payment details onto PersPolicy.PaymentOption

Payment Injection

addPaymentToRequest() builds the PaymentOption on PersPolicy:

FieldValue
PaymentPlanCdMapped from display code via PLAN_CODE_MAP
com.safeco_DownPaymentInfoAlways CreditCard, includes InstrumentId and DownPaymentAmt
com.safeco_RecurringPaymentInfoIncludes RecurringPaymentMethod, InstrumentId, ElectronicSignatureYN, RCCAcceptanceYN

Plan Code Mapping

Display CodeSafeco Code
FullFL
MonthlyMO
QuarterlyQT
SemiAnnual2E

Full-pay plans use ByMail for recurring payment method. Monthly/recurring plans default to CreditCard.

Retry Logic

executeBindWithRetry(rc3Request, maxRetries = 1):

  • Up to 2 total attempts (1 initial + 1 retry)
  • Only retries on transient Hydra errors: messages containing 'GetInstrumentDetails' or 'try again later'
  • 2-second delay between retries
  • Non-transient errors fail immediately

Response Parsing

Policy number extraction uses a cascading fallback:

PrioritySource
1PolicySummaryInfo.PolicyNumber
2ItemIdInfo.InsurerId
3QuoteInfo.CompanysQuoteNumber
4RqUID

Premium extraction also cascades:

PrioritySource
1QuoteInfo.com.safeco_QuoteRq_PremiumTotal
2PersPolicy.FullTermAmt.Amt
3Sum of PersVeh[].FullTermAmt.Amt

Bind Response DTO

{
success: true,
policyNumber: string,
bindDate: string,
effectiveDate: string,
expirationDate: string, // Computed: effectiveDate + DurationPeriod months
boundAt: string, // ISO timestamp
confirmationNumber: string,
premium: number,
documents: [{ type: 'policy_portal', name, url, description }],
safecoPortalUrl: string,
messages: string[],
errors: string[],
}

Status Progression

PENDING → BINDING → SUCCESS | FAILED

The frontend receives these statuses via SSE. See SSE Bind Status.

Error Handling

Error TypeBehavior
MsgStatusCd === 'Rejected'Extracts all ExtendedStatusDesc messages, throws
MsgStatusCd === 'Error'Same as Rejected
Missing ACORD envelopeAttempts regeneration from field mapper, throws if that fails
Missing PersPolicyThrows 'Invalid quote data structure: missing PersPolicy'
Transient Hydra errorRetried once after 2s delay
All other errorsWrapped as 'Bind policy failed: ...'

Sequence Diagram