Skip to main content

Flow documentation

Annual Plan Quote & Purchase

Partner implementation guide for quoting, staging, paying for, and binding an annual travel policy.

AudiencePartner developers and solution architects implementing annual plan quote-to-purchase flowsLast updatedOctober 2, 2026Flows1Operations2

Annual policies use a deferred purchase flow:

annualPlanQuote -> stageAnnualPolicyPurchase -> embedded payment session -> hosted PCI card form -> automatic backend binding

The current GraphQL schema does not expose a streamlined annual equivalent to the single-trip purchasePolicy mutation. Do not submit annual quote data to purchasePolicy.

Operation Summary

StepOperationPurposeValue to retain
1annualPlanQuoteReturn eligible annual products and coverage choicesquoteNumber, selected productCode, selected coverage IDs, quoted amount
2stageAnnualPolicyPurchaseCreate the pending annual policyplanGuid
3Embedded payment appSecurely capture card data, process payment, and automatically bind the staged annual policypaymentSessionId; reconciled planNumber and policy result

Keep API credentials and payment verification on your backend. See Single Trip Quote & Purchase for the common authentication headers and payment identifier distinctions.

Flow

MERMAID
sequenceDiagram
    autonumber
    actor Traveler
    participant App as Partner app
    participant Backend as Partner backend
    participant API as Travel Insured GraphQL API
    participant Payment as Approved payment flow

    Traveler->>App: Enter annual coverage and traveler details
    App->>Backend: Request annual products
    Backend->>API: annualPlanQuote
    API-->>Backend: quoteNumber and annual products
    Backend-->>App: Display products and prices
    Traveler->>App: Select annual product
    Backend->>API: stageAnnualPolicyPurchase
    API-->>Backend: planGuid
    Backend->>Payment: Create payment session for planGuid
    Payment-->>Backend: paymentSessionId, embedToken, expiresAt
    Backend-->>App: Short-lived widget configuration
    App->>Payment: Submit card in hosted PCI form
    Payment->>Payment: Process payment and bind policy
    Payment-->>App: Payment or policy UX event
    Backend->>Backend: Reconcile authoritative policy status
    Backend-->>App: Return issued policy confirmation

Step 1: Request an Annual Quote

GraphQL
mutation QuoteAnnualPlan($annualPlanQuoteRequest: AnnualPlanQuoteRequestInput!) {
  annualPlanQuote(annualPlanQuoteRequest: $annualPlanQuoteRequest) {
    quoteNumber
    products {
      productId
      productCode
      productName
      productDescription
      availablePaymentMethod {
        paymentMethod
      }
      coverages {
        productCoverageId
        productCoverageType
        productCoverageTypeCode
        coverageLimits {
          productCoverageLimitId
          totalPrice
          available
        }
      }
    }
  }
}

This example omits the optional trip segment.

Annual Plan - No Known Trip Segment

Use this request when the customer is purchasing annual coverage without supplying a known trip. Do not use it when the quote included a trip segment that must be carried into staging.

Request example variables:

JSON
{
  "annualPlanQuoteRequest": {
    "agencyNumber": "<assigned-agency-number>",
    "effectiveDate": "2027-07-01",
    "includeOptionalCoverage": true,
    "residencyCountryIsoCode": "US",
    "residencyStateIsoCode": "CT",
    "travelers": [
      {
        "id": 1,
        "primaryTraveler": true,
        "dateOfBirth": "1985-06-15",
        "firstName": "<primary-first-name>",
        "lastName": "<primary-last-name>",
        "email": "<primary-email>"
      },
      {
        "id": 2,
        "primaryTraveler": false,
        "dateOfBirth": "1987-08-22",
        "firstName": "<traveler-first-name>",
        "lastName": "<traveler-last-name>"
      }
    ]
  }
}

Effective Date and Travelers

  • effectiveDate is the requested start of annual coverage.
  • Supply exactly one traveler with primaryTraveler: true.
  • Assign a unique integer id to every traveler.
  • Keep each ID associated with the same person through quote and staging. These IDs also connect travelers to an optional trip segment.
  • Names and email are nullable in the quote schema, but collect enough identity context to prevent traveler mismatches before purchase.

Optional Trip Segment

Include tripSegment when the annual quote must also describe a known trip. It requires departure and return dates, at least one destination, and its traveler list.

JSON
"tripSegment": {
  "departureDate": "2027-08-10",
  "returnDate": "2027-08-18",
  "depositDate": "<YYYY-MM-DD>",
  "destinations": [
    { "countryIsoCode": "FR" }
  ],
  "travelers": [
    {
      "id": 1,
      "firstName": "<primary-first-name>",
      "lastName": "<primary-last-name>",
      "dateOfBirth": "1985-06-15",
      "tripCost": 2500.00
    }
  ]
}

A trip-segment traveler ID must refer to the same person represented by that ID in the top-level travelers list.

