@delegance/sdk 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +245 -249
- package/dist/index.d.mts +105 -21
- package/dist/index.d.ts +105 -21
- package/dist/index.js +25 -20
- package/dist/index.mjs +25 -20
- package/package.json +9 -4
package/README.md
CHANGED
|
@@ -1,27 +1,35 @@
|
|
|
1
1
|
# @delegance/sdk
|
|
2
2
|
|
|
3
|
-
TypeScript SDK
|
|
3
|
+
Get commercial insurance quotes from your code. This TypeScript SDK covers the Delegance API: signup, instant quotes, bind, payments, policies, certificates, bonds, claims, and documents.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Full docs: https://portal.delegancebrokerage.com/docs/sdk
|
|
6
|
+
|
|
7
|
+
## Install
|
|
6
8
|
|
|
7
9
|
```bash
|
|
8
10
|
npm install @delegance/sdk
|
|
9
|
-
# or
|
|
10
|
-
yarn add @delegance/sdk
|
|
11
|
-
# or
|
|
12
|
-
pnpm add @delegance/sdk
|
|
13
11
|
```
|
|
14
12
|
|
|
15
13
|
Requires Node 18 or newer. The package ships CommonJS, ESM, and TypeScript types.
|
|
16
14
|
|
|
15
|
+
Prefer a terminal? [`@delegance/cli`](https://www.npmjs.com/package/@delegance/cli) runs the same flows: `npx -y @delegance/cli quote start --demo`.
|
|
16
|
+
|
|
17
17
|
## Availability
|
|
18
18
|
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
19
|
+
- Quoting is open to every account. A new account from `createSignup()` can quote as soon as the owner confirms the email.
|
|
20
|
+
- Bind, payments, bonds, and claims are live over the API.
|
|
21
|
+
- A licensed Delegance broker approves every bind before coverage starts. `instantQuotes.bind()` files the request; it never charges a card.
|
|
22
|
+
- A switched-off feature answers 503 with `reason: 'not_available'`. The SDK does not retry that answer.
|
|
23
|
+
|
|
24
|
+
## One key, one company
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
An API key belongs to exactly one company. Every call acts on that company, so you never pass a company id to quote.
|
|
27
|
+
|
|
28
|
+
- `documents.upload()` and `documents.list()` take an optional `companyId`. Leave it out. If you name a company the key does not belong to, the server answers 403 with `code: 'company_mismatch'`.
|
|
29
|
+
- A customer key cannot create companies. `companies.create()` and `companies.upsert()` answer 403 `tenant_key_cannot_create`. Open a new account with `createSignup()` instead.
|
|
30
|
+
- `companies.list()` returns the key's own company.
|
|
31
|
+
|
|
32
|
+
## Quick start: sign up and quote
|
|
25
33
|
|
|
26
34
|
```typescript
|
|
27
35
|
import { createSignup, newDeviceSecret, DeleganceClient } from '@delegance/sdk';
|
|
@@ -33,6 +41,7 @@ const account = await signup.createAccount({
|
|
|
33
41
|
contactEmail: 'owner@acmebakery.com',
|
|
34
42
|
industry: 'commercial bakery',
|
|
35
43
|
companySize: '2-10',
|
|
44
|
+
address: { street: '100 Main St', city: 'Austin', state: 'TX', zip: '78701' },
|
|
36
45
|
});
|
|
37
46
|
const device = newDeviceSecret();
|
|
38
47
|
const { enrollmentId } = await signup.enroll(account.bootstrapKey, {
|
|
@@ -46,250 +55,258 @@ await signup.requestVerification(account.bootstrapKey);
|
|
|
46
55
|
const result = await signup.waitForKey(enrollmentId, device.secret);
|
|
47
56
|
if (result.status !== 'ready') throw new Error('Confirm link not clicked yet');
|
|
48
57
|
|
|
49
|
-
// 3. Quote
|
|
58
|
+
// 3. Quote. See "Instant quotes" below for the answers.
|
|
50
59
|
const client = new DeleganceClient({ apiKey: result.apiKey });
|
|
51
60
|
const session = await client.instantQuotes.start(['general_liability']);
|
|
52
|
-
// Answer session.questions (keyed by question id), then submit.
|
|
53
|
-
const submitted = await client.instantQuotes.submit({
|
|
54
|
-
submissionId: session.submissionId,
|
|
55
|
-
sessionVersion: session.sessionVersion,
|
|
56
|
-
answers: {},
|
|
57
|
-
});
|
|
58
|
-
const status = await client.instantQuotes.waitForQuotes(session.submissionId);
|
|
59
61
|
```
|
|
60
62
|
|
|
61
|
-
|
|
63
|
+
Store `result.apiKey` somewhere safe. The server shows it once.
|
|
62
64
|
|
|
63
|
-
## Quick
|
|
65
|
+
## Quick start: existing API key
|
|
64
66
|
|
|
65
67
|
```typescript
|
|
66
68
|
import { DeleganceClient } from '@delegance/sdk';
|
|
67
69
|
import fs from 'fs';
|
|
68
70
|
|
|
69
|
-
|
|
70
|
-
const client = new DeleganceClient({
|
|
71
|
-
apiKey: 'dlg_xxxxxxxx_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
|
|
72
|
-
});
|
|
71
|
+
const client = new DeleganceClient({ apiKey: process.env.DELEGANCE_API_KEY! });
|
|
73
72
|
|
|
74
|
-
//
|
|
75
|
-
const company = await client.companies.
|
|
76
|
-
|
|
77
|
-
industry: 'construction',
|
|
78
|
-
companySize: '11-25',
|
|
79
|
-
contactEmail: 'contact@abcconstruction.com',
|
|
80
|
-
fein: '12-3456789',
|
|
81
|
-
address: {
|
|
82
|
-
street: '123 Main St',
|
|
83
|
-
city: 'Austin',
|
|
84
|
-
state: 'TX',
|
|
85
|
-
zip: '78701'
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
console.log('Created company:', company.id);
|
|
73
|
+
// The key's own company
|
|
74
|
+
const [company] = await client.companies.list();
|
|
75
|
+
console.log(company.name);
|
|
90
76
|
|
|
91
|
-
// Upload a policy
|
|
77
|
+
// Upload a policy. No companyId: the key decides the company.
|
|
92
78
|
const doc = await client.documents.upload({
|
|
93
|
-
companyId: company.id,
|
|
94
79
|
file: fs.readFileSync('./GL-Policy-2025.pdf'),
|
|
95
80
|
fileName: 'GL-Policy-2025.pdf',
|
|
96
|
-
documentType: 'policy'
|
|
81
|
+
documentType: 'policy',
|
|
97
82
|
});
|
|
98
83
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
// Wait for extraction to complete
|
|
102
|
-
const result = await client.documents.waitForExtraction(doc.id, {
|
|
103
|
-
timeoutMs: 60000,
|
|
104
|
-
onStatusChange: (status) => console.log('Processing:', status)
|
|
105
|
-
});
|
|
84
|
+
const done = await client.documents.waitForExtraction(doc.id, { timeoutMs: 120_000 });
|
|
85
|
+
console.log(done.extraction?.policies);
|
|
106
86
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
87
|
+
// Read what is in force
|
|
88
|
+
const { policies } = await client.policies.list();
|
|
110
89
|
```
|
|
111
90
|
|
|
112
|
-
##
|
|
91
|
+
## Instant quotes
|
|
92
|
+
|
|
93
|
+
Real carrier premiums over the API. The flow has four calls.
|
|
94
|
+
|
|
95
|
+
1. `start(coverages)` returns the session and the carriers' questions.
|
|
96
|
+
2. `submit()` files your answers with the carriers.
|
|
97
|
+
3. `status()` or `waitForQuotes()` returns premiums as carriers answer.
|
|
98
|
+
4. `bind()` requests a bind on one offer.
|
|
113
99
|
|
|
114
|
-
|
|
100
|
+
Coverage ids: `general_liability`, `workers_comp`, `business_owners`, `cyber`, `professional_liability`, `tech_eo`, `commercial_auto`, `commercial_property`, `umbrella`.
|
|
115
101
|
|
|
116
102
|
```typescript
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
// Optional: Custom headers
|
|
131
|
-
headers: {
|
|
132
|
-
'X-Custom-Header': 'value'
|
|
133
|
-
}
|
|
103
|
+
const session = await client.instantQuotes.start(['general_liability', 'workers_comp']);
|
|
104
|
+
|
|
105
|
+
// Each question: { id, label, type, options?, required, prefill?, suggested?, showIf?, requiredIfShown? }
|
|
106
|
+
const answers: Record<string, unknown> = {};
|
|
107
|
+
for (const q of session.questions) {
|
|
108
|
+
if (q.prefill !== undefined && q.prefill !== null) answers[q.id] = q.prefill;
|
|
109
|
+
}
|
|
110
|
+
answers.annual_revenue = 850000;
|
|
111
|
+
|
|
112
|
+
const submitted = await client.instantQuotes.submit({
|
|
113
|
+
submissionId: session.submissionId,
|
|
114
|
+
sessionVersion: session.sessionVersion,
|
|
115
|
+
answers,
|
|
134
116
|
});
|
|
117
|
+
|
|
118
|
+
if (submitted.status === 'submitted') {
|
|
119
|
+
const status = await client.instantQuotes.waitForQuotes(session.submissionId, { timeoutMs: 10 * 60_000 });
|
|
120
|
+
console.log('Coverage starts', status.effectiveDate);
|
|
121
|
+
for (const q of status.carrierQuotes) {
|
|
122
|
+
console.log(q.coverage, q.carrierName, q.premium, q.limits, q.deductible, q.bindable);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
135
125
|
```
|
|
136
126
|
|
|
137
|
-
###
|
|
127
|
+
### Answers
|
|
138
128
|
|
|
139
|
-
|
|
129
|
+
- Key every answer by question `id`.
|
|
130
|
+
- `yes_no`: `'yes'` or `'no'`. `number`, `currency`, `percentage`: a number. `select`: one option `value`. Anything else: text.
|
|
131
|
+
- `prefill` comes from the insured's own account data. Send it back unless the insured changes it.
|
|
132
|
+
- `suggested` is a guess from another source. It counts only after the insured confirms it.
|
|
133
|
+
- `showIf: { questionId, equals }` hides a follow-up until the parent answer matches. A hidden question is never required. `requiredIfShown` makes it required while visible.
|
|
140
134
|
|
|
141
|
-
|
|
142
|
-
import { createClientFromEnv } from '@delegance/sdk';
|
|
135
|
+
### Submit results
|
|
143
136
|
|
|
144
|
-
|
|
145
|
-
const client = createClientFromEnv();
|
|
146
|
-
```
|
|
137
|
+
`submit()` returns `status`:
|
|
147
138
|
|
|
148
|
-
|
|
139
|
+
| Status | Meaning |
|
|
140
|
+
|--------|---------|
|
|
141
|
+
| `submitted` | Filed with the instant carriers. Poll `status()` for premiums. |
|
|
142
|
+
| `acord_pending` | Some coverages need a person. A broker task opened (`brokerTaskId`). |
|
|
143
|
+
| `no_carriers` | No carrier can quote this instantly. Hand it to a broker (below). |
|
|
149
144
|
|
|
150
|
-
|
|
145
|
+
A second submit for coverage that already has a live request answers 409 `active_request_exists`. To re-quote, call `start(coverages, { fresh: true })` and submit with `replace: true`.
|
|
151
146
|
|
|
152
|
-
|
|
147
|
+
### Reading quotes
|
|
153
148
|
|
|
154
|
-
|
|
155
|
-
const company = await client.companies.create({
|
|
156
|
-
name: 'ABC Construction', // Required
|
|
157
|
-
industry: 'construction', // Required
|
|
158
|
-
companySize: '11-25', // Required: '1', '2-10', '11-25', '26-50', '51-100', '100-499', '500+'
|
|
159
|
-
contactEmail: 'contact@abc.com', // Required
|
|
160
|
-
|
|
161
|
-
// Optional fields
|
|
162
|
-
legalName: 'ABC Construction LLC',
|
|
163
|
-
fein: '12-3456789',
|
|
164
|
-
website: 'https://abc.com',
|
|
165
|
-
yearEstablished: '2015',
|
|
166
|
-
companyStructure: 'LLC',
|
|
167
|
-
description: 'Commercial construction company',
|
|
168
|
-
contactPhone: '+1-555-123-4567',
|
|
169
|
-
externalId: 'ams-12345', // For deduplication
|
|
170
|
-
address: {
|
|
171
|
-
street: '123 Main St',
|
|
172
|
-
suite: 'Suite 100',
|
|
173
|
-
city: 'Austin',
|
|
174
|
-
state: 'TX',
|
|
175
|
-
zip: '78701'
|
|
176
|
-
}
|
|
177
|
-
});
|
|
178
|
-
```
|
|
149
|
+
`status()` returns `carrierQuotes`, one row per carrier offer:
|
|
179
150
|
|
|
180
|
-
|
|
151
|
+
- `premium`: annual premium in dollars, or null before the carrier prices it.
|
|
152
|
+
- `bindable`: true when you can bind the offer.
|
|
153
|
+
- `limits`: readable limits, for example `"$1M per occurrence / $2M aggregate"` or `"Statutory / $1M employers liability"`.
|
|
154
|
+
- `deductible`: dollars, 0 for none. Today only cyber quotes carry one; other lines return null.
|
|
155
|
+
- `effectiveDate` (on the status): when coverage would start, as `YYYY-MM-DD`.
|
|
181
156
|
|
|
182
|
-
|
|
183
|
-
// List your company
|
|
184
|
-
const companies = await client.companies.list();
|
|
157
|
+
The three fields are new in 0.2.1. An older server leaves them out, so treat a missing field like null.
|
|
185
158
|
|
|
186
|
-
|
|
187
|
-
const allCompanies = await client.companies.list({ includeCreated: true });
|
|
188
|
-
```
|
|
159
|
+
Compare prices within one coverage only. The cheapest bindable offer per coverage is the one to show first.
|
|
189
160
|
|
|
190
|
-
|
|
161
|
+
### No instant carrier: broker handoff
|
|
191
162
|
|
|
192
163
|
```typescript
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
console.log('Company already existed');
|
|
164
|
+
if (submitted.status === 'no_carriers') {
|
|
165
|
+
const plan = await client.instantQuotes.brokerHandoffQuestions(session.submissionId, answers);
|
|
166
|
+
const acordAnswers: Record<string, unknown> = {}; // answer plan.questions the same way
|
|
167
|
+
const handoff = await client.instantQuotes.brokerHandoff(session.submissionId, {
|
|
168
|
+
answers: acordAnswers,
|
|
169
|
+
instantAnswers: answers,
|
|
170
|
+
complete: true,
|
|
171
|
+
});
|
|
172
|
+
console.log(handoff.status, handoff.brokerTaskId); // 'broker_review'
|
|
203
173
|
}
|
|
204
174
|
```
|
|
205
175
|
|
|
206
|
-
|
|
176
|
+
A broker places the risk with a market that quotes by hand and emails the owner. `complete: false` says you stopped early; the broker asks the rest. A repeat call returns the same broker task. `status().brokerReview` shows the task.
|
|
207
177
|
|
|
208
|
-
|
|
178
|
+
### Bind and pay
|
|
209
179
|
|
|
210
180
|
```typescript
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
181
|
+
const status = await client.instantQuotes.status(session.submissionId);
|
|
182
|
+
const offer = status.carrierQuotes.find((q) => q.bindable && q.premium !== null);
|
|
183
|
+
if (!offer) throw new Error('No bindable offer yet');
|
|
184
|
+
|
|
185
|
+
const bind = await client.instantQuotes.bind(session.submissionId, offer.opportunityId);
|
|
186
|
+
console.log(bind.status, bind.next);
|
|
187
|
+
|
|
188
|
+
// After a broker approves the bind, a payment request appears
|
|
189
|
+
const due = (await client.payments.list()).filter((p) => p.payable);
|
|
190
|
+
if (due[0]) {
|
|
191
|
+
const { checkoutUrl } = await client.payments.checkout(due[0].id);
|
|
192
|
+
console.log('Pay here:', checkoutUrl); // Stripe checkout
|
|
193
|
+
}
|
|
223
194
|
```
|
|
224
195
|
|
|
225
|
-
|
|
196
|
+
A Delegance broker approves each bind request. You get an email when payment is ready. One live bind per coverage per submission: a repeat returns the existing request (`existing: true`).
|
|
197
|
+
|
|
198
|
+
`bindWithStepUp()` covers fast bind, where the owner attests the answers and enters a 6-digit code we email. Fast bind with the carrier's own checkout (tier A) is not open yet; until it is, every bind goes to a broker.
|
|
199
|
+
|
|
200
|
+
## Device login (existing customers)
|
|
201
|
+
|
|
202
|
+
A person who already has a portal account approves a new device in the browser. No API key is needed to start.
|
|
226
203
|
|
|
227
204
|
```typescript
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
205
|
+
import { createDeviceLogin, newDeviceSecret, DeleganceClient } from '@delegance/sdk';
|
|
206
|
+
|
|
207
|
+
const login = createDeviceLogin();
|
|
208
|
+
const device = newDeviceSecret();
|
|
209
|
+
const start = await login.start({ deviceSecretHash: device.hash, deviceName: 'build-server' });
|
|
210
|
+
console.log(`Open ${start.verificationUriComplete} and confirm code ${start.userCode}`);
|
|
211
|
+
|
|
212
|
+
const result = await login.waitForKey(start.loginId, device.secret);
|
|
213
|
+
if (result.status === 'ready') {
|
|
214
|
+
const client = new DeleganceClient({ apiKey: result.apiKey });
|
|
215
|
+
const info = await client.auth.keyInfo(); // scopes, company, expiry
|
|
216
|
+
if (info.refreshable) await client.auth.refresh(); // extend a CLI key
|
|
237
217
|
}
|
|
238
218
|
```
|
|
239
219
|
|
|
240
|
-
|
|
220
|
+
## API keys
|
|
241
221
|
|
|
242
|
-
|
|
243
|
-
const doc = await client.documents.get('document-uuid');
|
|
222
|
+
Create keys in the portal (Settings > API keys), with `delegance signup` / `delegance auth login`, or with `client.apiKeys.create()` from a key with the `admin` scope.
|
|
244
223
|
|
|
245
|
-
|
|
246
|
-
// 'pending' | 'processing' | 'completed' | 'processed' | 'error' | 'failed'
|
|
224
|
+
Key rules:
|
|
247
225
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
226
|
+
- A key belongs to one company.
|
|
227
|
+
- A new key expires in 90 days unless you pick another expiry.
|
|
228
|
+
- A key with `write`, `admin`, or `claims:write` must expire within 365 days. `expiresInDays: 'never'` is allowed only for a read-only key; otherwise the server answers 400 `write_key_requires_expiry`.
|
|
229
|
+
- `claims:write` can be created only while signed in to the portal (signup and device login keys for owners and admins carry it).
|
|
230
|
+
- Delegance staff accounts cannot create client keys (403).
|
|
231
|
+
- `appetite:read`, `mcp:read`, `mcp:orin`, and `claims:write` are opt-in. `read` and `write` never imply them.
|
|
232
|
+
- Keys from signup and device login refresh with `client.auth.refresh()`.
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
const created = await client.apiKeys.create({
|
|
236
|
+
name: 'CI uploader',
|
|
237
|
+
scopes: ['read', 'write'],
|
|
238
|
+
expiresInDays: 90,
|
|
239
|
+
});
|
|
240
|
+
console.log('Save this key now:', created.key);
|
|
251
241
|
```
|
|
252
242
|
|
|
253
|
-
|
|
243
|
+
Format: `dlg_xxxxxxxx_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`.
|
|
244
|
+
|
|
245
|
+
## Limits
|
|
246
|
+
|
|
247
|
+
| Limit | Error |
|
|
248
|
+
|-------|-------|
|
|
249
|
+
| Quote starts per key per day | 429 `quote_limit_reached` |
|
|
250
|
+
| Per-key daily AI budget (chat, quote sessions) | 429 `api_key_budget_exhausted` |
|
|
251
|
+
| Delegance-wide daily API AI budget | 429 `api_budget_exhausted`, `Retry-After: 3600` |
|
|
252
|
+
| Requests per minute | 429, see `client.usage.rateLimits()` |
|
|
253
|
+
|
|
254
|
+
The SDK does not retry a 429. Read `err.retryAfter` (seconds, from the body or the `Retry-After` header) and wait before you call again.
|
|
255
|
+
|
|
256
|
+
## Other modules
|
|
257
|
+
|
|
258
|
+
Every module hangs off the client. Each one has a docs page with examples.
|
|
259
|
+
|
|
260
|
+
| Module | What it does |
|
|
261
|
+
|--------|--------------|
|
|
262
|
+
| `instantQuotes` | Start, submit, status, broker handoff, bind |
|
|
263
|
+
| `payments` | Premium payment requests and checkout links |
|
|
264
|
+
| `bonds` | Surety bond quotes; you buy on the surety's page |
|
|
265
|
+
| `claims` | File and track claims (needs `claims:write`; accept the claims disclaimer once in the portal) |
|
|
266
|
+
| `policies` | Policies in force, expiring soon, cancellation requests |
|
|
267
|
+
| `coi` | Certificates of insurance |
|
|
268
|
+
| `documents` | Upload, extraction status, list |
|
|
269
|
+
| `sov` | Schedules of values |
|
|
270
|
+
| `chat` | Ask about your coverage |
|
|
271
|
+
| `knowledge` | Notecards and facts extracted from a document |
|
|
272
|
+
| `appetite` | Which carriers will write a risk (needs `appetite:read`) |
|
|
273
|
+
| `leads` | Send a prospect business to Delegance |
|
|
274
|
+
| `onboarding` | Account setup status and verification email |
|
|
275
|
+
| `feedback` | Report a bug, an idea, or a question |
|
|
276
|
+
| `usage` | Billing-period usage, daily usage, rate limits |
|
|
277
|
+
| `apiKeys` | Create, list, revoke keys |
|
|
278
|
+
| `auth` | Key info and refresh |
|
|
279
|
+
| `companies` | The key's own company |
|
|
280
|
+
| `quotes` | Legacy partner quote queue. Submission answers 501; use `instantQuotes` |
|
|
281
|
+
|
|
282
|
+
### Bonds
|
|
254
283
|
|
|
255
284
|
```typescript
|
|
256
|
-
|
|
257
|
-
|
|
285
|
+
const start = await client.bonds.start({ state: 'TX', bondName: 'notary' });
|
|
286
|
+
```
|
|
258
287
|
|
|
259
|
-
|
|
260
|
-
const policies = await client.documents.list({
|
|
261
|
-
documentType: 'policy',
|
|
262
|
-
status: 'completed',
|
|
263
|
-
limit: 50,
|
|
264
|
-
offset: 0
|
|
265
|
-
});
|
|
288
|
+
### Claims
|
|
266
289
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
// ...
|
|
271
|
-
}
|
|
290
|
+
```typescript
|
|
291
|
+
const claim = await client.claims.file({ description: 'Water damage in the kitchen', incidentDate: '2026-10-01' });
|
|
292
|
+
console.log(claim.claimId, claim.status, claim.portalUrl);
|
|
272
293
|
```
|
|
273
294
|
|
|
274
|
-
|
|
295
|
+
A 403 with `reason: 'gate_not_acknowledged'` means the claims disclaimer is not accepted yet. The owner accepts it once in the portal (`err.body.portalUrl`).
|
|
296
|
+
|
|
297
|
+
### Feedback
|
|
275
298
|
|
|
276
299
|
```typescript
|
|
277
|
-
const
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
300
|
+
const { id } = await client.feedback.submit({
|
|
301
|
+
type: 'bug',
|
|
302
|
+
message: 'quote submit hung on the delivery question',
|
|
303
|
+
context: { command: 'quote submit', exitCode: 1, traceId: 'trace-from-the-error' },
|
|
281
304
|
});
|
|
282
|
-
|
|
283
|
-
if (result.status === 'completed') {
|
|
284
|
-
console.log('Policies found:', result.extraction?.policies.length);
|
|
285
|
-
} else if (result.status === 'error') {
|
|
286
|
-
console.error('Processing failed:', result.error?.message);
|
|
287
|
-
}
|
|
288
305
|
```
|
|
289
306
|
|
|
290
307
|
### Appetite
|
|
291
308
|
|
|
292
|
-
|
|
309
|
+
Needs a key with the `appetite:read` scope. A warm cache hit returns the result at once; a cold match returns a job to poll.
|
|
293
310
|
|
|
294
311
|
```typescript
|
|
295
312
|
const start = await client.appetite.match({
|
|
@@ -297,19 +314,12 @@ const start = await client.appetite.match({
|
|
|
297
314
|
industry: 'commercial bakery',
|
|
298
315
|
coverageTypes: ['general_liability', 'workers_comp'],
|
|
299
316
|
});
|
|
300
|
-
|
|
301
|
-
const result = start.status === 'succeeded'
|
|
302
|
-
? start
|
|
303
|
-
: await client.appetite.waitForMatch(start.jobId);
|
|
304
|
-
|
|
305
|
-
for (const c of result.carrierResults) {
|
|
306
|
-
console.log(c.carrier, c.overallStatus, c.productsAvailable);
|
|
307
|
-
}
|
|
317
|
+
const result = start.status === 'succeeded' ? start : await client.appetite.waitForMatch(start.jobId);
|
|
308
318
|
```
|
|
309
319
|
|
|
310
320
|
### Leads
|
|
311
321
|
|
|
312
|
-
|
|
322
|
+
Idempotent on `externalId`. A contact email that already belongs to a company returns that company.
|
|
313
323
|
|
|
314
324
|
```typescript
|
|
315
325
|
const { companyId } = await client.leads.create({
|
|
@@ -320,77 +330,63 @@ const { companyId } = await client.leads.create({
|
|
|
320
330
|
});
|
|
321
331
|
```
|
|
322
332
|
|
|
323
|
-
##
|
|
333
|
+
## Use it from an AI agent
|
|
324
334
|
|
|
325
|
-
|
|
335
|
+
Claude Code, Codex, Gemini CLI, and other coding agents can drive the SDK or the CLI. The CLI is often simpler for an agent: `npx -y @delegance/cli quote start --json` prints the questions as JSON, and `--answers answers.json` files them. See the CLI README section "Use it from an AI agent" and https://portal.delegancebrokerage.com/docs/cli.
|
|
326
336
|
|
|
327
|
-
|
|
328
|
-
import {
|
|
329
|
-
AuthenticationError,
|
|
330
|
-
ForbiddenError,
|
|
331
|
-
ValidationError,
|
|
332
|
-
NotFoundError,
|
|
333
|
-
NotImplementedError,
|
|
334
|
-
RateLimitError,
|
|
335
|
-
DeleganceError
|
|
336
|
-
} from '@delegance/sdk';
|
|
337
|
+
Rules that keep an agent safe:
|
|
337
338
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
} else if (error instanceof ForbiddenError) {
|
|
344
|
-
console.error('Key lacks the scope for this call');
|
|
345
|
-
} else if (error instanceof NotFoundError) {
|
|
346
|
-
console.error('Document not found');
|
|
347
|
-
} else if (error instanceof NotImplementedError) {
|
|
348
|
-
console.error('Not available over the API yet:', error.message);
|
|
349
|
-
} else if (error instanceof ValidationError) {
|
|
350
|
-
console.error('Invalid input:', error.details);
|
|
351
|
-
} else if (error instanceof RateLimitError) {
|
|
352
|
-
console.error('Rate limited, retry after:', error.retryAfter);
|
|
353
|
-
} else if (error instanceof DeleganceError) {
|
|
354
|
-
console.error('API error:', error.message, 'Status:', error.statusCode);
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
```
|
|
339
|
+
- Read the key from `DELEGANCE_API_KEY`. Never paste it into a prompt or a file the agent commits.
|
|
340
|
+
- Pass your own `idempotencyKey` to `submit()`, `bind()`, and `brokerHandoff()` when the agent may retry across restarts. The same key lands on the same request.
|
|
341
|
+
- Gate on `err.reason` and `err.code`, never on the message text.
|
|
342
|
+
|
|
343
|
+
## Configuration
|
|
358
344
|
|
|
359
|
-
|
|
345
|
+
```typescript
|
|
346
|
+
const client = new DeleganceClient({
|
|
347
|
+
apiKey: 'dlg_xxxxxxxx_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', // required
|
|
348
|
+
baseUrl: 'https://portal.delegancebrokerage.com', // default
|
|
349
|
+
timeout: 30000, // ms, default 30000
|
|
350
|
+
retries: 3, // default 3
|
|
351
|
+
headers: { 'X-Custom-Header': 'value' },
|
|
352
|
+
});
|
|
353
|
+
```
|
|
360
354
|
|
|
361
|
-
|
|
355
|
+
`createClientFromEnv()` reads `DELEGANCE_API_KEY` and, if set, `DELEGANCE_BASE_URL`.
|
|
362
356
|
|
|
363
|
-
|
|
357
|
+
## Errors
|
|
364
358
|
|
|
365
359
|
```typescript
|
|
366
|
-
import
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
360
|
+
import {
|
|
361
|
+
DeleganceError,
|
|
362
|
+
AuthenticationError, // 401
|
|
363
|
+
ValidationError, // 400
|
|
364
|
+
ForbiddenError, // 403
|
|
365
|
+
NotFoundError, // 404
|
|
366
|
+
RateLimitError, // 429
|
|
367
|
+
NotImplementedError, // 501
|
|
373
368
|
} from '@delegance/sdk';
|
|
374
369
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
370
|
+
try {
|
|
371
|
+
await client.documents.list({ companyId: 'another-company' });
|
|
372
|
+
} catch (err) {
|
|
373
|
+
if (err instanceof DeleganceError) {
|
|
374
|
+
console.error(err.statusCode, err.reason, err.code, err.message, err.traceId);
|
|
375
|
+
}
|
|
381
376
|
}
|
|
382
377
|
```
|
|
383
378
|
|
|
384
|
-
|
|
379
|
+
Every error carries:
|
|
385
380
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
381
|
+
- `statusCode`: the HTTP status.
|
|
382
|
+
- `reason`: the machine-readable reason from the body, when sent (`not_available`, `quote_limit_reached`, `active_request_exists`, `attestation_required`, ...).
|
|
383
|
+
- `code`: the body's `code`, when sent (`company_mismatch`). New in 0.2.1; on 0.2.0 read `err.body.code`.
|
|
384
|
+
- `body`: the parsed error body, for fields such as `portalUrl`.
|
|
385
|
+
- `traceId`: quote it to support.
|
|
390
386
|
|
|
391
|
-
|
|
387
|
+
Retries: the SDK retries network failures and 5xx answers other than 501, with backoff. It never retries a 4xx (including 429), a 501, or a 503 with `reason: 'not_available'`.
|
|
392
388
|
|
|
393
389
|
## Support
|
|
394
390
|
|
|
395
|
-
-
|
|
391
|
+
- Docs: https://portal.delegancebrokerage.com/docs/sdk
|
|
396
392
|
- Email: support@delegancebrokerage.com
|