@curviate/sdk 0.11.0 → 0.13.0

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/dist/index.js CHANGED
@@ -76,7 +76,9 @@ var KNOWN_CODES = /* @__PURE__ */ new Set([
76
76
  "PAYLOAD_TOO_LARGE",
77
77
  "ACCOUNT_NOT_FOUND",
78
78
  "ACCOUNT_RESTRICTED",
79
+ "ACCOUNT_ALREADY_LINKED",
79
80
  "RESOURCE_NOT_FOUND",
81
+ "RESOURCE_ACCESS_RESTRICTED",
80
82
  "TIER_NOT_ACTIVE",
81
83
  "LINKEDIN_FEATURE_NOT_SUBSCRIBED",
82
84
  "RATE_LIMIT_ACCOUNT",
@@ -331,7 +333,20 @@ var AccountsResource = class {
331
333
  * Connect a LinkedIn account to an empty seat.
332
334
  *
333
335
  * Returns an account (201) or a checkpoint challenge (202) when LinkedIn
334
- * requires verification. Callers discriminate on `result.object`.
336
+ * requires verification. Callers discriminate on `result.object`; resolve a
337
+ * 202 with {@link solveCheckpoint} (code) or {@link pollCheckpoint}
338
+ * (mobile-app approval).
339
+ *
340
+ * For `auth_method: "cookie"`, `user_agent` is **required** — connecting by
341
+ * session cookie without one is rejected with `INVALID_REQUEST`. It stays
342
+ * optional for `auth_method: "credentials"`.
343
+ *
344
+ * On a 201 account, `recovered` is `true` only when the connect reclaimed a
345
+ * LinkedIn identity already present on the workspace (claiming it into your
346
+ * account) rather than connecting a brand-new one — it is absent on a normal
347
+ * connect. Its `status` reflects the account's real observed state: as well as
348
+ * `active` it may be `reconnect_needed`, `restricted`, or `disconnected` (a
349
+ * recovered identity often needs a reconnect).
335
350
  */
336
351
  link(body) {
337
352
  return this.ctx.request({
@@ -341,45 +356,75 @@ var AccountsResource = class {
341
356
  });
342
357
  }
343
358
  /**
344
- * Submit an OTP or 2FA code to resolve a checkpoint challenge.
359
+ * Solve a checkpoint challenge by submitting an OTP or 2FA code.
360
+ *
361
+ * The account is addressed by `accountId` (the provisional `account_id`
362
+ * returned on the 202 `checkpoint_required` response); the body carries the
363
+ * `code`. Returns the connected account (201) or, when LinkedIn chains a
364
+ * second challenge, another checkpoint (202) — resolve that one with a
365
+ * further `solveCheckpoint` call for the same `accountId`.
366
+ *
367
+ * On the 201 account, `recovered` is `true` only when solving the challenge
368
+ * reclaimed a LinkedIn identity already present on the workspace (rather than
369
+ * connecting a brand-new one); it is absent otherwise. Its `status` reflects
370
+ * the account's real observed state — as well as `active` it may be
371
+ * `reconnect_needed`, `restricted`, or `disconnected`.
372
+ *
373
+ * @param accountId - the provisional `account_id` from the 202 response.
374
+ * @param body - the verification `code`.
345
375
  */
346
- submitCheckpoint(body) {
376
+ solveCheckpoint(accountId, body) {
347
377
  return this.ctx.request({
348
378
  method: "POST",
349
- path: "/v1/accounts/checkpoints/submit",
379
+ path: `/v1/accounts/${accountId}/checkpoint/solve`,
350
380
  body
351
381
  });
352
382
  }
353
383
  /**
354
- * Poll for mobile-app approval of a pending checkpoint challenge.
384
+ * Re-request the pending verification challenge notification for an account.
385
+ *
386
+ * Useful when the end user says they never received the code or push
387
+ * notification for a pending checkpoint. `resent` echoes the outcome
388
+ * honestly: `true` once the notification was actually re-sent, `false` when
389
+ * there was nothing to re-send for that challenge type (this call never
390
+ * throws just because a re-send wasn't applicable). Does not reset the
391
+ * checkpoint's expiry.
392
+ *
393
+ * @param accountId - the provisional `account_id` from the 202 response.
355
394
  */
356
- pollCheckpoint(body) {
395
+ requestCheckpoint(accountId) {
357
396
  return this.ctx.request({
358
397
  method: "POST",
359
- path: "/v1/accounts/checkpoints/poll",
360
- body
398
+ path: `/v1/accounts/${accountId}/checkpoint/request`
361
399
  });
362
400
  }
363
401
  /**
364
- * Re-send the pending verification challenge notification for an account.
402
+ * Poll for mobile-app approval of a pending checkpoint challenge.
365
403
  *
366
- * Useful when the end user says they never received the code or push
367
- * notification for a pending checkpoint. `resent` echoes the result
368
- * honestly: `true` once the notification was actually re-sent, `false`
369
- * when there was nothing to re-send for that challenge type (this call
370
- * never throws just because a resend wasn't applicable). Does not reset
371
- * the checkpoint's expiry.
404
+ * The account is addressed by `accountId` (the provisional `account_id`
405
+ * from the 202 response). `status` is `pending` until the end user approves
406
+ * on their device, then `active` (the account is connected), or
407
+ * `expired` / `failed`. Poll until it leaves `pending`.
408
+ *
409
+ * On `status: "expired"` (the approval timed out), the response carries
410
+ * `challenge_type` (`"mobile_app_approval"`) and a human-readable
411
+ * `recovery_hint` — the actionable next step — so a client can render the
412
+ * right recovery guidance without parsing prose.
413
+ *
414
+ * @param accountId - the provisional `account_id` from the 202 response.
372
415
  */
373
- resendCheckpoint(body) {
416
+ pollCheckpoint(accountId) {
374
417
  return this.ctx.request({
375
418
  method: "POST",
376
- path: "/v1/accounts/checkpoints/resend",
377
- body
419
+ path: `/v1/accounts/${accountId}/checkpoint/poll`
378
420
  });
379
421
  }
380
422
  /**
381
- * Generate a one-time hosted connection link the end user opens to authorize a
382
- * LinkedIn connection without credentials transiting the API or LLM context.
423
+ * Generate a one-time hosted connection link the end user opens to authorize
424
+ * a new LinkedIn connection without credentials transiting the API or LLM
425
+ * context. Poll completion with {@link getConnectSession} using the returned
426
+ * `session_id`. To re-authorize an existing account, use
427
+ * {@link createReconnectLink} instead.
383
428
  */
384
429
  createConnectLink(body) {
385
430
  return this.ctx.request({
@@ -389,8 +434,25 @@ var AccountsResource = class {
389
434
  });
390
435
  }
391
436
  /**
392
- * Poll a hosted connect session minted by {@link createConnectLink} (its
393
- * `session_id`).
437
+ * Generate a one-time hosted **re-authorization** link for an existing
438
+ * account that became disconnected — the hosted counterpart of
439
+ * {@link reconnect}. The end user opens the returned `url`; poll completion
440
+ * with {@link getConnectSession} using the returned `session_id`. The account
441
+ * keeps its `account_id` and seat.
442
+ *
443
+ * @param accountId - the account to re-authorize.
444
+ * @param body - optional `expires_in_seconds` and `redirect_url`.
445
+ */
446
+ createReconnectLink(accountId, body) {
447
+ return this.ctx.request({
448
+ method: "POST",
449
+ path: `/v1/accounts/${accountId}/reconnect-link`,
450
+ ...body !== void 0 ? { body } : {}
451
+ });
452
+ }
453
+ /**
454
+ * Poll a hosted connect session minted by {@link createConnectLink} or
455
+ * {@link createReconnectLink} (its `session_id`).
394
456
  *
395
457
  * A pure status read — it makes no external call and does not itself complete
396
458
  * the connection. `status` is `pending` until the end user finishes the
@@ -412,10 +474,11 @@ var AccountsResource = class {
412
474
  * seat this account occupies, `null` for an admin seatless account).
413
475
  *
414
476
  * This is a stale-while-revalidate read — it always returns immediately
415
- * from the cached row (never blocks on a live substrate call), and the
416
- * six cached enrichment fields (`username`, `premium_id`,
417
- * `public_identifier`, `substrate_created_at`, `signatures`, `groups`) are
418
- * `null`/`[]` until the account's first enrichment pass completes.
477
+ * from the cached row (never blocks on a live substrate call). The cached
478
+ * enrichment fields `full_name` and `substrate_created_at` are populated by
479
+ * a background enrichment pass; `username`, `premium_id`,
480
+ * `public_identifier`, `signatures`, and `groups` are not sourced on the
481
+ * current connection surface and read `null`/`[]`.
419
482
  */
420
483
  get(accountId) {
421
484
  return this.ctx.request({
@@ -424,7 +487,13 @@ var AccountsResource = class {
424
487
  });
425
488
  }
426
489
  /**
427
- * Re-authorize a disconnected account in place (same account_id, same seat).
490
+ * Re-authorize a disconnected account in place (same `account_id`, same
491
+ * seat). Returns the reconnected account (200) or a checkpoint challenge
492
+ * (202) when LinkedIn requires verification — resolve a 202 with
493
+ * {@link solveCheckpoint} / {@link pollCheckpoint}, exactly like {@link link}.
494
+ *
495
+ * For `auth_method: "cookie"`, `user_agent` is **required** (as on
496
+ * {@link link}). For the hosted re-auth flow, use {@link createReconnectLink}.
428
497
  */
429
498
  reconnect(accountId, body) {
430
499
  return this.ctx.request({
@@ -434,16 +503,13 @@ var AccountsResource = class {
434
503
  });
435
504
  }
436
505
  /**
437
- * Refresh frozen account sources (re-sync conversations, connection lists, etc.).
438
- */
439
- refresh(accountId) {
440
- return this.ctx.request({
441
- method: "POST",
442
- path: `/v1/accounts/${accountId}/refresh`
443
- });
444
- }
445
- /**
446
- * Update managed-proxy configuration for an account.
506
+ * Update an account's configuration.
507
+ *
508
+ * `metadata` is a flat string→string map that **replaces** the account's
509
+ * custom-data store wholesale (keys not provided are removed). `proxy` sets a
510
+ * custom egress proxy, or clears it (reverting to automatic proxy protection)
511
+ * when passed as `null`. The `proxy.password`, if given, is stored securely
512
+ * and never returned.
447
513
  */
448
514
  update(accountId, body) {
449
515
  return this.ctx.request({
@@ -701,13 +767,6 @@ var ProfilesResource = class {
701
767
  ...params ? { query: params } : {}
702
768
  });
703
769
  }
704
- /** Get a company profile. `GET /v1/profiles/companies/{company_id}` */
705
- getCompany(companyId) {
706
- return this.ctx.request({
707
- method: "GET",
708
- path: `/v1/profiles/companies/${companyId}`
709
- });
710
- }
711
770
  /** Endorse a skill on a profile. `POST /v1/profiles/{profile_id}/endorse` */
712
771
  endorse(profileId, body) {
713
772
  return this.ctx.request({
@@ -1055,12 +1114,20 @@ var SalesNavigatorResource = class {
1055
1114
  });
1056
1115
  }
1057
1116
  /**
1058
- * Save a Sales Navigator member as a lead. `POST /v1/sales-navigator/leads/{user_id}`
1117
+ * Save a Sales Navigator member into a lead list.
1118
+ * `POST /v1/sales-navigator/lead-lists/{list_id}/save`
1119
+ *
1120
+ * **BREAKING (2026-07-04):** replaces the retired v1
1121
+ * `saveLead(userId, { account_id, list_id? })` — there is no alias. The
1122
+ * list is now mandatory and addresses the path; the member id travels in
1123
+ * the body alongside `account_id` (the save endpoints carry no query
1124
+ * params, so `account_id` has nowhere else to go).
1059
1125
  */
1060
- saveLead(userId, body) {
1126
+ saveLead(input) {
1127
+ const { list_id, ...body } = input;
1061
1128
  return this.ctx.request({
1062
1129
  method: "POST",
1063
- path: `/v1/sales-navigator/leads/${userId}`,
1130
+ path: `/v1/sales-navigator/lead-lists/${list_id}/save`,
1064
1131
  body,
1065
1132
  accountIdIn: "body"
1066
1133
  });
@@ -1076,6 +1143,71 @@ var SalesNavigatorResource = class {
1076
1143
  query: params
1077
1144
  });
1078
1145
  }
1146
+ // ─── v2 list surface ──────────────────────────────────────────────────────
1147
+ /**
1148
+ * List the saved-account (company) lists on the operator's Sales Navigator seat.
1149
+ * `GET /v1/sales-navigator/account-lists`
1150
+ */
1151
+ accountLists(query) {
1152
+ return this.ctx.request({
1153
+ method: "GET",
1154
+ path: "/v1/sales-navigator/account-lists",
1155
+ ...query ? { query } : {}
1156
+ });
1157
+ }
1158
+ /**
1159
+ * List the saved-lead (member) lists on the operator's Sales Navigator seat.
1160
+ * `GET /v1/sales-navigator/lead-lists`
1161
+ */
1162
+ leadLists(query) {
1163
+ return this.ctx.request({
1164
+ method: "GET",
1165
+ path: "/v1/sales-navigator/lead-lists",
1166
+ ...query ? { query } : {}
1167
+ });
1168
+ }
1169
+ /**
1170
+ * Browse the saved accounts (companies) in one account list. Pass optional
1171
+ * `persona` / `filter` / `sort_by` / `sort_order` filters in the body.
1172
+ * `POST /v1/sales-navigator/account-lists/{list_id}`
1173
+ */
1174
+ browseAccountList(listId, body, query) {
1175
+ return this.ctx.request({
1176
+ method: "POST",
1177
+ path: `/v1/sales-navigator/account-lists/${listId}`,
1178
+ body: body ?? {},
1179
+ ...query ? { query } : {}
1180
+ });
1181
+ }
1182
+ /**
1183
+ * Browse the saved leads (members) in one lead list. Pass optional
1184
+ * `spotlight` / `sort_by` / `sort_order` filters in the body.
1185
+ * `POST /v1/sales-navigator/lead-lists/{list_id}`
1186
+ */
1187
+ browseLeadList(listId, body, query) {
1188
+ return this.ctx.request({
1189
+ method: "POST",
1190
+ path: `/v1/sales-navigator/lead-lists/${listId}`,
1191
+ body: body ?? {},
1192
+ ...query ? { query } : {}
1193
+ });
1194
+ }
1195
+ /**
1196
+ * Save a LinkedIn company into an account list.
1197
+ * `POST /v1/sales-navigator/account-lists/{list_id}/save`
1198
+ *
1199
+ * No `saved` boolean is invented — a `2xx` response body is the success
1200
+ * signal (the substrate returns no success flag).
1201
+ */
1202
+ saveAccount(input) {
1203
+ const { list_id, ...body } = input;
1204
+ return this.ctx.request({
1205
+ method: "POST",
1206
+ path: `/v1/sales-navigator/account-lists/${list_id}/save`,
1207
+ body,
1208
+ accountIdIn: "body"
1209
+ });
1210
+ }
1079
1211
  };
1080
1212
 
1081
1213
  // src/internal/job-id.ts
@@ -1386,6 +1518,88 @@ var JobsResource = class {
1386
1518
  }
1387
1519
  };
1388
1520
 
1521
+ // src/resources/companies.ts
1522
+ var CompaniesResource = class {
1523
+ constructor(ctx) {
1524
+ this.ctx = ctx;
1525
+ }
1526
+ /**
1527
+ * Retrieve a company's full LinkedIn profile.
1528
+ * `GET /v1/companies/{identifier}`
1529
+ *
1530
+ * Accepts a public handle (the slug in `linkedin.com/company/<handle>`,
1531
+ * e.g. `t-systems`) or a numeric id (e.g. `1234567`). A URN is not accepted.
1532
+ * The `account_id` is injected by the account-scoped context.
1533
+ */
1534
+ get(identifier) {
1535
+ return this.ctx.request({
1536
+ method: "GET",
1537
+ path: `/v1/companies/${identifier}`
1538
+ });
1539
+ }
1540
+ /**
1541
+ * List people who currently work at the company.
1542
+ * `GET /v1/companies/{identifier}/employees`
1543
+ *
1544
+ * A facade over people search with the company filter applied — filter
1545
+ * further with `keywords` or `location`. `identifier` must be the
1546
+ * company's numeric provider_id (the same `id` field `get()` returns) —
1547
+ * a handle or URN is rejected before any upstream call.
1548
+ */
1549
+ employees(identifier, params) {
1550
+ return this.ctx.request({
1551
+ method: "GET",
1552
+ path: `/v1/companies/${identifier}/employees`,
1553
+ ...params ? { query: params } : {}
1554
+ });
1555
+ }
1556
+ /**
1557
+ * List the company's posts.
1558
+ * `GET /v1/companies/{identifier}/posts`
1559
+ *
1560
+ * A facade over post search with the company filter applied. `identifier`
1561
+ * must be the company's numeric provider_id.
1562
+ */
1563
+ posts(identifier, params) {
1564
+ return this.ctx.request({
1565
+ method: "GET",
1566
+ path: `/v1/companies/${identifier}/posts`,
1567
+ ...params ? { query: params } : {}
1568
+ });
1569
+ }
1570
+ /**
1571
+ * List the company's open job postings.
1572
+ * `GET /v1/companies/{identifier}/jobs`
1573
+ *
1574
+ * A facade over job search with the company filter applied — filter
1575
+ * further with `keywords`. An empty `items[]` is a valid result (the
1576
+ * company currently has no open postings). `identifier` must be the
1577
+ * company's numeric provider_id.
1578
+ */
1579
+ jobs(identifier, params) {
1580
+ return this.ctx.request({
1581
+ method: "GET",
1582
+ path: `/v1/companies/${identifier}/jobs`,
1583
+ ...params ? { query: params } : {}
1584
+ });
1585
+ }
1586
+ /**
1587
+ * List the company's followers.
1588
+ * `GET /v1/companies/{identifier}/followers`
1589
+ *
1590
+ * Native — reuses the same seam that backs `profiles.listFollowers()`.
1591
+ * You must be an administrator of the target company page.
1592
+ * `identifier` must be the company's numeric provider_id.
1593
+ */
1594
+ followers(identifier, params) {
1595
+ return this.ctx.request({
1596
+ method: "GET",
1597
+ path: `/v1/companies/${identifier}/followers`,
1598
+ ...params ? { query: params } : {}
1599
+ });
1600
+ }
1601
+ };
1602
+
1389
1603
  // src/resources/webhooks.ts
1390
1604
  var WebhooksResource = class {
1391
1605
  constructor(ctx) {
@@ -1472,6 +1686,7 @@ function buildNamespaces(ctx) {
1472
1686
  salesNavigator: new SalesNavigatorResource(ctx),
1473
1687
  recruiter: new RecruiterResource(ctx),
1474
1688
  jobs: new JobsResource(ctx),
1689
+ companies: new CompaniesResource(ctx),
1475
1690
  webhooks: new WebhooksResource(ctx)
1476
1691
  };
1477
1692
  }
@@ -1496,6 +1711,7 @@ var Curviate = class {
1496
1711
  this.salesNavigator = ns.salesNavigator;
1497
1712
  this.recruiter = ns.recruiter;
1498
1713
  this.jobs = ns.jobs;
1714
+ this.companies = ns.companies;
1499
1715
  this.webhooks = ns.webhooks;
1500
1716
  }
1501
1717
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@curviate/sdk",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
4
  "private": false,
5
5
  "description": "TypeScript SDK for the Curviate API.",
6
6
  "license": "MIT",