Use the Quote Response

  1. Retain quoteNumber.
  2. Display only returned annual products and coverage choices.
  3. Carry the selected productCode and optional coverage IDs unchanged.
  4. Use the response price rather than a locally calculated premium.
  5. Re-run annualPlanQuote when the effective date, residency, travelers, or segment changes.

Step 2: Stage the Annual Purchase

GraphQL
mutation StageAnnualPlan($annualPolicyPurchaseStage: AnnualPolicyPurchaseStageInput!) {
  stageAnnualPolicyPurchase(
    annualPolicyPurchaseStage: $annualPolicyPurchaseStage
  ) {
    planGuid
  }
}

Request example variables:

JSON
{
  "annualPolicyPurchaseStage": {
    "agencyNumber": "<assigned-agency-number>",
    "quoteNumber": "<annual-quote-number>",
    "deliveryTypes": [
      { "deliveryType": "Email" }
    ],
    "product": {
      "productCode": "<selected-annual-product-code>",
      "effectiveDate": "2027-07-01",
      "optionalCoverages": []
    },
    "planTravelers": [
      {
        "id": 1,
        "primaryTraveler": true,
        "firstName": "<primary-first-name>",
        "lastName": "<primary-last-name>",
        "dateOfBirth": "1985-06-15",
        "contactInfo": {
          "email": "<primary-email>",
          "phoneNumbers": ["<primary-phone>"],
          "address": {
            "addressLine1": "<street-address>",
            "city": "<city>",
            "stateIsoCode": "CT",
            "zipCode": "<postal-code>",
            "countryIsoCode": "US"
          }
        }
      },
      {
        "id": 2,
        "primaryTraveler": false,
        "firstName": "<traveler-first-name>",
        "lastName": "<traveler-last-name>",
        "dateOfBirth": "1987-08-22"
      }
    ]
  }
}

Annual Plan - With Trip Segment

Use the same base request when the quote included a known trip, and add the confirmed segment before staging:

JSON
"tripSegment": {
  "departureDate": "2027-08-10",
  "returnDate": "2027-08-18",
  "depositDate": "<YYYY-MM-DD>",
  "destinations": [
    { "countryIsoCode": "FR" }
  ],
  "travelers": [
    {
      "id": 1,
      "firstName": "<primary-first-name>",
      "lastName": "<primary-last-name>",
      "dateOfBirth": "1985-06-15",
      "tripCost": 2500.00
    }
  ]
}

The segment is optional when no trip is known. When present in the quote, carry it forward with the same traveler IDs and confirmed values. If dates, destinations, travelers, or costs change, request a fresh annualPlanQuote and stage from that new authoritative quote.

For no optional coverage, use "optionalCoverages": []. For a selected coverage, use the SDL-verified shape:

JSON
"optionalCoverages": [
  {
    "productCoverageTypeCode": "<type-code-from-annual-quote>",
    "productCoverageLimitId": 301
  }
]

Multiple coverage entries are allowed. Each type code and limit ID must come from the selected annual quote product. Requote after the selection changes and use the refreshed authoritative amount for payment.

deliveryType is a required String in the published SDL, which does not define allowed values or casing. Email reflects the observed integration request shape but requires Travel Insured API Owner Confirmation as the canonical runtime value.

The stage response contains only planGuid. Keep the quote number, effective date, selected premium, travelers, and payment state in server-side checkout state.

Step 3: Complete Payment

From your backend, create an embedded payment session with the returned planGuid, current approved amount, billing contact, and billing address. Return only the short-lived session values required to mount the widget. Do not call processPayment; payment-session creation replaces that partner-orchestrated mutation.

The widget captures card data only in the Travel Insured-hosted PCI form. After successful capture, the embedded payment app processes payment and automatically binds the annual policy on the backend. Treat widget events as UX signals. Poll the session status from the partner backend and require both status and bindStatus to be Bound before confirming issuance.

Do not call processPayment or policyBindRequest; the embedded payment app handles that orchestration behind the scenes. Follow the Payment Integration Guide for the complete session and security contract.

Persist After Issuance

  • Store planNumber as the durable annual-policy identifier.
  • Retain paymentSessionId for authoritative server-side status polling and support correlation.
  • Protect policy documents and traveler data with server-side object-level authorization.
  • Use searchPlan with planNumber to retrieve the issued plan for later servicing.
  • Preserve traveler and segment identifiers returned by plan search before starting annual modification.

Failure and Retry Rules

Failure pointRecommended action
Annual quote failsCorrect inputs; do not substitute a single-trip quote
Annual inputs changeRequest a fresh annual quote and replace the selection
Staging failsCorrect the request; do not begin payment without planGuid
Payment or binding is pending or unknownPoll the payment-session status with bounded backoff; do not call payment or bind mutations
Final policy result is uncertainReconcile the existing session before retrying session creation

Do not log API credentials, payment data, or complete traveler records. Apply authorization before returning quote, payment, policy, or document data to a browser session.

Still need help?

Reach out to your account manager for support.