@curviate/sdk 0.36.0 → 0.37.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/CHANGELOG.md CHANGED
@@ -9,6 +9,108 @@ Versioning: semantic. Minor for additive changes, patch for bug fixes; no stabil
9
9
 
10
10
  ## [Unreleased]
11
11
 
12
+ ## [0.37.1] - 2026-09-23
13
+
14
+ Fixture and types regenerated against the deployed production document
15
+ (`https://api.curviate.com`, 127 paths, server
16
+ `0b33680536a45681ed5ffe420006cb05c85fe683`). Description changes only; no type
17
+ shape changed.
18
+
19
+ ### Changed
20
+
21
+ - **Generated type descriptions follow the served document.** `is_sender` on
22
+ chat messages now documents that it is omitted when the connected account
23
+ cannot yet be identified (treat a missing value as unknown, not as received).
24
+ Recruiter search and project filters, and the job read's `sections`
25
+ parameter, are documented as trimmed before use rather than forwarded
26
+ verbatim.
27
+
28
+ ### Fixed
29
+
30
+ - **The retry decision now honours `retry_hint.kind: "never"`.** A retryable
31
+ code (`INTERNAL`, `PLATFORM_ERROR`, `PLATFORM_RATE_LIMIT`,
32
+ `RATE_LIMIT_ACCOUNT`, `RATE_LIMIT_TENANT`) whose envelope carries
33
+ `retry_hint: { kind: "never" }`, an explicit server instruction that this
34
+ exact refusal will not change on a retry (for example, an upstream response
35
+ in a shape this API cannot read), is no longer retried on GETs. Previously
36
+ the retry gate consulted only the code table, so a structural-drift 502
37
+ (`PLATFORM_ERROR` with `retry_likely_to_succeed: false` and
38
+ `retry_hint.kind: "never"`) was retried up to three times against an answer
39
+ that could not change.
40
+
41
+ `retry_likely_to_succeed` is still not consulted by the retry decision. The
42
+ server currently defaults it to `false` on several generic
43
+ "unresolved error" paths that are not a per-cause verdict, and honouring it
44
+ as written would have silently stopped retrying most undecoded server
45
+ errors. Filed back rather than shipped; unaffected callers see no
46
+ behaviour change.
47
+
48
+ - **An empty but present `Retry-After` header no longer reads as "retry in
49
+ 0ms".** `Number("")` is `0`, which is finite and non-negative, so it passed
50
+ the same check a real delay does; it now falls back to the same
51
+ conservative 30s the unparseable HTTP-date form already gets. Found in
52
+ passing while touching this file for the fix above; unrelated to it.
53
+
54
+ ## [0.37.0] - 2026-09-22
55
+
56
+ Fixture and types regenerated against the deployed production document
57
+ (`https://api.curviate.com`, 127 paths, server
58
+ `9d5eb6583e24928eca0c3c8b162ad664e869af99`).
59
+ **BREAKING**: the webhook read summaries no longer carry `headers[].value_prefix`;
60
+ a keyed `headers[].value_fingerprint` takes its place. Pre-1.0 a breaking change
61
+ ships as a minor (as `0.27.0` did), so a caret range on `0.36.x` will not pick
62
+ this up.
63
+
64
+ ### BREAKING
65
+
66
+ - **`headers[].value_prefix` is removed from every webhook read; `headers[].value_fingerprint` replaces it.**
67
+ The old field was a masked preview of the configured value: the first 8
68
+ characters plus `...` for values of 24 characters or more, a fixed `********`
69
+ below that. It disclosed a leading slice of a credential and leaked the
70
+ value's length class. The replacement is an 8-character keyed fingerprint that
71
+ carries no part of the value and no indication of its length.
72
+
73
+ It is deterministic **within an account**, which is what makes it useful: two
74
+ headers with the same fingerprint hold the same value, and a changed
75
+ fingerprint means a rotation took effect. Fingerprints are not comparable
76
+ across accounts. It is `string | null`, `null` for a header configured before
77
+ fingerprints existed, so the member is nullable where `value_prefix` was not.
78
+
79
+ Affects `webhooks.create` (201), `webhooks.list` (200), `webhooks.get` (200)
80
+ and `webhooks.update` (200).
81
+
82
+ ```diff
83
+ - const configured = webhook.headers?.[0]?.value_prefix; // masked preview, gone
84
+ + const configured = webhook.headers?.[0]?.value_fingerprint; // 8-char keyed fingerprint, nullable
85
+ ```
86
+
87
+ Any code that read `value_prefix` stops compiling, which is the intended
88
+ outcome: a masked preview and a fingerprint are not interchangeable, and a
89
+ silent rename would have left comparisons across accounts looking correct
90
+ while meaning nothing.
91
+
92
+ ### Changed
93
+
94
+ - Every `cursor` query parameter in the document now declares `minLength: 1`:
95
+ all 61 of them, the last 4 landing in this release (`GET /profile/visitors`,
96
+ `GET /posts/{post_id}/comments`, `GET /posts/{post_id}/reactions`,
97
+ `GET /saved-posts`). An empty-string cursor is a `400` rather than a silently
98
+ ignored parameter. No TypeScript type changes: `minLength` is a validation
99
+ constraint, not a shape, so this reaches callers as server behaviour and as a
100
+ documented constraint in the generated reference.
101
+ - Regenerated descriptions for `limit_profile`, `limit_profile_source` and
102
+ `limit_profile_detected_at` on the account and safety-policy surfaces. An
103
+ operator-set `limit_profile` is now a **pin**: it is no longer released by the
104
+ account's next connect, and neither a connect, a reconnect nor an account read
105
+ moves it or advances `limit_profile_detected_at`. Releasing it means sending
106
+ `limit_profile_source: "default"` **on its own**: changing `limit_profile`
107
+ and releasing the pin in the same request is refused with `INVALID_REQUEST`.
108
+ Description-only in this package; the behaviour is the deployed server's.
109
+
110
+ ### Fixed
111
+
112
+ - `search.getParameters` JSDoc example follows the convention of every other example (no code fence, a fully qualified `curviate.account(...)` call), so generated reference pages render it as one runnable snippet. Documentation only.
113
+
12
114
  ## [0.36.0] - 2026-09-20
13
115
 
14
116
  Fixture and types regenerated against the deployed production document
