Embedded Insurance API - Auto
The Embedded Insurance API is organized around REST. It accepts JSON request bodies, returns JSON responses, and uses standard HTTP response codes and Bearer token authentication.
Authorization: Bearer <access_token> and Content-Type: application/json unless otherwise noted.
Authentication
The EI API uses OAuth 2.0 client credentials. Exchange your client_id and client_secret for a short-lived Bearer token, then include it in the Authorization header of every subsequent request.
Your credentials will be shared via a secure one-time link during partner onboarding.
| Field | Type | Description | |
|---|---|---|---|
| client_id | string | required | Your partner client ID |
| client_secret | string | required | Your partner client secret |
| grant_type | string | required | Always client_credentials |
access_token, token_type, and expires_inPOST https://auth.embeddedinsurance.com/oauth2/token
Content-Type: application/x-www-form-urlencoded
client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&grant_type=client_credentials
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5...",
"token_type": "Bearer",
"expires_in": 3600
}
Authorization: Bearer <access_token>
Embedded Component
The Embedded Component is a drop-in React widget that surfaces a personalized auto insurance offer directly inside your application - on a dashboard, account page, or post-purchase screen - without redirecting the customer to a hosted microsite.
Published as @ei-tech/embedded-component on npm. You give it a leadId and two async callbacks (getContent and getUrl) that proxy to your backend; the component handles polling, rendering, and CTA hand-off to the EI microsite.
- On mount, the component calls
getContent(leadId), which hits a route on your backend (e.g.GET /api/embedded-content/:leadId). - Your backend authenticates with EI via POST /oauth2/token and proxies GET /auto/v1/leads/:id/embedded-content.
- The component renders the layout returned (
content,content-cta,image-content,image-content-cta, ornone). - If the response includes
"continuePolling": true, the component schedules anothergetContentcall afterpollingIntervalms (default5000), up tomaxPollingAttempts(default50). - When the customer clicks the CTA button, the component calls
getUrl(leadId)- your backend proxies POST /auto/v1/leads/:id/get-link - and opens the returned one-time URL in a new tab.
Your EI client credentials never leave your server - the browser only ever talks to your two proxy routes.
| Prop | Type | Description | |
|---|---|---|---|
| leadId | string | required | The EI lead ID returned by Create Lead |
| getContent | (leadId) => Promise<Content> | required | Async fetch of the content payload from your backend proxy |
| getUrl | (leadId) => Promise<string> | required | Async fetch of the one-time microsite URL when the customer clicks the CTA |
| theme | 'dark' | 'light' | optional | Visual theme. Defaults to dark |
| pollingInterval | number | optional | Milliseconds between content polls. Defaults to 5000 |
| maxPollingAttempts | number | optional | Cap on poll iterations. Defaults to 50 |
The shape returned by /embedded-content (passed through by your backend) determines what the component renders. layout selects the variant; the other fields are populated according to the variant's schema.
| layout | Renders | Required fields |
|---|---|---|
| none | Nothing | - |
| content | Heading + subheading + footer | mainHeading, subHeading, footerText |
| content-cta | Text with a CTA button | Above + buttonText |
| image-content | Image + text | mainHeading, subHeading, footerText, imageUrl, imageAlt |
| image-content-cta | Image + text + CTA | All of the above + buttonText |
Optional fields available on CTA layouts: ctaHeadline, buttonAriaLabel, buttonDisabled, buttonLoading, buttonBackgroundColor, buttonTextColor. All payloads accept continuePolling: boolean to drive the polling loop.
npm install @ei-tech/embedded-component
React 18+ peer dependency. Import the bundled stylesheet once in your app entry: import '@ei-tech/embedded-component/styles';
// Express example - keep this on your backend
async function getEIToken() {
const r = await fetch('https://auth.embeddedinsurance.com/oauth2/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
client_id: process.env.EI_CLIENT_ID,
client_secret: process.env.EI_CLIENT_SECRET,
grant_type: 'client_credentials'
})
});
return (await r.json()).access_token;
}
// Drives getContent - proxies the embedded-content payload
app.get('/api/embedded-content/:leadId', async (req, res) => {
const token = await getEIToken();
const r = await fetch(
`https://api.embeddedinsurance.com/auto/v1/leads/${req.params.leadId}/embedded-content`,
{ headers: { Authorization: `Bearer ${token}` } }
);
res.json(await r.json());
});
// Drives getUrl - proxies the one-time microsite link
app.get('/api/quote-link/:leadId', async (req, res) => {
const token = await getEIToken();
const r = await fetch(
`https://api.embeddedinsurance.com/auto/v1/leads/${req.params.leadId}/get-link`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ partnerBrand: process.env.EI_PARTNER_BRAND })
}
);
const { url } = await r.json();
res.json(url);
});
import { EmbeddedInsurance, Content } from '@ei-tech/embedded-component';
const getContent = async (leadId: string): Promise<Content> => {
const r = await fetch(`/api/embedded-content/${leadId}`);
if (!r.ok) throw new Error('Failed to load content');
return r.json();
};
const getUrl = async (leadId: string): Promise<string> => {
const r = await fetch(`/api/quote-link/${leadId}`);
if (!r.ok) throw new Error('Failed to get link');
return r.json();
};
export function Dashboard({ leadId }: { leadId: string }) {
return (
<EmbeddedInsurance
leadId={leadId}
getContent={getContent}
getUrl={getUrl}
theme="dark"
/>
);
}
{
"layout": "image-content-cta",
"mainHeading": "Your Quote is Ready!",
"subHeading": "Click to view your personalized insurance details.",
"buttonText": "View Now",
"imageUrl": "https://cdn.example.com/quote.svg",
"imageAlt": "Insurance Quote",
"footerText": "Insurance by Embedded Insurance Agency, LLC.",
"continuePolling": false
}
Create Lead
Send a customer's information to EI to get an auto insurance quote. At minimum you need the primary applicant's contact details, address, and one vehicle.
"isTest": true at the root of the request body when working in a non-production context. The same endpoint and credentials work in both environments.
| Field | Type | Description | |
|---|---|---|---|
| firstName | string | required | |
| lastName | string | required | |
| dateOfBirth | string | required | Format: YYYY-MM-DD |
| address | object | required | address1, city, state (2-letter), zip (5-digit). address2 optional. |
| phoneNumber | string | required | E.164 format: +1XXXXXXXXXX |
| string | required | Must be unique per lead | |
| gender | string | optional | Male · Female · Non-Binary |
| maritalStatus | string | optional | Single · Married · Divorced · Widowed · Separated · Domestic Partner |
| residenceOwnershipType | string | optional | Own · Rent · Other |
| monthsAtAddress | integer | optional | |
| priorAddress | object | optional | Same structure as address |
| licenseNumber | string | optional | |
| licenseState | string | optional | 2-letter state abbreviation |
| yearsLicensed | integer | optional | |
| educationLevel | string | optional | HighSchool · BachelorsDegree · MastersDegree · and more |
| income | array | optional | Array of income objects: employmentType, employerName, jobTitle, monthsAtEmployer, annualIncome |
Object with numeric string keys "1"–"9". Each shares the same optional fields as applicant, plus:
| Field | Type | Description | |
|---|---|---|---|
| relationshipToApplicant | string | optional | Spouse · Parent · Child · Relative · Cohabitant · Other |
Object with numeric string keys "1"–"9". Vehicle 1 is required.
| Field | Type | Description | |
|---|---|---|---|
| make | string | required | |
| model | string | required | |
| year | string | required | 4-digit year as string |
| vin | string | optional | 17-character VIN |
| trim | string | optional | |
| estimatedAnnualMileage | integer | optional | |
| isFinanced | boolean | optional | |
| lien | object | optional | lienHolder, monthlyPayment, originalAmount, payoffAmount, remainingTerm |
| Field | Type | Description | |
|---|---|---|---|
| orgId | string | required | Your organization ID provided by EI |
| isTest | boolean | optional | Set true for test requests |
| partnerExternalId | string | optional | Your internal reference ID for this lead |
| partnerData | object | optional | Arbitrary key-value metadata to pass through |
id.POST /auto/v1/leads
Authorization: Bearer <access_token>
Content-Type: application/json
{
"applicant": {
"firstName": "John",
"lastName": "Doe",
"dateOfBirth": "1980-01-15",
"address": {
"address1": "123 Main St",
"city": "Boston",
"state": "MA",
"zip": "02108"
},
"phoneNumber": "+16175551234",
"email": "john.doe@example.com",
"gender": "Male",
"maritalStatus": "Married"
},
"coapplicants": {
"1": {
"firstName": "Jane",
"lastName": "Doe",
"dateOfBirth": "1982-06-20",
"relationshipToApplicant": "Spouse"
}
},
"vehicles": {
"1": {
"vin": "1HGCM82633A123456",
"make": "Toyota",
"model": "Camry",
"year": "2020"
}
},
"orgId": "your-org-id"
}
{
"id": "bea82fae-e1b7-5bc5-810b-c38694e66aef",
"status": "PENDING"
}
Get Lead
Retrieve the latest status and quote information for a lead.
| Field | Type | Description | |
|---|---|---|---|
| id | string (UUID) | required | The lead ID returned by Create Lead |
GET /auto/v1/leads/bea82fae-e1b7-5bc5-810b-c38694e66aef
Authorization: Bearer <access_token>
Update Lead
Requote a lead with updated applicant, driver, or vehicle information. Only the fields included in the request body will be updated.
| Field | Type | |
|---|---|---|
| id | string (UUID) | required |
| Field | Type | Description | |
|---|---|---|---|
| id | string (UUID) | required | Lead ID (must match path param) |
| address | object | optional | Updated address |
| drivers | object | optional | Keyed "1"–"9", updated driver info |
| vehicles | object | optional | Keyed "1"–"9", updated vehicle info |
POST /auto/v1/leads/bea82fae-e1b7-5bc5-810b-c38694e66aef
Authorization: Bearer <access_token>
Content-Type: application/json
{
"id": "bea82fae-e1b7-5bc5-810b-c38694e66aef",
"address": {
"address1": "456 New Ave",
"city": "Boston",
"state": "MA",
"zip": "02109"
},
"vehicles": {
"1": {
"vin": "1HGCM82633A123456",
"make": "Toyota",
"model": "Camry",
"year": "2020"
}
}
}
Get Quote Link
Returns a one-time URL that directs the applicant to the Embedded Insurance quoting microsite, pre-populated with their lead data.
| Field | Type | |
|---|---|---|
| id | string (UUID) | required |
| Field | Type | Description | |
|---|---|---|---|
| partnerBrand | string | required | Your partner brand identifier provided by EI |
url - a one-time redirect linkPOST /auto/v1/leads/bea82fae-e1b7-5bc5-810b-c38694e66aef/get-link
Authorization: Bearer <access_token>
Content-Type: application/json
{
"partnerBrand": "your-brand"
}
{
"url": "https://quote.embeddedinsurance.com/..."
}
Get Quote Content
Returns the props needed to render the @ei-tech/embedded-component React component directly within your application. Use this endpoint when embedding the EI quoting experience inline rather than redirecting to a hosted microsite.
| Field | Type | |
|---|---|---|
| id | string (UUID) | required |
@ei-tech/embedded-componentGET /auto/v1/leads/bea82fae-e1b7-5bc5-810b-c38694e66aef/embedded-content
Authorization: Bearer <access_token>
Get Verification Link
Returns a one-time link to the EI verification microsite, where the applicant can confirm their coverage and bind a policy.
| Field | Type | |
|---|---|---|
| id | string (UUID) | required |
| Field | Type | Description | |
|---|---|---|---|
| partnerBrand | string | required | Your partner brand identifier |
| returnUrl | string | optional | URL to redirect to when verification completes |
| partnerExternalId | string | optional | Your internal reference for this application |
POST /auto/v1/leads/bea82fae-e1b7-5bc5-810b-c38694e66aef/verify/get-link
Authorization: Bearer <access_token>
Content-Type: application/json
{
"partnerBrand": "your-brand",
"returnUrl": "https://yoursite.com/thank-you",
"partnerExternalId": "your-ref-123"
}
{
"url": "https://verify.embeddedinsurance.com/..."
}
Create Lead Event
Record a lifecycle event against a lead. Use this to signal partner-side state changes that EI should be aware of.
| Field | Type | |
|---|---|---|
| id | string (UUID) | required |
| Field | Type | Description | |
|---|---|---|---|
| type | string | required |
Event type. Supported values:
APPLICANT_AUTHENTICATED
|
POST /auto/v1/leads/bea82fae-e1b7-5bc5-810b-c38694e66aef/events
Authorization: Bearer <access_token>
Content-Type: application/json
{
"type": "APPLICANT_AUTHENTICATED"
}
{
"ok": true,
"eventId": "evt_123456789"
}
Common Errors
These error patterns are returned by most EI API endpoints.
Most error responses include a JSON body with error and optionally message to explain the failure.
{
"error": "invalid_request",
"message": "Missing required field: applicant.firstName"
}
Webhooks - Overview
EI delivers lifecycle events to a HTTPS URL you provide during onboarding. Each event arrives as an HTTP POST with a JSON body and is signed so you can verify it came from EI.
| Header | Value |
|---|---|
| Content-Type | application/json |
| X-Webhook-Signature | Hex HMAC-SHA256 of the raw request body using your shared webhook secret - see Verifying Signatures |
All event bodies share these fields:
| Field | Type | Description |
|---|---|---|
| id | string | Unique event ID |
| leadId | string | The lead this event relates to |
| partnerCode | string | Your EI partner code |
| partnerExternalId | string | Optional - the ID you supplied via Create Lead |
| eventType | string | One of verification · quote · lead_summary · needs_insurance |
| eventTime | string | ISO 8601 timestamp |
| idempotencyKey | string | Stable per unique event content - use it to deduplicate retries |
2xx within a few seconds to acknowledge receipt. Non-2xx responses or timeouts may be retried; treat your handler as idempotent by keying on idempotencyKey.// Express - keep the raw body so the signature check works
app.post('/webhooks/ei',
express.raw({ type: 'application/json' }),
(req, res) => {
const sig = req.headers['x-webhook-signature'];
const body = req.body.toString('utf8');
if (!verifyWebhookSignature(process.env.EI_WEBHOOK_SECRET, sig, body)) {
return res.status(401).end();
}
const event = JSON.parse(body);
// dedupe on event.idempotencyKey, then handle by event.eventType
res.sendStatus(200);
}
);
Verifying Signatures
Every webhook is signed with HMAC-SHA256 over the raw request body using a secret shared with you during onboarding. Verify the signature before trusting the payload.
- Read the
X-Webhook-Signatureheader. - Compute
HMAC-SHA256(secret, rawBody)as a hex string. - Compare the two using a constant-time equality check.
import crypto from 'node:crypto';
const createWebhookSignature = (secret, body) => {
const hmac = crypto.createHmac('sha256', secret);
hmac.update(body);
return hmac.digest('hex');
};
export const verifyWebhookSignature = (secret, signature, body) => {
if (!signature) return false;
const expected = createWebhookSignature(secret, body);
try {
return crypto.timingSafeEqual(
Buffer.from(signature, 'hex'),
Buffer.from(expected, 'hex'),
);
} catch {
return false;
}
};
Verification Events
Delivered when insurance verification finishes for a lead - either successfully or with a failure reason.
| Field | Type | Description |
|---|---|---|
| insuranceVerification.id | string | Verification record ID |
| insuranceVerification.source | string | id-card · third-party |
| policyInfo.carrier | string | Verified carrier name (optional) |
| policyInfo.policyType | string | Always auto |
| policyInfo.policyNumber | string | Optional |
| policyInfo.vehicles[] | array | vin, year, make, model - all optional |
| policyInfo.namedInsureds[] | array | firstName, lastName, isPrimary |
| media[] | array | documentType (insurance-id-card · declarations), url, description, contentType, size, createdAt, expiresAt |
| verificationConfidence | number | Optional - confidence score from 0.00 to 1.00 |
| _tag | Description |
|---|---|
| NoActiveAutoPoliciesFound | No active auto policies were found for the insured |
| NoVehicleMatchesFound | No auto policies with matching vehicles were found |
| RetrieveError | An error occurred while retrieving verification data |
Media URLs are pre-signed and expire - download or copy assets before expiresAt if you need to retain them.
{
"id": "evt_abc123",
"leadId": "lead_987654321",
"partnerExternalId": "partner_app_456",
"partnerCode": "ACME",
"eventType": "verification",
"eventTime": "2024-01-15T10:30:00.000Z",
"status": "completed",
"idempotencyKey": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"insuranceVerification": {
"id": "verification_123",
"source": "id-card",
"policyInfo": {
"carrier": "Progressive",
"policyType": "auto",
"policyNumber": "POL123456789",
"vehicles": [
{ "vin": "1HGBH41JXMN109186", "year": "2023", "make": "Honda", "model": "Accord" }
],
"namedInsureds": [
{ "firstName": "Jane", "lastName": "Doe", "isPrimary": true }
]
},
"media": [
{
"documentType": "insurance-id-card",
"url": "https://storage.googleapis.com/ei-media/insurance-cards/id-card-123.jpg",
"description": "Insurance identification card",
"contentType": "image/jpeg",
"size": 512000,
"createdAt": "2024-01-15T10:25:00.000Z",
"expiresAt": "2024-01-22T10:25:00.000Z"
}
],
"verificationConfidence": 0.95
}
}
{
"id": "evt_def456",
"leadId": "lead_987654321",
"partnerCode": "ACME",
"eventType": "verification",
"eventTime": "2024-01-15T10:35:00.000Z",
"status": "failed",
"idempotencyKey": "f6e5d4c3-b2a1-0987-fedc-ba9876543210",
"insuranceVerification": {
"id": "verification_124",
"source": "third-party",
"failureReasons": [
{ "_tag": "NoActiveAutoPoliciesFound", "message": "No active auto policies found" }
]
}
}
Quote Events
Delivered when a quote is successfully generated for a lead.
| Field | Type | Description |
|---|---|---|
| quote.id | string | Quote ID |
| quote.carrier | string | Insurance carrier the quote is with |
| quote.totalPremiumCents | integer | Total premium in cents (optional) |
| quote.savingsAmountCents | integer | Savings vs current policy in cents |
| quote.savingsMonthlyCents | integer | Monthly savings in cents |
| quote.savingsAnnualCents | integer | Annual savings in cents (rounded to nearest $10) |
| quote.currentPaymentMonthlyCents | integer | Current monthly payment in cents |
| quote.newPaymentMonthlyCents | integer | New monthly payment in cents |
Savings and payment fields are populated only when the lead has both a quote and prior insurance information from verification. Expect them to be absent for cold quotes.
{
"id": "evt_ghi789",
"leadId": "lead_987654321",
"partnerExternalId": "partner_app_456",
"partnerCode": "ACME",
"eventType": "quote",
"eventTime": "2024-01-15T11:15:00.000Z",
"status": "completed",
"idempotencyKey": "12345678-abcd-ef01-2345-6789abcdef01",
"quote": {
"id": "quote_456",
"carrier": "Geico",
"totalPremiumCents": 120000,
"savingsAmountCents": 30000,
"savingsMonthlyCents": 2500,
"savingsAnnualCents": 30000,
"currentPaymentMonthlyCents": 12500,
"newPaymentMonthlyCents": 10000
}
}
{
"id": "evt_jkl012",
"leadId": "lead_987654321",
"partnerCode": "ACME",
"eventType": "quote",
"eventTime": "2024-01-15T11:15:00.000Z",
"status": "completed",
"idempotencyKey": "abcdef01-2345-6789-abcd-ef0123456789",
"quote": {
"id": "quote_457",
"carrier": "Allstate",
"totalPremiumCents": 150000
}
}
Lead Summary Events
A consolidated lifecycle stream covering verification, quoting, viewing, and binding for a lead. Each event carries a summary object with whichever components are available at that point in the journey.
| Status | Required summary keys | Meaning |
|---|---|---|
| verification.completed | insuranceVerification | Verification finished successfully |
| quote.completed | quote (+ optional insuranceVerification) | A quote was generated |
| quote.viewed | quote | The lead viewed a quote |
| policy.bound | policy | The lead bound a policy |
| error | - | Lead is in an error state (e.g. quoting error) |
| Field | Type | Description |
|---|---|---|
| id | string | |
| status | string | pending · completed · failed |
| source | string | id-card · third-party |
| policyInfo | object | Same shape as in Verification Events |
| media[] | array | Same shape as in Verification Events |
| verifiedAt | string | ISO 8601 timestamp |
| Field | Type | Description |
|---|---|---|
| id | string | |
| status | string | completed · viewed |
| carrier | string | |
| totalPremiumCents | integer | |
| savingsAmountCents | integer | Optional |
| createdAt | string | ISO 8601 timestamp |
| viewedAt | string | Optional, present on quote.viewed |
| Field | Type | Description |
|---|---|---|
| id | string | |
| carrier | string | |
| boundAt | string | ISO 8601 timestamp |
{
"id": "req_123456789",
"leadId": "lead_987654321",
"partnerExternalId": "partner_app_456",
"eventType": "lead_summary",
"eventTime": "2024-01-15T11:15:00.000Z",
"status": "quote.completed",
"summary": {
"insuranceVerification": {
"id": "verification_123",
"status": "completed",
"source": "id-card",
"policyInfo": { "carrier": "Progressive", "policyType": "auto" },
"verifiedAt": "2024-01-15T10:30:00.000Z"
},
"quote": {
"id": "quote_456",
"status": "completed",
"carrier": "Geico",
"totalPremiumCents": 120000,
"savingsAmountCents": 30000,
"createdAt": "2024-01-15T11:15:00.000Z"
}
}
}
{
"id": "req_123456789",
"leadId": "lead_987654321",
"partnerExternalId": "partner_app_456",
"eventType": "lead_summary",
"eventTime": "2024-01-15T11:30:00.000Z",
"status": "quote.viewed",
"summary": {
"quote": {
"id": "quote_456",
"status": "viewed",
"carrier": "Geico",
"totalPremiumCents": 120000,
"createdAt": "2024-01-15T11:15:00.000Z",
"viewedAt": "2024-01-15T11:30:00.000Z"
}
}
}
{
"id": "req_123456789",
"leadId": "lead_987654321",
"partnerExternalId": "partner_app_456",
"eventType": "lead_summary",
"eventTime": "2024-01-15T12:00:00.000Z",
"status": "policy.bound",
"summary": {
"policy": {
"id": "policy_789",
"carrier": "Geico",
"boundAt": "2024-01-15T12:00:00.000Z"
}
}
}
{
"id": "req_123456789",
"leadId": "lead_987654321",
"partnerExternalId": "partner_app_456",
"eventType": "lead_summary",
"eventTime": "2024-01-15T11:45:00.000Z",
"status": "error",
"summary": {}
}
Needs Insurance Event
Delivered when a user expresses interest in finding insurance via the insurance verification app. Use this signal to route the lead into a quoting flow.
| Field | Type | Description |
|---|---|---|
| source | string | Always insurance_verification_app |
All other fields come from the common envelope.
{
"id": "evt_mno345",
"leadId": "lead_987654321",
"partnerExternalId": "partner_app_456",
"partnerCode": "ACME",
"eventType": "needs_insurance",
"source": "insurance_verification_app",
"eventTime": "2024-01-15T09:00:00.000Z",
"idempotencyKey": "11112222-3333-4444-5555-666677778888"
}
Get Health
Check the operational status of the API. No authentication required. Use this for uptime monitoring or pre-flight checks.
GET https://api.embeddedinsurance.com/auto/v1/health
{
"status": "ok"
}