Using the ISA SDK with Vue 3
Initialize the ISA SDK once on your backend, expose a quote endpoint, and render v3 plan offers from a Vue 3 component.
Using the ISA SDK with Vue 3
A Vue 3 + Composition API integration of the ISA SDK. The SDK ships no
Vue-specific surface — it runs on your backend, and Vue calls your backend.
This guide wires one client per server process, a POST /api/quote route
that runs a prequalify, and a component that renders the v3 plan offers.
If you have not made a first call yet, read the
TypeScript Quickstart first — it covers the
Isa client, the prequalify request, and the v3 response shape this guide
renders.
Install
npm install isa-sdk
The SDK targets Node 20+ and the bundled [email protected]+ toolchain (Vite,
Nuxt 3, vue-cli with Vite). Both ESM and CommonJS work.
Keep the token on the server. Your
isa_live_…/isa_test_…bearer
token authenticates every API call and must never reach the browser. Run
the SDK on a backend (Node API route, edge function, or BFF) and have Vue
call your own endpoint. The pattern below proxies through/api/quote;
theIsaclient lives behind that route.
Initialize the client (on your backend)
Construct one Isa instance per server process. The client authenticates
with a bearer token read from the ISA_TOKEN environment variable.
// server/isa.ts (Node — Express, Fastify, or any framework)
import { Isa } from 'isa-sdk';
// Reads ISA_TOKEN (isa_live_… in production, isa_test_… in development).
export const isa = await Isa.fromEnv();
Isa.fromEnv() resolves the bearer token from ISA_TOKEN; pass it
explicitly with Isa.withBearer({ token }) if you manage configuration
yourself. The client is concurrency-safe — share the single instance across
all requests.
Load reference data
Expose isa.zyins.datasets.get() from your backend (for example, a
POST /api/datasets route) and cache the response on first request. Vue
components fetch from your endpoint, not from the SDK directly. Datasets
change rarely — carrier additions, rate updates — so a daily refresh is
plenty.
Run a quote
The canonical happy path: John Doe, male, born 1962-04-18, North Carolina,
70 inches, 195 pounds, no conditions or medications, looking at $25,000 of
final-expense coverage.
To quote a whole product family, use ProductSelection.byTypes([ProductClass.FinalExpense]). This quotes roughly 248 plans for the applicant.
To narrow results to specific carriers, pass product IDs directly with ProductSelection.of([...]). Get the IDs from isa.zyins.datasets.get(). Note: the v3 contract no longer narrows by slug.
Backend: POST /api/quote
POST /api/quote// server/routes/quote.ts (Express; same pattern in Fastify, Hono, etc.)
import { Router } from 'express';
import {
Isa, Sex, State, Height, Weight, NicotineDuration, Coverage,
ProductSelection, ProductClass,
} from 'isa-sdk';
const isa = await Isa.withBearer(); // share this instance across requests
export const quoteRouter = Router().post('/quote', async (_req, res, next) => {
try {
const { data } = await isa.zyins.prequalify({
applicant: {
dob: '1962-04-18',
sex: Sex.Male,
height: Height.fromFeetInches(5, 10),
weight: Weight.fromPounds(195),
state: State.NorthCarolina,
nicotineUse: { lastUsed: NicotineDuration.Never },
},
coverage: Coverage.faceValue(25_000),
// Quote a whole product family; narrow to specific carriers with
// ProductSelection.of([...]) using product IDs from datasets.get().
products: ProductSelection.byTypes([ProductClass.FinalExpense]),
});
res.json(data); // { plans: V3Offer[] }
} catch (err) {
next(err);
}
});
A successful response is the v3 envelope: object: "prequalify_result",
plus request_id, idempotency_key, livemode, and data.plans. Each
offer in data.plans carries the carrier, the product, the death benefit,
and a pricing[] array — one row per rate class. The headline premium and
eligibility live on the row flagged primary.
Frontend: Vue component
<!-- src/components/QuoteButton.vue -->
<script setup lang="ts">
import { ref } from 'vue';
// The fields this component reads off a v3 plan offer. See the
// TypeScript Quickstart for the full V3Offer shape.
type PricingRow = {
primary: boolean;
rate_class: string;
eligibility: { category: 'immediate' | 'graded' | 'rop'; eligible: boolean };
premium: { amount: { cents: number; display: string } };
};
type PlanOffer = {
id: string;
carrier: { name: string };
product: { name: string };
pricing: PricingRow[];
};
const loading = ref(false);
const plans = ref<PlanOffer[]>([]);
// The headline price and eligibility come from the row flagged `primary`.
function headline(plan: PlanOffer): PricingRow {
return plan.pricing.find((row) => row.primary) ?? plan.pricing[0];
}
async function runQuote() {
loading.value = true;
try {
const r = await fetch('/api/quote', { method: 'POST' });
const data = (await r.json()) as { plans: PlanOffer[] };
plans.value = data.plans;
} finally {
loading.value = false;
}
}
</script>
<template>
<button :disabled="loading" @click="runQuote">
{{ loading ? 'Running…' : 'Run quote' }}
</button>
<ul>
<li v-for="plan in plans" :key="plan.id">
{{ plan.carrier.name }} — {{ plan.product.name }} —
{{ headline(plan).eligibility.category }} —
{{ headline(plan).premium.amount.display }}
</li>
</ul>
</template>
premium.amount.cents is the canonical integer in US cents;
premium.amount.display is the carrier-formatted string. Render display,
do arithmetic on cents. The SDK mints an idempotency key per call
automatically.
Handle errors
Every SDK exception extends IsaError. Match on the specific subclass at
the component or app boundary — never switch on error.message.
// src/isa/errors.ts
import {
IsaApiError,
IsaConfigError,
IsaIdempotencyConflictError,
} from 'isa-sdk';
export function reportIsaError(err: unknown): string {
if (err instanceof IsaIdempotencyConflictError) {
return `Duplicate request with a different body (key ${err.key}).`;
}
if (err instanceof IsaApiError) {
console.error('isa api', err.code, err.requestId);
return err.message; // server messages are human-safe
}
if (err instanceof IsaConfigError) {
return 'SDK configuration error. Check ISA_TOKEN on the server.';
}
return 'An unexpected error occurred. Please try again.';
}
Pair this with a Vue error boundary (app.config.errorHandler) so
unhandled SDK exceptions surface a toast rather than crashing the tree.
Always log err.requestId — that is the support ticket's anchor.
Production checklist
ISA_TOKENis set on the server only (isa_live_…in production,
isa_test_…in development) — never bundled into the Vue app.- The Vue app calls a backend endpoint (for example,
/api/quote); the SDK
lives behind that route. - Idempotency keys are UUID v4 (the SDK default). If you mint your own,
match the shape550e8400-e29b-41d4-a716-446655440000. err.requestIdis logged on every error (for example,
req_01HZK2N5GQR9T8X4B6FJW3Y1AS).- An
app.config.errorHandlertranslates server-error responses into
UI-appropriate toasts.
What's next
- Authentication — bearer tokens, test vs. live,
rotation - Idempotency — how the SDK mints keys, when to bring
your own - Errors reference — every
codevalue and its remediation - TypeScript Quickstart — the underlying v3
request and response shapes
Updated about 10 hours ago