package/dist/index.d.ts CHANGED
@@ -2709,7 +2709,7 @@ interface paths {
2709
2709
  head?: never;
2710
2710
  /**
2711
2711
  * Update an account's safety policy
2712
- * @description The account-level safety-policy write (tenant-wide defaults are set on `PATCH /v1/safety-policy`). Send only the fields you are changing: everything you omit is left byte-identical, and sending `null` for a field clears your override and restores the tenant default where one is set, the Curviate default otherwise. Any limit may be set to any value: Curviate does not clamp, cap or refuse a change on the grounds that the number is unsafe. A value above the Curviate default is reported back in the response, and on every later read, with the default and its source class attached; there is no way to acknowledge it away, and setting the value back to the default removes it. A value that is not a value, such as a negative ceiling or an unknown row name, is a 400. Every field whose value CHANGES is appended to the account's action ledger with the previous value, the new value, the Curviate default, the actor and the time; a field you send whose value already equals its current effective value is not ledgered and is not stored as an override, so reading the policy and sending the document back changes nothing. Six fields on the read are derived rather than configured: `effective_ceiling`, `interface_ceiling`, `effective_interface_ceiling`, `posture_source`, `over_default` and each row's `warm_up_state`. Send them and they are accepted and ignored, never stored and never ledgered, so the document you read can go straight back. To pin a row's ramp, set `warm_up_factor`. `activity_window` is not accepted: send its settable subfields instead, the top-level `timezone` for the zone, and per row `activity_window_start`, `activity_window_end`, `activity_window_timezone` and `activity_window_applies_to`. The 400 this produces names those subfields, not just the refused object. And read `changes nothing` as `changes no limit`: the `posture` fields are OVERRIDES at every scope, so writing back a posture a scope merely inherits PINS it there and appends one ledger entry per pinned scope. That is what stops a later account- or tenant-wide change from moving it. A pin already in place is a no-op. An agent-authenticated write is accepted on exactly the same footing as an operator's. There is no bulk import, file upload or policy template: configuring many rows or many accounts is a loop over this operation. One field is not account-scoped: `tenant_default_posture` sets the default for EVERY account in the tenant, not just the one in the path, which is what makes it a one-call change for a whole workspace of personas. It is reported back at the top of every policy response, so a change to it is visible even on an account that overrides it. One other field is not row-scoped: `limit_profile` selects which of the four Curviate default sets this account's rows resolve from, so it moves the default under every row at once while leaving every value you have configured explicitly exactly as you set it. It is the platform product active on the account, not your Curviate seat entitlement, and the two can disagree: a lapsed subscription leaves the seat untouched. Curviate detects it when the account connects and re-detects it on every reconnect; setting it here is an operator override of that result, and it holds until the next connect. One field on this operation does not configure anything: `clear_halts` lifts the platform pause on the action types you name. When the platform refuses a call on an account, Curviate pauses that action type for the platform's own retry-after or a seeded cooldown, and every later call on it is refused locally without reaching the platform; the account resource reports the live pauses as `quotas[].halt`. Naming an action type here lifts its pause immediately, so the next call goes out. An action type with no active pause is accepted and does nothing, which makes it safe to send for a set you have not checked, and only the ones actually lifted are ledgered, each with the expiry it cut short, the actor and the time, readable afterwards on `GET /v1/{account_id}/safety-events` with `reason: "halt_cleared"`. Clearing disarms nothing: if the platform refuses the account again the pause returns, and a 429 or a refused write returns it for the full cooldown. Clear one when you have reason to believe the refusal was a transient upstream fault rather than the platform pushing back on this account.
2712
+ * @description The account-level safety-policy write (tenant-wide defaults are set on `PATCH /v1/safety-policy`). Send only the fields you are changing: everything you omit is left byte-identical, and sending `null` for a field clears your override and restores the tenant default where one is set, the Curviate default otherwise. Any limit may be set to any value: Curviate does not clamp, cap or refuse a change on the grounds that the number is unsafe. A value above the Curviate default is reported back in the response, and on every later read, with the default and its source class attached; there is no way to acknowledge it away, and setting the value back to the default removes it. A value that is not a value, such as a negative ceiling or an unknown row name, is a 400. Every field whose value CHANGES is appended to the account's action ledger with the previous value, the new value, the Curviate default, the actor and the time; a field you send whose value already equals its current effective value is not ledgered and is not stored as an override, so reading the policy and sending the document back changes nothing. Six fields on the read are derived rather than configured: `effective_ceiling`, `interface_ceiling`, `effective_interface_ceiling`, `posture_source`, `over_default` and each row's `warm_up_state`. Send them and they are accepted and ignored, never stored and never ledgered, so the document you read can go straight back. To pin a row's ramp, set `warm_up_factor`. `activity_window` is not accepted: send its settable subfields instead, the top-level `timezone` for the zone, and per row `activity_window_start`, `activity_window_end`, `activity_window_timezone` and `activity_window_applies_to`. The 400 this produces names those subfields, not just the refused object. And read `changes nothing` as `changes no limit`: the `posture` fields are OVERRIDES at every scope, so writing back a posture a scope merely inherits PINS it there and appends one ledger entry per pinned scope. That is what stops a later account- or tenant-wide change from moving it. A pin already in place is a no-op. An agent-authenticated write is accepted on exactly the same footing as an operator's. There is no bulk import, file upload or policy template: configuring many rows or many accounts is a loop over this operation. One field is not account-scoped: `tenant_default_posture` sets the default for EVERY account in the tenant, not just the one in the path, which is what makes it a one-call change for a whole workspace of personas. It is reported back at the top of every policy response, so a change to it is visible even on an account that overrides it. One other field is not row-scoped: `limit_profile` selects which of the four Curviate default sets this account's rows resolve from, so it moves the default under every row at once while leaving every value you have configured explicitly exactly as you set it. It is the platform product active on the account, not your Curviate seat entitlement, and the two can disagree: a lapsed subscription leaves the seat untouched. Curviate detects it when the account connects and re-detects it on every reconnect; setting it here pins it, and the pin wins from then on: no connect, reconnect or account read moves it again until you release it with `limit_profile_source: "default"`, which is sent on its own: changing `limit_profile` and releasing it in the same request is refused. One field on this operation does not configure anything: `clear_halts` lifts the platform pause on the action types you name. When the platform refuses a call on an account, Curviate pauses that action type for the platform's own retry-after or a seeded cooldown, and every later call on it is refused locally without reaching the platform; the account resource reports the live pauses as `quotas[].halt`. Naming an action type here lifts its pause immediately, so the next call goes out. An action type with no active pause is accepted and does nothing, which makes it safe to send for a set you have not checked, and only the ones actually lifted are ledgered, each with the expiry it cut short, the actor and the time, readable afterwards on `GET /v1/{account_id}/safety-events` with `reason: "halt_cleared"`. Clearing disarms nothing: if the platform refuses the account again the pause returns, and a 429 or a refused write returns it for the full cooldown. Clear one when you have reason to believe the refusal was a transient upstream fault rather than the platform pushing back on this account.
2713
2713
  */
2714
2714
  patch: operations["patchV1AccountIdSafetyPolicy"];
2715
2715
  trace?: never;
@@ -2904,7 +2904,7 @@ interface components {
2904
2904
  }[];
2905
2905
  /** @description ISO-8601 UTC send timestamp. */
2906
2906
  timestamp?: string;
2907
- /** @description True if the connected account sent this message. */
2907
+ /** @description True if the connected account sent this message. Omitted when Curviate cannot yet identify the connected account; treat a missing value as unknown, not as received. */
2908
2908
  is_sender?: boolean;
2909
2909
  is_seen?: boolean;
2910
2910
  is_delivered?: boolean;
@@ -10378,7 +10378,7 @@ interface operations {
10378
10378
  }[];
10379
10379
  /** @description ISO-8601 UTC send timestamp. */
10380
10380
  timestamp?: string;
10381
- /** @description True if the connected account sent this message. */
10381
+ /** @description True if the connected account sent this message. Omitted when Curviate cannot yet identify the connected account; treat a missing value as unknown, not as received. */
10382
10382
  is_sender?: boolean;
10383
10383
  is_seen?: boolean;
10384
10384
  is_delivered?: boolean;
@@ -10803,7 +10803,7 @@ interface operations {
10803
10803
  }[];
10804
10804
  /** @description ISO-8601 UTC send timestamp. */
10805
10805
  timestamp?: string;
10806
- /** @description True if the connected account sent this message. */
10806
+ /** @description True if the connected account sent this message. Omitted when Curviate cannot yet identify the connected account; treat a missing value as unknown, not as received. */
10807
10807
  is_sender?: boolean;
10808
10808
  is_seen?: boolean;
10809
10809
  is_delivered?: boolean;
@@ -11173,7 +11173,7 @@ interface operations {
11173
11173
  }[];
11174
11174
  /** @description ISO-8601 UTC send timestamp. */
11175
11175
  timestamp?: string;
11176
- /** @description True if the connected account sent this message. */
11176
+ /** @description True if the connected account sent this message. Omitted when Curviate cannot yet identify the connected account; treat a missing value as unknown, not as received. */
11177
11177
  is_sender?: boolean;
11178
11178
  is_seen?: boolean;
11179
11179
  is_delivered?: boolean;
@@ -11557,7 +11557,7 @@ interface operations {
11557
11557
  }[];
11558
11558
  /** @description ISO-8601 UTC send timestamp. */
11559
11559
  timestamp?: string;
11560
- /** @description True if the connected account sent this message. */
11560
+ /** @description True if the connected account sent this message. Omitted when Curviate cannot yet identify the connected account; treat a missing value as unknown, not as received. */
11561
11561
  is_sender?: boolean;
11562
11562
  is_seen?: boolean;
11563
11563
  is_delivered?: boolean;
@@ -12752,7 +12752,7 @@ interface operations {
12752
12752
  }[];
12753
12753
  /** @description ISO-8601 UTC send timestamp. */
12754
12754
  timestamp?: string;
12755
- /** @description True if the connected account sent this message. */
12755
+ /** @description True if the connected account sent this message. Omitted when Curviate cannot yet identify the connected account; treat a missing value as unknown, not as received. */
12756
12756
  is_sender?: boolean;
12757
12757
  is_seen?: boolean;
12758
12758
  is_delivered?: boolean;
@@ -16514,7 +16514,7 @@ interface operations {
16514
16514
  getV1AccountIdJobsJobId: {
16515
16515
  parameters: {
16516
16516
  query?: {
16517
- /** @description Which additional sections to include on the response (e.g. hiring_team, salary, benefits). The exact set of accepted values is not finalized, supply the section names you need, comma-separated for more than one, and they are forwarded verbatim. Omit for the base fields only. */
16517
+ /** @description Which additional sections to include on the response (e.g. hiring_team, salary, benefits). The exact set of accepted values is not finalized, supply the section names you need, comma-separated for more than one; each name is trimmed before use. Omit for the base fields only. */
16518
16518
  with_sections?: string[];
16519
16519
  };
16520
16520
  header?: never;
@@ -20436,7 +20436,7 @@ interface operations {
20436
20436
  requestBody: {
20437
20437
  content: {
20438
20438
  "application/json": {
20439
- /** @description Free-text keyword search. Content, forwarded verbatim, never persisted. */
20439
+ /** @description Free-text keyword search. Trimmed before use; never persisted. */
20440
20440
  keywords?: string;
20441
20441
  /** @description Filter by candidate spotlight tags. */
20442
20442
  spotlights?: string[];
@@ -20509,9 +20509,9 @@ interface operations {
20509
20509
  project?: string;
20510
20510
  /** @description Resolved JOB_FUNCTION parameter ids. */
20511
20511
  job_function?: string[];
20512
- /** @description Content, forwarded verbatim, never persisted. */
20512
+ /** @description Filter by first name (trimmed before use; never persisted). */
20513
20513
  first_name?: string;
20514
- /** @description Content, forwarded verbatim, never persisted. */
20514
+ /** @description Filter by last name (trimmed before use; never persisted). */
20515
20515
  last_name?: string;
20516
20516
  /** @description Filter to members who recently joined LinkedIn. */
20517
20517
  recently_joined?: boolean;
@@ -20534,7 +20534,7 @@ interface operations {
20534
20534
  group?: string[];
20535
20535
  /** @description Filter to members who previously applied. */
20536
20536
  is_past_applicant?: boolean;
20537
- /** @description Content, forwarded verbatim, never persisted. */
20537
+ /** @description Filter by an existing note's content (trimmed before use; never persisted). */
20538
20538
  notes?: string;
20539
20539
  /** @description Resolved TAG parameter ids. */
20540
20540
  tags?: string[];
@@ -20922,7 +20922,7 @@ interface operations {
20922
20922
  status?: ("ACTIVE" | "CLOSED" | "DRAFT" | "REVIEW")[];
20923
20923
  /** @description Field to sort results by. Defaults to LAST_USED_BY_ME. */
20924
20924
  sort_by?: "LAST_USED_BY_ME" | "MOST_USED_BY_ME" | "LAST_VIEWED_BY_ME" | "NEWEST_TO_OLDEST" | "OLDEST_TO_NEWEST" | "ALPHABETICAL" | "REVERSE_ALPHABETICAL";
20925
- /** @description Filter by project name (content, forwarded verbatim, never persisted). */
20925
+ /** @description Filter by project name (trimmed before use; never persisted). */
20926
20926
  keywords?: string;
20927
20927
  /** @description Number of projects to return (1-100). Defaults to 10. */
20928
20928
  limit?: number;
@@ -21785,7 +21785,7 @@ interface operations {
21785
21785
  requestBody: {
21786
21786
  content: {
21787
21787
  "application/json": {
21788
- /** @description Free-text keyword search. Content, forwarded verbatim, never persisted. */
21788
+ /** @description Free-text keyword search. Trimmed before use; never persisted. */
21789
21789
  keywords?: string;
21790
21790
  /** @description Filter by candidate spotlight tags. */
21791
21791
  spotlights?: string[];
@@ -21858,9 +21858,9 @@ interface operations {
21858
21858
  project?: string;
21859
21859
  /** @description Resolved JOB_FUNCTION parameter ids. */
21860
21860
  job_function?: string[];
21861
- /** @description Content, forwarded verbatim, never persisted. */
21861
+ /** @description Filter by first name (trimmed before use; never persisted). */
21862
21862
  first_name?: string;
21863
- /** @description Content, forwarded verbatim, never persisted. */
21863
+ /** @description Filter by last name (trimmed before use; never persisted). */
21864
21864
  last_name?: string;
21865
21865
  /** @description Filter to members who recently joined LinkedIn. */
21866
21866
  recently_joined?: boolean;
@@ -21883,7 +21883,7 @@ interface operations {
21883
21883
  group?: string[];
21884
21884
  /** @description Filter to members who previously applied. */
21885
21885
  is_past_applicant?: boolean;
21886
- /** @description Content, forwarded verbatim, never persisted. */
21886
+ /** @description Filter by an existing note's content (trimmed before use; never persisted). */
21887
21887
  notes?: string;
21888
21888
  /** @description Resolved TAG parameter ids. */
21889
21889
  tags?: string[];
@@ -23203,7 +23203,7 @@ interface operations {
23203
23203
  reject_unqualified_applicants?: boolean;
23204
23204
  reject_out_of_country_applicants?: boolean;
23205
23205
  };
23206
- /** @description Content; the new project's name, forwarded verbatim, never persisted. */
23206
+ /** @description The new project's name (trimmed before use); never persisted. */
23207
23207
  project_name: string;
23208
23208
  };
23209
23209
  };
@@ -24221,7 +24221,7 @@ interface operations {
24221
24221
  "application/json": {
24222
24222
  /** @description The ID of the JOB_POSTING channel from the Talent Pool. SDK-confirmed REQUIRED. */
24223
24223
  channel_id: string;
24224
- /** @description Free-text keyword search. Content, forwarded verbatim, never persisted. */
24224
+ /** @description Free-text keyword search. Trimmed before use; never persisted. */
24225
24225
  keywords?: string;
24226
24226
  /**
24227
24227
  * @description Sort order for the applicant list.
@@ -29825,11 +29825,11 @@ interface operations {
29825
29825
  name?: string | null;
29826
29826
  account_ids?: string[];
29827
29827
  enabled?: boolean;
29828
- /** @description Custom headers added to each delivery POST, with the value masked. */
29828
+ /** @description Custom headers added to each delivery POST, with a fingerprint in place of the value. */
29829
29829
  headers?: {
29830
29830
  key?: string;
29831
- /** @description A masked view of the configured value: the first 8 characters followed by "..." when the value is at least 24 characters long, and a fixed "********" for anything shorter. The full value is never returned; the header name is what identifies which credential is configured. */
29832
- value_prefix?: string;
29831
+ /** @description A 8-character keyed fingerprint of the configured value. It carries no part of the value and no indication of its length, but it is not a zero-disclosure field: it is deterministic, so two headers in your account with the same fingerprint hold the same value, and a changed fingerprint means a changed value. Use it to confirm a rotation took effect, or to tell whether two of your webhooks carry the same credential. Fingerprints are scoped to your account and are not comparable with another account's. Null for a header configured before fingerprints existed. The header name is what identifies which credential is configured. */
29832
+ value_fingerprint?: string | null;
29833
29833
  }[];
29834
29834
  events?: string[];
29835
29835
  data?: string[];
@@ -29914,7 +29914,7 @@ interface operations {
29914
29914
  */
29915
29915
  enabled?: boolean;
29916
29916
  /**
29917
- * @description Custom headers added to each delivery POST. Names must be valid HTTP header names and values must be printable ASCII (no line breaks or control characters). Reserved names are rejected at registration; they include Content-Type, User-Agent, Host, any Curviate-* or Sec-* name, and the hop-by-hop headers. At most 10 headers, 1024 characters per value, 4096 bytes in total. Custom headers are not covered by the delivery signature, so treat them as a hint, not as proof of origin. Values are encrypted at rest and are never returned by a read. A read shows the header name plus a masked value: the first 8 characters followed by "..." when the value is at least 24 characters long, and a fixed "********" for anything shorter, so a short value is never disclosed by its own preview. The header name is what identifies which credential is configured.
29917
+ * @description Custom headers added to each delivery POST. Names must be valid HTTP header names and values must be printable ASCII (no line breaks or control characters). Reserved names are rejected at registration; they include Content-Type, User-Agent, Host, any Curviate-* or Sec-* name, and the hop-by-hop headers. At most 10 headers, 1024 characters per value, 4096 bytes in total. Custom headers are not covered by the delivery signature, so treat them as a hint, not as proof of origin. Values are encrypted at rest and are never returned by a read. A read shows the header name plus a 8-character keyed fingerprint of the value, which carries no part of the value and no indication of its length. It is deterministic within your account, so a fingerprint confirms a rotation took effect and tells you whether two of your webhooks carry the same credential; fingerprints are not comparable across accounts. The header name is what identifies which credential is configured.
29918
29918
  * @default []
29919
29919
  */
29920
29920
  headers?: {
@@ -29943,7 +29943,7 @@ interface operations {
29943
29943
  */
29944
29944
  enabled?: boolean;
29945
29945
  /**
29946
- * @description Custom headers added to each delivery POST. Names must be valid HTTP header names and values must be printable ASCII (no line breaks or control characters). Reserved names are rejected at registration; they include Content-Type, User-Agent, Host, any Curviate-* or Sec-* name, and the hop-by-hop headers. At most 10 headers, 1024 characters per value, 4096 bytes in total. Custom headers are not covered by the delivery signature, so treat them as a hint, not as proof of origin. Values are encrypted at rest and are never returned by a read. A read shows the header name plus a masked value: the first 8 characters followed by "..." when the value is at least 24 characters long, and a fixed "********" for anything shorter, so a short value is never disclosed by its own preview. The header name is what identifies which credential is configured.
29946
+ * @description Custom headers added to each delivery POST. Names must be valid HTTP header names and values must be printable ASCII (no line breaks or control characters). Reserved names are rejected at registration; they include Content-Type, User-Agent, Host, any Curviate-* or Sec-* name, and the hop-by-hop headers. At most 10 headers, 1024 characters per value, 4096 bytes in total. Custom headers are not covered by the delivery signature, so treat them as a hint, not as proof of origin. Values are encrypted at rest and are never returned by a read. A read shows the header name plus a 8-character keyed fingerprint of the value, which carries no part of the value and no indication of its length. It is deterministic within your account, so a fingerprint confirms a rotation took effect and tells you whether two of your webhooks carry the same credential; fingerprints are not comparable across accounts. The header name is what identifies which credential is configured.
29947
29947
  * @default []
29948
29948
  */
29949
29949
  headers?: {
@@ -29972,7 +29972,7 @@ interface operations {
29972
29972
  */
29973
29973
  enabled?: boolean;
29974
29974
  /**
29975
- * @description Custom headers added to each delivery POST. Names must be valid HTTP header names and values must be printable ASCII (no line breaks or control characters). Reserved names are rejected at registration; they include Content-Type, User-Agent, Host, any Curviate-* or Sec-* name, and the hop-by-hop headers. At most 10 headers, 1024 characters per value, 4096 bytes in total. Custom headers are not covered by the delivery signature, so treat them as a hint, not as proof of origin. Values are encrypted at rest and are never returned by a read. A read shows the header name plus a masked value: the first 8 characters followed by "..." when the value is at least 24 characters long, and a fixed "********" for anything shorter, so a short value is never disclosed by its own preview. The header name is what identifies which credential is configured.
29975
+ * @description Custom headers added to each delivery POST. Names must be valid HTTP header names and values must be printable ASCII (no line breaks or control characters). Reserved names are rejected at registration; they include Content-Type, User-Agent, Host, any Curviate-* or Sec-* name, and the hop-by-hop headers. At most 10 headers, 1024 characters per value, 4096 bytes in total. Custom headers are not covered by the delivery signature, so treat them as a hint, not as proof of origin. Values are encrypted at rest and are never returned by a read. A read shows the header name plus a 8-character keyed fingerprint of the value, which carries no part of the value and no indication of its length. It is deterministic within your account, so a fingerprint confirms a rotation took effect and tells you whether two of your webhooks carry the same credential; fingerprints are not comparable across accounts. The header name is what identifies which credential is configured.
29976
29976
  * @default []
29977
29977
  */
29978
29978
  headers?: {
@@ -30014,12 +30014,12 @@ interface operations {
30014
30014
  account_ids?: string[];
30015
30015
  /** @description A disabled webhook is created but delivers nothing. */
30016
30016
  enabled?: boolean;
30017
- /** @description Custom headers added to each delivery POST. Values are encrypted at rest, so a read shows the name and a masked value only. */
30017
+ /** @description Custom headers added to each delivery POST. Values are encrypted at rest and no read returns one, so a read shows the name and a fingerprint of the value. */
30018
30018
  headers?: {
30019
30019
  /** @description The header name, as configured. */
30020
30020
  key?: string;
30021
- /** @description A masked view of the configured value: the first 8 characters followed by "..." when the value is at least 24 characters long, and a fixed "********" for anything shorter. The full value is never returned; the header name is what identifies which credential is configured. */
30022
- value_prefix?: string;
30021
+ /** @description A 8-character keyed fingerprint of the configured value. It carries no part of the value and no indication of its length, but it is not a zero-disclosure field: it is deterministic, so two headers in your account with the same fingerprint hold the same value, and a changed fingerprint means a changed value. Use it to confirm a rotation took effect, or to tell whether two of your webhooks carry the same credential. Fingerprints are scoped to your account and are not comparable with another account's. Null for a header configured before fingerprints existed. The header name is what identifies which credential is configured. */
30022
+ value_fingerprint?: string | null;
30023
30023
  }[];
30024
30024
  /** @description Canonical event names this webhook subscribes to. */
30025
30025
  events?: string[];
@@ -30292,12 +30292,12 @@ interface operations {
30292
30292
  account_ids?: string[];
30293
30293
  /** @description A disabled webhook is kept but delivers nothing. Disabling takes effect immediately, including for retries that were already queued; those attempts are abandoned, not deferred, so re-enabling delivers new events rather than replaying the ones that were dropped. */
30294
30294
  enabled?: boolean;
30295
- /** @description Custom headers added to each delivery POST. Values are encrypted at rest, so a read shows the name and a masked value only. */
30295
+ /** @description Custom headers added to each delivery POST. Values are encrypted at rest and no read returns one, so a read shows the name and a fingerprint of the value. */
30296
30296
  headers?: {
30297
30297
  /** @description The header name, as configured. */
30298
30298
  key?: string;
30299
- /** @description A masked view of the configured value: the first 8 characters followed by "..." when the value is at least 24 characters long, and a fixed "********" for anything shorter. The full value is never returned; the header name is what identifies which credential is configured. */
30300
- value_prefix?: string;
30299
+ /** @description A 8-character keyed fingerprint of the configured value. It carries no part of the value and no indication of its length, but it is not a zero-disclosure field: it is deterministic, so two headers in your account with the same fingerprint hold the same value, and a changed fingerprint means a changed value. Use it to confirm a rotation took effect, or to tell whether two of your webhooks carry the same credential. Fingerprints are scoped to your account and are not comparable with another account's. Null for a header configured before fingerprints existed. The header name is what identifies which credential is configured. */
30300
+ value_fingerprint?: string | null;
30301
30301
  }[];
30302
30302
  /** @description Canonical event names this webhook subscribes to. */
30303
30303
  events?: string[];
@@ -30446,7 +30446,7 @@ interface operations {
30446
30446
  name?: string | null;
30447
30447
  /** @description Enable or disable the webhook. A disabled webhook delivers nothing. Disabling is a stop, not a pause: it takes effect immediately, including for retries that were already queued, and those attempts are abandoned rather than deferred, so re-enabling delivers new events instead of replaying the ones that were dropped. */
30448
30448
  enabled?: boolean;
30449
- /** @description Replace the custom headers added to each delivery POST (whole-array). Names must be valid HTTP header names and values must be printable ASCII (no line breaks or control characters). Reserved names are rejected at registration; they include Content-Type, User-Agent, Host, any Curviate-* or Sec-* name, and the hop-by-hop headers. At most 10 headers, 1024 characters per value, 4096 bytes in total. Custom headers are not covered by the delivery signature, so treat them as a hint, not as proof of origin. Values are encrypted at rest and are never returned by a read. A read shows the header name plus a masked value: the first 8 characters followed by "..." when the value is at least 24 characters long, and a fixed "********" for anything shorter, so a short value is never disclosed by its own preview. The header name is what identifies which credential is configured. */
30449
+ /** @description Replace the custom headers added to each delivery POST (whole-array). Names must be valid HTTP header names and values must be printable ASCII (no line breaks or control characters). Reserved names are rejected at registration; they include Content-Type, User-Agent, Host, any Curviate-* or Sec-* name, and the hop-by-hop headers. At most 10 headers, 1024 characters per value, 4096 bytes in total. Custom headers are not covered by the delivery signature, so treat them as a hint, not as proof of origin. Values are encrypted at rest and are never returned by a read. A read shows the header name plus a 8-character keyed fingerprint of the value, which carries no part of the value and no indication of its length. It is deterministic within your account, so a fingerprint confirms a rotation took effect and tells you whether two of your webhooks carry the same credential; fingerprints are not comparable across accounts. The header name is what identifies which credential is configured. */
30450
30450
  headers?: {
30451
30451
  key: string;
30452
30452
  value: string;
@@ -30488,12 +30488,12 @@ interface operations {
30488
30488
  account_ids?: string[];
30489
30489
  /** @description A disabled webhook is kept but delivers nothing. Disabling takes effect immediately, including for retries that were already queued; those attempts are abandoned, not deferred, so re-enabling delivers new events rather than replaying the ones that were dropped. */
30490
30490
  enabled?: boolean;
30491
- /** @description Custom headers added to each delivery POST. Values are encrypted at rest, so a read shows the name and a masked value only. */
30491
+ /** @description Custom headers added to each delivery POST. Values are encrypted at rest and no read returns one, so a read shows the name and a fingerprint of the value. */
30492
30492
  headers?: {
30493
30493
  /** @description The header name, as configured. */
30494
30494
  key?: string;
30495
- /** @description A masked view of the configured value: the first 8 characters followed by "..." when the value is at least 24 characters long, and a fixed "********" for anything shorter. The full value is never returned; the header name is what identifies which credential is configured. */
30496
- value_prefix?: string;
30495
+ /** @description A 8-character keyed fingerprint of the configured value. It carries no part of the value and no indication of its length, but it is not a zero-disclosure field: it is deterministic, so two headers in your account with the same fingerprint hold the same value, and a changed fingerprint means a changed value. Use it to confirm a rotation took effect, or to tell whether two of your webhooks carry the same credential. Fingerprints are scoped to your account and are not comparable with another account's. Null for a header configured before fingerprints existed. The header name is what identifies which credential is configured. */
30496
+ value_fingerprint?: string | null;
30497
30497
  }[];
30498
30498
  /** @description Canonical event names this webhook subscribes to. */
30499
30499
  events?: string[];
@@ -30600,13 +30600,13 @@ interface operations {
30600
30600
  */
30601
30601
  limit_profile?: "basic" | "premium" | "sales_navigator" | "recruiter";
30602
30602
  /**
30603
- * @description Where `limit_profile` came from. `detected`: Curviate read it from LinkedIn, at `limit_profile_detected_at`. `operator`: it was set through this operation and holds until the account next connects, or until you send `limit_profile_source: "default"` on this operation, which releases it. `default`: it has never been observed, so the value is the seeded `basic` and says nothing about the account; Curviate detects it on the account's next read or connect.
30603
+ * @description Where `limit_profile` came from. `detected`: Curviate read it from LinkedIn, at `limit_profile_detected_at`. `operator`: it was set through this operation and holds until you release it by sending `limit_profile_source: "default"` on this operation, on its own (changing `limit_profile` and releasing it in the same request is refused). Nothing else overrides it: a connect, a reconnect and an account read all leave a pinned value exactly as you set it. `default`: it has never been observed, so the value is the seeded `basic` and says nothing about the account; Curviate detects it on the account's next read or connect.
30604
30604
  * @enum {string}
30605
30605
  */
30606
30606
  limit_profile_source?: "default" | "detected" | "operator";
30607
30607
  /**
30608
30608
  * Format: date-time
30609
- * @description When Curviate last read `limit_profile` from LinkedIn, whether or not the value changed. Null until it has. Curviate re-reads it on connect and, at most once a day, on an account read, so a subscription change reaches the numbers without a reconnect.
30609
+ * @description When Curviate last read `limit_profile` from LinkedIn, whether or not the value changed. Null until it has. Curviate re-reads it on connect and, at most once a day, on an account read, so a subscription change reaches the numbers without a reconnect. While `limit_profile_source` is `operator` neither the value nor this timestamp moves, until you release the pin.
30610
30610
  */
30611
30611
  limit_profile_detected_at?: string | null;
30612
30612
  /**
@@ -30770,7 +30770,7 @@ interface operations {
30770
30770
  content: {
30771
30771
  "application/json": {
30772
30772
  /**
30773
- * @description Which set of Curviate defaults this account's rows resolve from: `basic`, `premium`, `sales_navigator` or `recruiter`. Each inherits the one before it and raises a few rows. This is the platform product active on the account, NOT the Curviate seat entitlement, and the two can disagree: a lapsed subscription leaves the seat untouched. Curviate detects it from the platform when the account connects, re-detects it on every reconnect and, at most once a day, on an account read; setting it here is an operator override of that result and holds until the next connect. To undo the override, send `limit_profile_source: "default"`: the pin is released, and Curviate re-reads the value from LinkedIn on the account's next read or connect. Sending the value the account already holds changes nothing and pins nothing. The change is recorded in the ledger and it moves the defaults under every row at once, so any row you have configured explicitly keeps your value. The elevated Sales Navigator and Recruiter figures apply only to calls made through the matching interface, the Sales Navigator and Recruiter operations, and Curviate holds each call to the figure for the interface it goes through. The numbers here are therefore the ones a standard-interface call is held to, on every profile; a call through one of those operations resolves from the elevated set instead, and each row publishes that figure as `interface_ceiling`.
30773
+ * @description Which set of Curviate defaults this account's rows resolve from: `basic`, `premium`, `sales_navigator` or `recruiter`. Each inherits the one before it and raises a few rows. This is the platform product active on the account, NOT the Curviate seat entitlement, and the two can disagree: a lapsed subscription leaves the seat untouched. Curviate detects it from the platform when the account connects, re-detects it on every reconnect and, at most once a day, on an account read; setting it here pins it, and the pin wins over detection from then on. None of those paths moves a pinned value, so it holds until you release it. To release the pin, send `limit_profile_source: "default"` on its own: Curviate re-reads the value from LinkedIn on the account's next read or connect. Changing `limit_profile` and releasing it in the same request is refused with `INVALID_REQUEST`, because those are opposite intents. Sending the value the account already holds changes nothing and pins nothing. The change is recorded in the ledger and it moves the defaults under every row at once, so any row you have configured explicitly keeps your value. The elevated Sales Navigator and Recruiter figures apply only to calls made through the matching interface, the Sales Navigator and Recruiter operations, and Curviate holds each call to the figure for the interface it goes through. The numbers here are therefore the ones a standard-interface call is held to, on every profile; a call through one of those operations resolves from the elevated set instead, and each row publishes that figure as `interface_ceiling`.
30774
30774
  * @enum {string}
30775
30775
  */
30776
30776
  limit_profile?: "basic" | "premium" | "sales_navigator" | "recruiter";
@@ -30860,7 +30860,7 @@ interface operations {
30860
30860
  /** @description READ-ONLY. The account this document describes; the path names it. Sent back on a write it is accepted and ignored, so the whole document round-trips; it is never stored and never ledgered. */
30861
30861
  account_id?: unknown;
30862
30862
  /**
30863
- * @description Where `limit_profile` came from: `default` (never observed), `detected` (read from LinkedIn) or `operator` (set through this operation). Sending `default` releases an operator override: the value is re-read from LinkedIn on the account's next read or connect. Sending `detected` or `operator` is accepted and ignored, so the whole document round-trips.
30863
+ * @description Where `limit_profile` came from: `default` (never observed), `detected` (read from LinkedIn) or `operator` (pinned through this operation, and nothing but a release moves it). Sending `default` releases a pin: the value is re-read from LinkedIn on the account's next read or connect. Send it on its own; changing `limit_profile` in the same request is refused. Sending `detected` or `operator` is accepted and ignored, so the whole document round-trips.
30864
30864
  * @enum {string}
30865
30865
  */
30866
30866
  limit_profile_source?: "default" | "detected" | "operator";
@@ -30898,13 +30898,13 @@ interface operations {
30898
30898
  */
30899
30899
  limit_profile?: "basic" | "premium" | "sales_navigator" | "recruiter";
30900
30900
  /**
30901
- * @description Where `limit_profile` came from. `detected`: Curviate read it from LinkedIn, at `limit_profile_detected_at`. `operator`: it was set through this operation and holds until the account next connects, or until you send `limit_profile_source: "default"` on this operation, which releases it. `default`: it has never been observed, so the value is the seeded `basic` and says nothing about the account; Curviate detects it on the account's next read or connect.
30901
+ * @description Where `limit_profile` came from. `detected`: Curviate read it from LinkedIn, at `limit_profile_detected_at`. `operator`: it was set through this operation and holds until you release it by sending `limit_profile_source: "default"` on this operation, on its own (changing `limit_profile` and releasing it in the same request is refused). Nothing else overrides it: a connect, a reconnect and an account read all leave a pinned value exactly as you set it. `default`: it has never been observed, so the value is the seeded `basic` and says nothing about the account; Curviate detects it on the account's next read or connect.
30902
30902
  * @enum {string}
30903
30903
  */
30904
30904
  limit_profile_source?: "default" | "detected" | "operator";
30905
30905
  /**
30906
30906
  * Format: date-time
30907
- * @description When Curviate last read `limit_profile` from LinkedIn, whether or not the value changed. Null until it has. Curviate re-reads it on connect and, at most once a day, on an account read, so a subscription change reaches the numbers without a reconnect.
30907
+ * @description When Curviate last read `limit_profile` from LinkedIn, whether or not the value changed. Null until it has. Curviate re-reads it on connect and, at most once a day, on an account read, so a subscription change reaches the numbers without a reconnect. While `limit_profile_source` is `operator` neither the value nor this timestamp moves, until you release the pin.
30908
30908
  */
30909
30909
  limit_profile_detected_at?: string | null;
30910
30910
  /**
@@ -32146,10 +32146,9 @@ declare class SearchResource {
32146
32146
  * stays available as the numeric fallback. A malformed cursor is a `400`.
32147
32147
  *
32148
32148
  * @example
32149
- * ```ts
32150
32149
  * let cursor: string | null | undefined;
32151
32150
  * do {
32152
- * const page = await acc.search.getParameters({
32151
+ * const page = await curviate.account("acc_123").search.getParameters({
32153
32152
  * type: "SKILL",
32154
32153
  * keywords: "software development",
32155
32154
  * ...(cursor ? { cursor } : {}),
@@ -32157,7 +32156,6 @@ declare class SearchResource {
32157
32156
  * for (const item of page.items) console.log(item.id, item.name);
32158
32157
  * cursor = page.cursor;
32159
32158
  * } while (cursor);
32160
- * ```
32161
32159
  */
32162
32160
  getParameters(query: SearchParametersQuery): Promise<SearchParametersResult>;
32163
32161
  /**
package/dist/index.js CHANGED
@@ -259,8 +259,11 @@ function defaultSleep(ms) {
259
259
  }
260
260
  function parseRetryAfterMs(header) {
261
261
  if (header == null) return void 0;
262
- const seconds = Number(header);
263
- if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1e3;
262
+ const trimmed = header.trim();
263
+ if (trimmed !== "") {
264
+ const seconds = Number(trimmed);
265
+ if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1e3;
266
+ }
264
267
  return 3e4;
265
268
  }
266
269
  function backoffDelay(n, jitter) {
@@ -404,7 +407,8 @@ async function execute(method, path, opts) {
404
407
  }
405
408
  const err = await errorFromResponse(res);
406
409
  const namesBudgetRow = err.budgetRow !== void 0;
407
- const retryable = !isWrite && !namesBudgetRow && RETRYABLE_CODES.has(err.code) && attempt < opts.maxRetries;
410
+ const neverRetry = err.retryHint?.kind === "never";
411
+ const retryable = !isWrite && !namesBudgetRow && !neverRetry && RETRYABLE_CODES.has(err.code) && attempt < opts.maxRetries;
408
412
  if (retryable) {
409
413
  await sleep(retryDelay(err, attempt + 1, jitterFn()));
410
414
  attempt += 1;
@@ -1138,10 +1142,9 @@ var SearchResource = class {
1138
1142
  * stays available as the numeric fallback. A malformed cursor is a `400`.
1139
1143
  *
1140
1144
  * @example
1141
- * ```ts
1142
1145
  * let cursor: string | null | undefined;
1143
1146
  * do {
1144
- * const page = await acc.search.getParameters({
1147
+ * const page = await curviate.account("acc_123").search.getParameters({
1145
1148
  * type: "SKILL",
1146
1149
  * keywords: "software development",
1147
1150
  * ...(cursor ? { cursor } : {}),
@@ -1149,7 +1152,6 @@ var SearchResource = class {
1149
1152
  * for (const item of page.items) console.log(item.id, item.name);
1150
1153
  * cursor = page.cursor;
1151
1154
  * } while (cursor);
1152
- * ```
1153
1155
  */
1154
1156
  getParameters(query) {
1155
1157
  return this.ctx.request({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@curviate/sdk",
3
- "version": "0.36.0",
3
+ "version": "0.37.1",
4
4
  "private": false,
5
5
  "description": "TypeScript SDK for the Curviate API.",
6
6
  "license": "MIT",
@@ -2611,7 +2611,7 @@ export interface paths {
2611
2611
  head?: never;
2612
2612
  /**
2613
2613
  * Update an account's safety policy
2614
- * @description The account-level safety-policy write (tenant-wide defaults are set on `PATCH /v1/safety-policy`). Send only the fields you are changing: everything you omit is left byte-identical, and sending `null` for a field clears your override and restores the tenant default where one is set, the Curviate default otherwise. Any limit may be set to any value: Curviate does not clamp, cap or refuse a change on the grounds that the number is unsafe. A value above the Curviate default is reported back in the response, and on every later read, with the default and its source class attached; there is no way to acknowledge it away, and setting the value back to the default removes it. A value that is not a value, such as a negative ceiling or an unknown row name, is a 400. Every field whose value CHANGES is appended to the account's action ledger with the previous value, the new value, the Curviate default, the actor and the time; a field you send whose value already equals its current effective value is not ledgered and is not stored as an override, so reading the policy and sending the document back changes nothing. Six fields on the read are derived rather than configured: `effective_ceiling`, `interface_ceiling`, `effective_interface_ceiling`, `posture_source`, `over_default` and each row's `warm_up_state`. Send them and they are accepted and ignored, never stored and never ledgered, so the document you read can go straight back. To pin a row's ramp, set `warm_up_factor`. `activity_window` is not accepted: send its settable subfields instead, the top-level `timezone` for the zone, and per row `activity_window_start`, `activity_window_end`, `activity_window_timezone` and `activity_window_applies_to`. The 400 this produces names those subfields, not just the refused object. And read `changes nothing` as `changes no limit`: the `posture` fields are OVERRIDES at every scope, so writing back a posture a scope merely inherits PINS it there and appends one ledger entry per pinned scope. That is what stops a later account- or tenant-wide change from moving it. A pin already in place is a no-op. An agent-authenticated write is accepted on exactly the same footing as an operator's. There is no bulk import, file upload or policy template: configuring many rows or many accounts is a loop over this operation. One field is not account-scoped: `tenant_default_posture` sets the default for EVERY account in the tenant, not just the one in the path, which is what makes it a one-call change for a whole workspace of personas. It is reported back at the top of every policy response, so a change to it is visible even on an account that overrides it. One other field is not row-scoped: `limit_profile` selects which of the four Curviate default sets this account's rows resolve from, so it moves the default under every row at once while leaving every value you have configured explicitly exactly as you set it. It is the platform product active on the account, not your Curviate seat entitlement, and the two can disagree: a lapsed subscription leaves the seat untouched. Curviate detects it when the account connects and re-detects it on every reconnect; setting it here is an operator override of that result, and it holds until the next connect. One field on this operation does not configure anything: `clear_halts` lifts the platform pause on the action types you name. When the platform refuses a call on an account, Curviate pauses that action type for the platform's own retry-after or a seeded cooldown, and every later call on it is refused locally without reaching the platform; the account resource reports the live pauses as `quotas[].halt`. Naming an action type here lifts its pause immediately, so the next call goes out. An action type with no active pause is accepted and does nothing, which makes it safe to send for a set you have not checked, and only the ones actually lifted are ledgered, each with the expiry it cut short, the actor and the time, readable afterwards on `GET /v1/{account_id}/safety-events` with `reason: "halt_cleared"`. Clearing disarms nothing: if the platform refuses the account again the pause returns, and a 429 or a refused write returns it for the full cooldown. Clear one when you have reason to believe the refusal was a transient upstream fault rather than the platform pushing back on this account.
2614
+ * @description The account-level safety-policy write (tenant-wide defaults are set on `PATCH /v1/safety-policy`). Send only the fields you are changing: everything you omit is left byte-identical, and sending `null` for a field clears your override and restores the tenant default where one is set, the Curviate default otherwise. Any limit may be set to any value: Curviate does not clamp, cap or refuse a change on the grounds that the number is unsafe. A value above the Curviate default is reported back in the response, and on every later read, with the default and its source class attached; there is no way to acknowledge it away, and setting the value back to the default removes it. A value that is not a value, such as a negative ceiling or an unknown row name, is a 400. Every field whose value CHANGES is appended to the account's action ledger with the previous value, the new value, the Curviate default, the actor and the time; a field you send whose value already equals its current effective value is not ledgered and is not stored as an override, so reading the policy and sending the document back changes nothing. Six fields on the read are derived rather than configured: `effective_ceiling`, `interface_ceiling`, `effective_interface_ceiling`, `posture_source`, `over_default` and each row's `warm_up_state`. Send them and they are accepted and ignored, never stored and never ledgered, so the document you read can go straight back. To pin a row's ramp, set `warm_up_factor`. `activity_window` is not accepted: send its settable subfields instead, the top-level `timezone` for the zone, and per row `activity_window_start`, `activity_window_end`, `activity_window_timezone` and `activity_window_applies_to`. The 400 this produces names those subfields, not just the refused object. And read `changes nothing` as `changes no limit`: the `posture` fields are OVERRIDES at every scope, so writing back a posture a scope merely inherits PINS it there and appends one ledger entry per pinned scope. That is what stops a later account- or tenant-wide change from moving it. A pin already in place is a no-op. An agent-authenticated write is accepted on exactly the same footing as an operator's. There is no bulk import, file upload or policy template: configuring many rows or many accounts is a loop over this operation. One field is not account-scoped: `tenant_default_posture` sets the default for EVERY account in the tenant, not just the one in the path, which is what makes it a one-call change for a whole workspace of personas. It is reported back at the top of every policy response, so a change to it is visible even on an account that overrides it. One other field is not row-scoped: `limit_profile` selects which of the four Curviate default sets this account's rows resolve from, so it moves the default under every row at once while leaving every value you have configured explicitly exactly as you set it. It is the platform product active on the account, not your Curviate seat entitlement, and the two can disagree: a lapsed subscription leaves the seat untouched. Curviate detects it when the account connects and re-detects it on every reconnect; setting it here pins it, and the pin wins from then on: no connect, reconnect or account read moves it again until you release it with `limit_profile_source: "default"`, which is sent on its own: changing `limit_profile` and releasing it in the same request is refused. One field on this operation does not configure anything: `clear_halts` lifts the platform pause on the action types you name. When the platform refuses a call on an account, Curviate pauses that action type for the platform's own retry-after or a seeded cooldown, and every later call on it is refused locally without reaching the platform; the account resource reports the live pauses as `quotas[].halt`. Naming an action type here lifts its pause immediately, so the next call goes out. An action type with no active pause is accepted and does nothing, which makes it safe to send for a set you have not checked, and only the ones actually lifted are ledgered, each with the expiry it cut short, the actor and the time, readable afterwards on `GET /v1/{account_id}/safety-events` with `reason: "halt_cleared"`. Clearing disarms nothing: if the platform refuses the account again the pause returns, and a 429 or a refused write returns it for the full cooldown. Clear one when you have reason to believe the refusal was a transient upstream fault rather than the platform pushing back on this account.
2615
2615
  */
2616
2616
  patch: operations["patchV1AccountIdSafetyPolicy"];
2617
2617
  trace?: never;
@@ -2807,7 +2807,7 @@ export interface components {
2807
2807
  }[];
2808
2808
  /** @description ISO-8601 UTC send timestamp. */
2809
2809
  timestamp?: string;
2810
- /** @description True if the connected account sent this message. */
2810
+ /** @description True if the connected account sent this message. Omitted when Curviate cannot yet identify the connected account; treat a missing value as unknown, not as received. */
2811
2811
  is_sender?: boolean;
2812
2812
  is_seen?: boolean;
2813
2813
  is_delivered?: boolean;
@@ -10282,7 +10282,7 @@ export interface operations {
10282
10282
  }[];
10283
10283
  /** @description ISO-8601 UTC send timestamp. */
10284
10284
  timestamp?: string;
10285
- /** @description True if the connected account sent this message. */
10285
+ /** @description True if the connected account sent this message. Omitted when Curviate cannot yet identify the connected account; treat a missing value as unknown, not as received. */
10286
10286
  is_sender?: boolean;
10287
10287
  is_seen?: boolean;
10288
10288
  is_delivered?: boolean;
@@ -10707,7 +10707,7 @@ export interface operations {
10707
10707
  }[];
10708
10708
  /** @description ISO-8601 UTC send timestamp. */
10709
10709
  timestamp?: string;
10710
- /** @description True if the connected account sent this message. */
10710
+ /** @description True if the connected account sent this message. Omitted when Curviate cannot yet identify the connected account; treat a missing value as unknown, not as received. */
10711
10711
  is_sender?: boolean;
10712
10712
  is_seen?: boolean;
10713
10713
  is_delivered?: boolean;
@@ -11077,7 +11077,7 @@ export interface operations {
11077
11077
  }[];
11078
11078
  /** @description ISO-8601 UTC send timestamp. */
11079
11079
  timestamp?: string;
11080
- /** @description True if the connected account sent this message. */
11080
+ /** @description True if the connected account sent this message. Omitted when Curviate cannot yet identify the connected account; treat a missing value as unknown, not as received. */
11081
11081
  is_sender?: boolean;
11082
11082
  is_seen?: boolean;
11083
11083
  is_delivered?: boolean;
@@ -11461,7 +11461,7 @@ export interface operations {
11461
11461
  }[];
11462
11462
  /** @description ISO-8601 UTC send timestamp. */
11463
11463
  timestamp?: string;
11464
- /** @description True if the connected account sent this message. */
11464
+ /** @description True if the connected account sent this message. Omitted when Curviate cannot yet identify the connected account; treat a missing value as unknown, not as received. */
11465
11465
  is_sender?: boolean;
11466
11466
  is_seen?: boolean;
11467
11467
  is_delivered?: boolean;
@@ -12656,7 +12656,7 @@ export interface operations {
12656
12656
  }[];
12657
12657
  /** @description ISO-8601 UTC send timestamp. */
12658
12658
  timestamp?: string;
12659
- /** @description True if the connected account sent this message. */
12659
+ /** @description True if the connected account sent this message. Omitted when Curviate cannot yet identify the connected account; treat a missing value as unknown, not as received. */
12660
12660
  is_sender?: boolean;
12661
12661
  is_seen?: boolean;
12662
12662
  is_delivered?: boolean;
@@ -16418,7 +16418,7 @@ export interface operations {
16418
16418
  getV1AccountIdJobsJobId: {
16419
16419
  parameters: {
16420
16420
  query?: {
16421
- /** @description Which additional sections to include on the response (e.g. hiring_team, salary, benefits). The exact set of accepted values is not finalized, supply the section names you need, comma-separated for more than one, and they are forwarded verbatim. Omit for the base fields only. */
16421
+ /** @description Which additional sections to include on the response (e.g. hiring_team, salary, benefits). The exact set of accepted values is not finalized, supply the section names you need, comma-separated for more than one; each name is trimmed before use. Omit for the base fields only. */
16422
16422
  with_sections?: string[];
16423
16423
  };
16424
16424
  header?: never;
@@ -20340,7 +20340,7 @@ export interface operations {
20340
20340
  requestBody: {
20341
20341
  content: {
20342
20342
  "application/json": {
20343
- /** @description Free-text keyword search. Content, forwarded verbatim, never persisted. */
20343
+ /** @description Free-text keyword search. Trimmed before use; never persisted. */
20344
20344
  keywords?: string;
20345
20345
  /** @description Filter by candidate spotlight tags. */
20346
20346
  spotlights?: string[];
@@ -20413,9 +20413,9 @@ export interface operations {
20413
20413
  project?: string;
20414
20414
  /** @description Resolved JOB_FUNCTION parameter ids. */
20415
20415
  job_function?: string[];
20416
- /** @description Content, forwarded verbatim, never persisted. */
20416
+ /** @description Filter by first name (trimmed before use; never persisted). */
20417
20417
  first_name?: string;
20418
- /** @description Content, forwarded verbatim, never persisted. */
20418
+ /** @description Filter by last name (trimmed before use; never persisted). */
20419
20419
  last_name?: string;
20420
20420
  /** @description Filter to members who recently joined LinkedIn. */
20421
20421
  recently_joined?: boolean;
@@ -20438,7 +20438,7 @@ export interface operations {
20438
20438
  group?: string[];
20439
20439
  /** @description Filter to members who previously applied. */
20440
20440
  is_past_applicant?: boolean;
20441
- /** @description Content, forwarded verbatim, never persisted. */
20441
+ /** @description Filter by an existing note's content (trimmed before use; never persisted). */
20442
20442
  notes?: string;
20443
20443
  /** @description Resolved TAG parameter ids. */
20444
20444
  tags?: string[];
@@ -20826,7 +20826,7 @@ export interface operations {
20826
20826
  status?: ("ACTIVE" | "CLOSED" | "DRAFT" | "REVIEW")[];
20827
20827
  /** @description Field to sort results by. Defaults to LAST_USED_BY_ME. */
20828
20828
  sort_by?: "LAST_USED_BY_ME" | "MOST_USED_BY_ME" | "LAST_VIEWED_BY_ME" | "NEWEST_TO_OLDEST" | "OLDEST_TO_NEWEST" | "ALPHABETICAL" | "REVERSE_ALPHABETICAL";
20829
- /** @description Filter by project name (content, forwarded verbatim, never persisted). */
20829
+ /** @description Filter by project name (trimmed before use; never persisted). */
20830
20830
  keywords?: string;
20831
20831
  /** @description Number of projects to return (1-100). Defaults to 10. */
20832
20832
  limit?: number;
@@ -21689,7 +21689,7 @@ export interface operations {
21689
21689
  requestBody: {
21690
21690
  content: {
21691
21691
  "application/json": {
21692
- /** @description Free-text keyword search. Content, forwarded verbatim, never persisted. */
21692
+ /** @description Free-text keyword search. Trimmed before use; never persisted. */
21693
21693
  keywords?: string;
21694
21694
  /** @description Filter by candidate spotlight tags. */
21695
21695
  spotlights?: string[];
@@ -21762,9 +21762,9 @@ export interface operations {
21762
21762
  project?: string;
21763
21763
  /** @description Resolved JOB_FUNCTION parameter ids. */
21764
21764
  job_function?: string[];
21765
- /** @description Content, forwarded verbatim, never persisted. */
21765
+ /** @description Filter by first name (trimmed before use; never persisted). */
21766
21766
  first_name?: string;
21767
- /** @description Content, forwarded verbatim, never persisted. */
21767
+ /** @description Filter by last name (trimmed before use; never persisted). */
21768
21768
  last_name?: string;
21769
21769
  /** @description Filter to members who recently joined LinkedIn. */
21770
21770
  recently_joined?: boolean;
@@ -21787,7 +21787,7 @@ export interface operations {
21787
21787
  group?: string[];
21788
21788
  /** @description Filter to members who previously applied. */
21789
21789
  is_past_applicant?: boolean;
21790
- /** @description Content, forwarded verbatim, never persisted. */
21790
+ /** @description Filter by an existing note's content (trimmed before use; never persisted). */
21791
21791
  notes?: string;
21792
21792
  /** @description Resolved TAG parameter ids. */
21793
21793
  tags?: string[];
@@ -23107,7 +23107,7 @@ export interface operations {
23107
23107
  reject_unqualified_applicants?: boolean;
23108
23108
  reject_out_of_country_applicants?: boolean;
23109
23109
  };
23110
- /** @description Content; the new project's name, forwarded verbatim, never persisted. */
23110
+ /** @description The new project's name (trimmed before use); never persisted. */
23111
23111
  project_name: string;
23112
23112
  };
23113
23113
  };
@@ -24125,7 +24125,7 @@ export interface operations {
24125
24125
  "application/json": {
24126
24126
  /** @description The ID of the JOB_POSTING channel from the Talent Pool. SDK-confirmed REQUIRED. */
24127
24127
  channel_id: string;
24128
- /** @description Free-text keyword search. Content, forwarded verbatim, never persisted. */
24128
+ /** @description Free-text keyword search. Trimmed before use; never persisted. */
24129
24129
  keywords?: string;
24130
24130
  /**
24131
24131
  * @description Sort order for the applicant list.
@@ -29729,11 +29729,11 @@ export interface operations {
29729
29729
  name?: string | null;
29730
29730
  account_ids?: string[];
29731
29731
  enabled?: boolean;
29732
- /** @description Custom headers added to each delivery POST, with the value masked. */
29732
+ /** @description Custom headers added to each delivery POST, with a fingerprint in place of the value. */
29733
29733
  headers?: {
29734
29734
  key?: string;
29735
- /** @description A masked view of the configured value: the first 8 characters followed by "..." when the value is at least 24 characters long, and a fixed "********" for anything shorter. The full value is never returned; the header name is what identifies which credential is configured. */
29736
- value_prefix?: string;
29735
+ /** @description A 8-character keyed fingerprint of the configured value. It carries no part of the value and no indication of its length, but it is not a zero-disclosure field: it is deterministic, so two headers in your account with the same fingerprint hold the same value, and a changed fingerprint means a changed value. Use it to confirm a rotation took effect, or to tell whether two of your webhooks carry the same credential. Fingerprints are scoped to your account and are not comparable with another account's. Null for a header configured before fingerprints existed. The header name is what identifies which credential is configured. */
29736
+ value_fingerprint?: string | null;
29737
29737
  }[];
29738
29738
  events?: string[];
29739
29739
  data?: string[];
@@ -29818,7 +29818,7 @@ export interface operations {
29818
29818
  */
29819
29819
  enabled?: boolean;
29820
29820
  /**
29821
- * @description Custom headers added to each delivery POST. Names must be valid HTTP header names and values must be printable ASCII (no line breaks or control characters). Reserved names are rejected at registration; they include Content-Type, User-Agent, Host, any Curviate-* or Sec-* name, and the hop-by-hop headers. At most 10 headers, 1024 characters per value, 4096 bytes in total. Custom headers are not covered by the delivery signature, so treat them as a hint, not as proof of origin. Values are encrypted at rest and are never returned by a read. A read shows the header name plus a masked value: the first 8 characters followed by "..." when the value is at least 24 characters long, and a fixed "********" for anything shorter, so a short value is never disclosed by its own preview. The header name is what identifies which credential is configured.
29821
+ * @description Custom headers added to each delivery POST. Names must be valid HTTP header names and values must be printable ASCII (no line breaks or control characters). Reserved names are rejected at registration; they include Content-Type, User-Agent, Host, any Curviate-* or Sec-* name, and the hop-by-hop headers. At most 10 headers, 1024 characters per value, 4096 bytes in total. Custom headers are not covered by the delivery signature, so treat them as a hint, not as proof of origin. Values are encrypted at rest and are never returned by a read. A read shows the header name plus a 8-character keyed fingerprint of the value, which carries no part of the value and no indication of its length. It is deterministic within your account, so a fingerprint confirms a rotation took effect and tells you whether two of your webhooks carry the same credential; fingerprints are not comparable across accounts. The header name is what identifies which credential is configured.
29822
29822
  * @default []
29823
29823
  */
29824
29824
  headers?: {
@@ -29847,7 +29847,7 @@ export interface operations {
29847
29847
  */
29848
29848
  enabled?: boolean;
29849
29849
  /**
29850
- * @description Custom headers added to each delivery POST. Names must be valid HTTP header names and values must be printable ASCII (no line breaks or control characters). Reserved names are rejected at registration; they include Content-Type, User-Agent, Host, any Curviate-* or Sec-* name, and the hop-by-hop headers. At most 10 headers, 1024 characters per value, 4096 bytes in total. Custom headers are not covered by the delivery signature, so treat them as a hint, not as proof of origin. Values are encrypted at rest and are never returned by a read. A read shows the header name plus a masked value: the first 8 characters followed by "..." when the value is at least 24 characters long, and a fixed "********" for anything shorter, so a short value is never disclosed by its own preview. The header name is what identifies which credential is configured.
29850
+ * @description Custom headers added to each delivery POST. Names must be valid HTTP header names and values must be printable ASCII (no line breaks or control characters). Reserved names are rejected at registration; they include Content-Type, User-Agent, Host, any Curviate-* or Sec-* name, and the hop-by-hop headers. At most 10 headers, 1024 characters per value, 4096 bytes in total. Custom headers are not covered by the delivery signature, so treat them as a hint, not as proof of origin. Values are encrypted at rest and are never returned by a read. A read shows the header name plus a 8-character keyed fingerprint of the value, which carries no part of the value and no indication of its length. It is deterministic within your account, so a fingerprint confirms a rotation took effect and tells you whether two of your webhooks carry the same credential; fingerprints are not comparable across accounts. The header name is what identifies which credential is configured.
29851
29851
  * @default []
29852
29852
  */
29853
29853
  headers?: {
@@ -29876,7 +29876,7 @@ export interface operations {
29876
29876
  */
29877
29877
  enabled?: boolean;
29878
29878
  /**
29879
- * @description Custom headers added to each delivery POST. Names must be valid HTTP header names and values must be printable ASCII (no line breaks or control characters). Reserved names are rejected at registration; they include Content-Type, User-Agent, Host, any Curviate-* or Sec-* name, and the hop-by-hop headers. At most 10 headers, 1024 characters per value, 4096 bytes in total. Custom headers are not covered by the delivery signature, so treat them as a hint, not as proof of origin. Values are encrypted at rest and are never returned by a read. A read shows the header name plus a masked value: the first 8 characters followed by "..." when the value is at least 24 characters long, and a fixed "********" for anything shorter, so a short value is never disclosed by its own preview. The header name is what identifies which credential is configured.
29879
+ * @description Custom headers added to each delivery POST. Names must be valid HTTP header names and values must be printable ASCII (no line breaks or control characters). Reserved names are rejected at registration; they include Content-Type, User-Agent, Host, any Curviate-* or Sec-* name, and the hop-by-hop headers. At most 10 headers, 1024 characters per value, 4096 bytes in total. Custom headers are not covered by the delivery signature, so treat them as a hint, not as proof of origin. Values are encrypted at rest and are never returned by a read. A read shows the header name plus a 8-character keyed fingerprint of the value, which carries no part of the value and no indication of its length. It is deterministic within your account, so a fingerprint confirms a rotation took effect and tells you whether two of your webhooks carry the same credential; fingerprints are not comparable across accounts. The header name is what identifies which credential is configured.
29880
29880
  * @default []
29881
29881
  */
29882
29882
  headers?: {
@@ -29918,12 +29918,12 @@ export interface operations {
29918
29918
  account_ids?: string[];
29919
29919
  /** @description A disabled webhook is created but delivers nothing. */
29920
29920
  enabled?: boolean;
29921
- /** @description Custom headers added to each delivery POST. Values are encrypted at rest, so a read shows the name and a masked value only. */
29921
+ /** @description Custom headers added to each delivery POST. Values are encrypted at rest and no read returns one, so a read shows the name and a fingerprint of the value. */
29922
29922
  headers?: {
29923
29923
  /** @description The header name, as configured. */
29924
29924
  key?: string;
29925
- /** @description A masked view of the configured value: the first 8 characters followed by "..." when the value is at least 24 characters long, and a fixed "********" for anything shorter. The full value is never returned; the header name is what identifies which credential is configured. */
29926
- value_prefix?: string;
29925
+ /** @description A 8-character keyed fingerprint of the configured value. It carries no part of the value and no indication of its length, but it is not a zero-disclosure field: it is deterministic, so two headers in your account with the same fingerprint hold the same value, and a changed fingerprint means a changed value. Use it to confirm a rotation took effect, or to tell whether two of your webhooks carry the same credential. Fingerprints are scoped to your account and are not comparable with another account's. Null for a header configured before fingerprints existed. The header name is what identifies which credential is configured. */
29926
+ value_fingerprint?: string | null;
29927
29927
  }[];
29928
29928
  /** @description Canonical event names this webhook subscribes to. */
29929
29929
  events?: string[];
@@ -30196,12 +30196,12 @@ export interface operations {
30196
30196
  account_ids?: string[];
30197
30197
  /** @description A disabled webhook is kept but delivers nothing. Disabling takes effect immediately, including for retries that were already queued; those attempts are abandoned, not deferred, so re-enabling delivers new events rather than replaying the ones that were dropped. */
30198
30198
  enabled?: boolean;
30199
- /** @description Custom headers added to each delivery POST. Values are encrypted at rest, so a read shows the name and a masked value only. */
30199
+ /** @description Custom headers added to each delivery POST. Values are encrypted at rest and no read returns one, so a read shows the name and a fingerprint of the value. */
30200
30200
  headers?: {
30201
30201
  /** @description The header name, as configured. */
30202
30202
  key?: string;
30203
- /** @description A masked view of the configured value: the first 8 characters followed by "..." when the value is at least 24 characters long, and a fixed "********" for anything shorter. The full value is never returned; the header name is what identifies which credential is configured. */
30204
- value_prefix?: string;
30203
+ /** @description A 8-character keyed fingerprint of the configured value. It carries no part of the value and no indication of its length, but it is not a zero-disclosure field: it is deterministic, so two headers in your account with the same fingerprint hold the same value, and a changed fingerprint means a changed value. Use it to confirm a rotation took effect, or to tell whether two of your webhooks carry the same credential. Fingerprints are scoped to your account and are not comparable with another account's. Null for a header configured before fingerprints existed. The header name is what identifies which credential is configured. */
30204
+ value_fingerprint?: string | null;
30205
30205
  }[];
30206
30206
  /** @description Canonical event names this webhook subscribes to. */
30207
30207
  events?: string[];
@@ -30350,7 +30350,7 @@ export interface operations {
30350
30350
  name?: string | null;
30351
30351
  /** @description Enable or disable the webhook. A disabled webhook delivers nothing. Disabling is a stop, not a pause: it takes effect immediately, including for retries that were already queued, and those attempts are abandoned rather than deferred, so re-enabling delivers new events instead of replaying the ones that were dropped. */
30352
30352
  enabled?: boolean;
30353
- /** @description Replace the custom headers added to each delivery POST (whole-array). Names must be valid HTTP header names and values must be printable ASCII (no line breaks or control characters). Reserved names are rejected at registration; they include Content-Type, User-Agent, Host, any Curviate-* or Sec-* name, and the hop-by-hop headers. At most 10 headers, 1024 characters per value, 4096 bytes in total. Custom headers are not covered by the delivery signature, so treat them as a hint, not as proof of origin. Values are encrypted at rest and are never returned by a read. A read shows the header name plus a masked value: the first 8 characters followed by "..." when the value is at least 24 characters long, and a fixed "********" for anything shorter, so a short value is never disclosed by its own preview. The header name is what identifies which credential is configured. */
30353
+ /** @description Replace the custom headers added to each delivery POST (whole-array). Names must be valid HTTP header names and values must be printable ASCII (no line breaks or control characters). Reserved names are rejected at registration; they include Content-Type, User-Agent, Host, any Curviate-* or Sec-* name, and the hop-by-hop headers. At most 10 headers, 1024 characters per value, 4096 bytes in total. Custom headers are not covered by the delivery signature, so treat them as a hint, not as proof of origin. Values are encrypted at rest and are never returned by a read. A read shows the header name plus a 8-character keyed fingerprint of the value, which carries no part of the value and no indication of its length. It is deterministic within your account, so a fingerprint confirms a rotation took effect and tells you whether two of your webhooks carry the same credential; fingerprints are not comparable across accounts. The header name is what identifies which credential is configured. */
30354
30354
  headers?: {
30355
30355
  key: string;
30356
30356
  value: string;
@@ -30392,12 +30392,12 @@ export interface operations {
30392
30392
  account_ids?: string[];
30393
30393
  /** @description A disabled webhook is kept but delivers nothing. Disabling takes effect immediately, including for retries that were already queued; those attempts are abandoned, not deferred, so re-enabling delivers new events rather than replaying the ones that were dropped. */
30394
30394
  enabled?: boolean;
30395
- /** @description Custom headers added to each delivery POST. Values are encrypted at rest, so a read shows the name and a masked value only. */
30395
+ /** @description Custom headers added to each delivery POST. Values are encrypted at rest and no read returns one, so a read shows the name and a fingerprint of the value. */
30396
30396
  headers?: {
30397
30397
  /** @description The header name, as configured. */
30398
30398
  key?: string;
30399
- /** @description A masked view of the configured value: the first 8 characters followed by "..." when the value is at least 24 characters long, and a fixed "********" for anything shorter. The full value is never returned; the header name is what identifies which credential is configured. */
30400
- value_prefix?: string;
30399
+ /** @description A 8-character keyed fingerprint of the configured value. It carries no part of the value and no indication of its length, but it is not a zero-disclosure field: it is deterministic, so two headers in your account with the same fingerprint hold the same value, and a changed fingerprint means a changed value. Use it to confirm a rotation took effect, or to tell whether two of your webhooks carry the same credential. Fingerprints are scoped to your account and are not comparable with another account's. Null for a header configured before fingerprints existed. The header name is what identifies which credential is configured. */
30400
+ value_fingerprint?: string | null;
30401
30401
  }[];
30402
30402
  /** @description Canonical event names this webhook subscribes to. */
30403
30403
  events?: string[];
@@ -30504,13 +30504,13 @@ export interface operations {
30504
30504
  */
30505
30505
  limit_profile?: "basic" | "premium" | "sales_navigator" | "recruiter";
30506
30506
  /**
30507
- * @description Where `limit_profile` came from. `detected`: Curviate read it from LinkedIn, at `limit_profile_detected_at`. `operator`: it was set through this operation and holds until the account next connects, or until you send `limit_profile_source: "default"` on this operation, which releases it. `default`: it has never been observed, so the value is the seeded `basic` and says nothing about the account; Curviate detects it on the account's next read or connect.
30507
+ * @description Where `limit_profile` came from. `detected`: Curviate read it from LinkedIn, at `limit_profile_detected_at`. `operator`: it was set through this operation and holds until you release it by sending `limit_profile_source: "default"` on this operation, on its own (changing `limit_profile` and releasing it in the same request is refused). Nothing else overrides it: a connect, a reconnect and an account read all leave a pinned value exactly as you set it. `default`: it has never been observed, so the value is the seeded `basic` and says nothing about the account; Curviate detects it on the account's next read or connect.
30508
30508
  * @enum {string}
30509
30509
  */
30510
30510
  limit_profile_source?: "default" | "detected" | "operator";
30511
30511
  /**
30512
30512
  * Format: date-time
30513
- * @description When Curviate last read `limit_profile` from LinkedIn, whether or not the value changed. Null until it has. Curviate re-reads it on connect and, at most once a day, on an account read, so a subscription change reaches the numbers without a reconnect.
30513
+ * @description When Curviate last read `limit_profile` from LinkedIn, whether or not the value changed. Null until it has. Curviate re-reads it on connect and, at most once a day, on an account read, so a subscription change reaches the numbers without a reconnect. While `limit_profile_source` is `operator` neither the value nor this timestamp moves, until you release the pin.
30514
30514
  */
30515
30515
  limit_profile_detected_at?: string | null;
30516
30516
  /**
@@ -30674,7 +30674,7 @@ export interface operations {
30674
30674
  content: {
30675
30675
  "application/json": {
30676
30676
  /**
30677
- * @description Which set of Curviate defaults this account's rows resolve from: `basic`, `premium`, `sales_navigator` or `recruiter`. Each inherits the one before it and raises a few rows. This is the platform product active on the account, NOT the Curviate seat entitlement, and the two can disagree: a lapsed subscription leaves the seat untouched. Curviate detects it from the platform when the account connects, re-detects it on every reconnect and, at most once a day, on an account read; setting it here is an operator override of that result and holds until the next connect. To undo the override, send `limit_profile_source: "default"`: the pin is released, and Curviate re-reads the value from LinkedIn on the account's next read or connect. Sending the value the account already holds changes nothing and pins nothing. The change is recorded in the ledger and it moves the defaults under every row at once, so any row you have configured explicitly keeps your value. The elevated Sales Navigator and Recruiter figures apply only to calls made through the matching interface, the Sales Navigator and Recruiter operations, and Curviate holds each call to the figure for the interface it goes through. The numbers here are therefore the ones a standard-interface call is held to, on every profile; a call through one of those operations resolves from the elevated set instead, and each row publishes that figure as `interface_ceiling`.
30677
+ * @description Which set of Curviate defaults this account's rows resolve from: `basic`, `premium`, `sales_navigator` or `recruiter`. Each inherits the one before it and raises a few rows. This is the platform product active on the account, NOT the Curviate seat entitlement, and the two can disagree: a lapsed subscription leaves the seat untouched. Curviate detects it from the platform when the account connects, re-detects it on every reconnect and, at most once a day, on an account read; setting it here pins it, and the pin wins over detection from then on. None of those paths moves a pinned value, so it holds until you release it. To release the pin, send `limit_profile_source: "default"` on its own: Curviate re-reads the value from LinkedIn on the account's next read or connect. Changing `limit_profile` and releasing it in the same request is refused with `INVALID_REQUEST`, because those are opposite intents. Sending the value the account already holds changes nothing and pins nothing. The change is recorded in the ledger and it moves the defaults under every row at once, so any row you have configured explicitly keeps your value. The elevated Sales Navigator and Recruiter figures apply only to calls made through the matching interface, the Sales Navigator and Recruiter operations, and Curviate holds each call to the figure for the interface it goes through. The numbers here are therefore the ones a standard-interface call is held to, on every profile; a call through one of those operations resolves from the elevated set instead, and each row publishes that figure as `interface_ceiling`.
30678
30678
  * @enum {string}
30679
30679
  */
30680
30680
  limit_profile?: "basic" | "premium" | "sales_navigator" | "recruiter";
@@ -30764,7 +30764,7 @@ export interface operations {
30764
30764
  /** @description READ-ONLY. The account this document describes; the path names it. Sent back on a write it is accepted and ignored, so the whole document round-trips; it is never stored and never ledgered. */
30765
30765
  account_id?: unknown;
30766
30766
  /**
30767
- * @description Where `limit_profile` came from: `default` (never observed), `detected` (read from LinkedIn) or `operator` (set through this operation). Sending `default` releases an operator override: the value is re-read from LinkedIn on the account's next read or connect. Sending `detected` or `operator` is accepted and ignored, so the whole document round-trips.
30767
+ * @description Where `limit_profile` came from: `default` (never observed), `detected` (read from LinkedIn) or `operator` (pinned through this operation, and nothing but a release moves it). Sending `default` releases a pin: the value is re-read from LinkedIn on the account's next read or connect. Send it on its own; changing `limit_profile` in the same request is refused. Sending `detected` or `operator` is accepted and ignored, so the whole document round-trips.
30768
30768
  * @enum {string}
30769
30769
  */
30770
30770
  limit_profile_source?: "default" | "detected" | "operator";
@@ -30802,13 +30802,13 @@ export interface operations {
30802
30802
  */
30803
30803
  limit_profile?: "basic" | "premium" | "sales_navigator" | "recruiter";
30804
30804
  /**
30805
- * @description Where `limit_profile` came from. `detected`: Curviate read it from LinkedIn, at `limit_profile_detected_at`. `operator`: it was set through this operation and holds until the account next connects, or until you send `limit_profile_source: "default"` on this operation, which releases it. `default`: it has never been observed, so the value is the seeded `basic` and says nothing about the account; Curviate detects it on the account's next read or connect.
30805
+ * @description Where `limit_profile` came from. `detected`: Curviate read it from LinkedIn, at `limit_profile_detected_at`. `operator`: it was set through this operation and holds until you release it by sending `limit_profile_source: "default"` on this operation, on its own (changing `limit_profile` and releasing it in the same request is refused). Nothing else overrides it: a connect, a reconnect and an account read all leave a pinned value exactly as you set it. `default`: it has never been observed, so the value is the seeded `basic` and says nothing about the account; Curviate detects it on the account's next read or connect.
30806
30806
  * @enum {string}
30807
30807
  */
30808
30808
  limit_profile_source?: "default" | "detected" | "operator";
30809
30809
  /**
30810
30810
  * Format: date-time
30811
- * @description When Curviate last read `limit_profile` from LinkedIn, whether or not the value changed. Null until it has. Curviate re-reads it on connect and, at most once a day, on an account read, so a subscription change reaches the numbers without a reconnect.
30811
+ * @description When Curviate last read `limit_profile` from LinkedIn, whether or not the value changed. Null until it has. Curviate re-reads it on connect and, at most once a day, on an account read, so a subscription change reaches the numbers without a reconnect. While `limit_profile_source` is `operator` neither the value nor this timestamp moves, until you release the pin.
30812
30812
  */
30813
30813
  limit_profile_detected_at?: string | null;
30814
30814
  /**