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:
- Customer selects payment method (credit card or ACH)
SafecoHydraPaymentBlockrenders the Hydra iframe for secure payment collection- On successful payment, Hydra calls
onPaymentSuccess(instrumentId) handlePaymentSuccess→bindPolicy(instrumentId)bindPolicycallssessionApi.bindSafecoPolicy({ sessionId, paymentInstrumentId: instrumentId, selectedPlan })- On success, sets
sseListening = trueto start SSE subscription
Bind API
POST /ghcms/safeco/bind
Request body:
| Field | Required | Description |
|---|---|---|
| sessionId | Yes | Session UUID |
| paymentInstrumentId | Yes | Hydra instrument ID from payment success |
| selectedPlan | No | Payment 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:
- Validate
sessionId,paymentInstrumentId - Load session, Safeco quote, Hydra payment from session store
- Verify Hydra instrument matches
paymentInstrumentId bindStatusService.setStatus(sessionId, 'PENDING')executeBindInBackground(sessionId, handler, context)— async, non-blocking- Return 202 immediately
executeBindInBackground:
- Sets status to
BINDING - Runs
SafecoBindHandler.execute(context) - On success: stores bind response, sets status
SUCCESSwith{ policyNumber } - On failure: sets status
FAILEDwith 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
- Check if
safecoQuoteDatahas an ACORD envelope — if not, regenerate viafieldMapper.mapToAcordXmlwith a minimal session - Prepare for RC3: set
TransactionType = 'RateCall3',SubTransactionType = 'com.safeco_Bind', removeMsgStatus - Inject payment details onto
PersPolicy.PaymentOption
Payment Injection
addPaymentToRequest() builds the PaymentOption on PersPolicy:
| Field | Value |
|---|---|
PaymentPlanCd | Mapped from display code via PLAN_CODE_MAP |
com.safeco_DownPaymentInfo | Always CreditCard, includes InstrumentId and DownPaymentAmt |
com.safeco_RecurringPaymentInfo | Includes RecurringPaymentMethod, InstrumentId, ElectronicSignatureYN, RCCAcceptanceYN |
Plan Code Mapping
| Display Code | Safeco Code |
|---|---|
| Full | FL |
| Monthly | MO |
| Quarterly | QT |
| SemiAnnual | 2E |
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:
| Priority | Source |
|---|---|
| 1 | PolicySummaryInfo.PolicyNumber |
| 2 | ItemIdInfo.InsurerId |
| 3 | QuoteInfo.CompanysQuoteNumber |
| 4 | RqUID |
Premium extraction also cascades:
| Priority | Source |
|---|---|
| 1 | QuoteInfo.com.safeco_QuoteRq_PremiumTotal |
| 2 | PersPolicy.FullTermAmt.Amt |
| 3 | Sum 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 Type | Behavior |
|---|---|
MsgStatusCd === 'Rejected' | Extracts all ExtendedStatusDesc messages, throws |
MsgStatusCd === 'Error' | Same as Rejected |
| Missing ACORD envelope | Attempts regeneration from field mapper, throws if that fails |
Missing PersPolicy | Throws 'Invalid quote data structure: missing PersPolicy' |
| Transient Hydra error | Retried once after 2s delay |
| All other errors | Wrapped as 'Bind policy failed: ...' |