@curviate/sdk 0.26.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,117 @@ Versioning: semantic. Minor for additive changes, patch for bug fixes; no stabil
7
7
 
8
8
  ---
9
9
 
10
+ ## [0.28.0] - 2026-09-07
11
+
12
+ Fixture regenerated against the deployed staging document
13
+ (`https://api.staging.curviate.com`, `server_git_sha 14fa8234...`, 125 paths).
14
+ **BREAKING**: `messaging.searchChats` now rejects a `query` shorter than 3
15
+ characters server-side. Pre-1.0 a breaking change ships as a minor, so a caret
16
+ range on `0.27.x` will not pick this up.
17
+
18
+ ### BREAKING
19
+
20
+ - **`searchChats` requires a `query` of at least 3 characters.** A 1-2 character
21
+ term previously returned `200`; it now returns `400 INVALID_REQUEST` with a
22
+ message naming the minimum. The search is served from an index built out of
23
+ overlapping 3-character sequences, so a shorter term cannot use it at all and
24
+ falls back to a scan: measured at 238-292 ms against 4.5 ms for the same term
25
+ one character longer. Returning `200` after 60x the work, with no way for a
26
+ caller to learn why, was the worse contract.
27
+
28
+ The bound is now expressed in the OpenAPI schema (`minLength: 3`) and in the
29
+ generated parameter description. **TypeScript cannot express a string minimum
30
+ length**, so the generated type is still `string`: the constraint is
31
+ documented and enforced at the wire, not by the compiler. Debounce a
32
+ type-ahead to 3 characters rather than relying on types to catch it.
33
+
34
+ `companies.searchChats` is a different endpoint and is unaffected; its
35
+ `query` stays optional and unbounded.
36
+
37
+ ### Added
38
+
39
+ - **`accounts.retrieve` gains `event_log`**: `{ retained, row_cap, at_row_cap }`.
40
+ Reports where the account stands against the retained event log's per-account
41
+ row budget. While `at_row_cap` is true, events are still delivered to any
42
+ registered webhook but are no longer retained, so the events resource has
43
+ stopped being a complete record of what arrived. Additive and always present.
44
+
45
+ - Every string parameter and body field on the surface now publishes its real
46
+ length bounds (`minLength` / `maxLength`) where the server enforces one. This
47
+ was previously emitted only for numbers, so string constraints existed in
48
+ descriptions and nowhere a generated client could read them.
49
+
50
+ ---
51
+
52
+ ## [0.27.0] - 2026-09-06
53
+
54
+ Fixture regenerated against the deployed production document
55
+ (`https://api.curviate.com`, `server_git_sha 2a86542f...`, 125 paths).
56
+ **BREAKING**: the `message.delivered` webhook event is gone from the catalogue,
57
+ from `CurviateEvent`, and from the events a subscription can be created with.
58
+ Everything else here is additive or description-only. Pre-1.0 a breaking change
59
+ ships as a minor, so a caret range on `0.26.x` will not pick this up.
60
+
61
+ ### BREAKING
62
+
63
+ - **`message.delivered` is removed from the webhook event catalogue.** The
64
+ platform never emitted it, so no `event.event === 'message.delivered'` branch
65
+ has ever run: the event was subscribable and undeliverable. Two surfaces lose
66
+ the member.
67
+ - `CurviateEvent` (hand-written, `src/webhooks.ts`) drops its
68
+ `{ event: "message.delivered"; data: MessagePayload }` arm, going from 25
69
+ arms to 24. A `switch` on `event.event` that still lists it stops
70
+ compiling, and that arm was dead code in every build it ever shipped in.
71
+ - The generated create-events enum, `events` on the `messaging` variant of
72
+ the `POST /v1/webhooks` request body
73
+ (`operations["postV1Webhooks"]["requestBody"]`), goes from 8 members to 7.
74
+ Passing `"message.delivered"` to a create call is now a type error, and the
75
+ server rejects the value.
76
+
77
+ The two are pinned to each other by an exact two-way type equality in
78
+ `test/webhooks.constructEvent.test.ts`, so they cannot drift apart: that pin
79
+ is what failed first on this regeneration.
80
+
81
+ `GET /v1/webhooks/events` now reports 27 events, messaging 7, where it
82
+ reported 28 and 8.
83
+
84
+ **The read path is untyped and deliberately unaffected.** `events` on a
85
+ webhook returned by `GET /v1/webhooks` or `GET /v1/webhooks/{id}` is
86
+ `string[]`, not the create enum. A subscription created before 2026-09-06 may
87
+ still echo `message.delivered` in its stored `events` until the server-side
88
+ cleanup migration lands; it was never delivered. Reading such a subscription
89
+ back therefore neither breaks a build nor throws, and no migration is
90
+ required of a consumer that only lists webhooks.
91
+
92
+ **The replacement is a read, not an event**: `is_delivered` on the message
93
+ resource.
94
+
95
+ ### Regenerated types
96
+
97
+ - **BREAKING for an exhaustive `switch` - `notices[].code` gains
98
+ `EXPANSION_WITHHELD_CEILING`.** On the same ten chat and message reads that
99
+ accept `expand=public_identifier`, alongside `EXPANSION_LIMIT_REACHED` and
100
+ `EXPANSION_WITHHELD_ACTIVITY_WINDOW`. The expansion was withheld because the
101
+ account is at an account-safety ceiling, not because the page ran out of
102
+ lookup budget and not because the account is outside its activity window.
103
+ Same consequence for the reader as its two siblings, `public_identifier` is
104
+ `null` for a reason that is not "no public profile", and a different remedy,
105
+ which is why it is a separate code rather than a reuse. Additive on the wire:
106
+ only a `switch` with a `never`-typed default arm stops compiling.
107
+ - Description-only, no type change:
108
+ - `SafetyWarning` now states that `hint.message` is the one field whose text
109
+ differs from the `BUDGET_EXHAUSTED` refusal. On a warn-posture ceiling
110
+ breach it says the action went through and how far past the ceiling the row
111
+ now stands, rather than telling the caller what was refused. The shape is
112
+ unchanged, so no branch moves; the string is longer and more specific.
113
+ - The `502` response documents that `retry_likely_to_succeed` is what
114
+ separates its two cases: a temporary upstream error is worth retrying, an
115
+ upstream response that could not be interpreted is not, and the latter
116
+ carries `retry_hint: {"kind": "never"}`. No new field, and the SDK's own
117
+ retry set is unchanged in this release.
118
+ - The `notices` description on the ten expansion reads now lists the ceiling
119
+ case as a third reason a person can go unresolved.
120
+
10
121
  ## [0.26.0] - 2026-09-06
11
122
 
12
123
  Fixture regenerated against the deployed production document
package/dist/index.d.ts CHANGED
@@ -2611,7 +2611,7 @@ interface paths {
2611
2611
  };
2612
2612
  /**
2613
2613
  * List webhook event types
2614
- * @description Returns the complete canonical event catalogue (28 events) grouped by source: messaging (8), user (2), account_status (15), plus 3 tier-gated events. A local catalogue read: no platform call is made.
2614
+ * @description Returns the complete canonical event catalogue (27 events) grouped by source: messaging (7), user (2), account_status (15), plus 3 tier-gated events. A local catalogue read: no platform call is made.
2615
2615
  */
2616
2616
  get: operations["getV1WebhooksEvents"];
2617
2617
  put?: never;
@@ -2689,7 +2689,7 @@ interface paths {
2689
2689
  head?: never;
2690
2690
  /**
2691
2691
  * Update an account's safety policy
2692
- * @description The single safety-policy write. 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 Curviate default. 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. When the seat and the detected product disagree, the detected product wins the numbers and the read reports the disagreement as `seat_tier_mismatch`.
2692
+ * @description The single safety-policy write. 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 Curviate default. 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. When the seat and the detected product disagree, the detected product wins the numbers and the read reports the disagreement as `seat_tier_mismatch`. 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.
2693
2693
  */
2694
2694
  patch: operations["patchV1AccountIdSafetyPolicy"];
2695
2695
  trace?: never;
@@ -2703,7 +2703,7 @@ interface paths {
2703
2703
  };
2704
2704
  /**
2705
2705
  * List what Curviate refused or warned about
2706
- * @description Returns this account's safety events, newest first: every action Curviate refused, and every action it let through while flagging that a limit had been crossed. Under the default posture nothing is refused, so everything here is a warning and `blocked` is how you tell the two apart. Each event names the budget row that breached, why, the operation that hit it and when. Filter by `budget_row` for one action type and by `since` / `until` for a period, and page until `cursor` is null. This is a read of what already happened, so it never changes a limit or a count: to change what is refused, update the safety policy. The account resource is the other half of the picture, reporting where each row stands right now rather than what has already been flagged.
2706
+ * @description Returns this account's safety events, newest first: every action Curviate refused, and every action it let through while flagging that a limit had been crossed. Under the default posture nothing is refused, so everything here is a warning and `blocked` is how you tell the two apart. Each event names the budget row that breached, why, the operation that hit it and when. Filter by `budget_row` for one action type and by `since` / `until` for a period, and page until `cursor` is null. This is a read of what already happened, so it never changes a limit or a count: to change what is refused, update the safety policy. The account resource is the other half of the picture, reporting where each row stands right now rather than what has already been flagged. One entry here is not a refusal: `reason: "halt_cleared"` with `blocked: false` records somebody lifting a platform pause early through `clear_halts` on the safety policy, and it sits beside the `rate_limited` entry it lifted so the pause and its end read as one thread.
2707
2707
  */
2708
2708
  get: operations["getV1AccountIdSafetyEvents"];
2709
2709
  put?: never;
@@ -2799,13 +2799,13 @@ interface components {
2799
2799
  }[];
2800
2800
  };
2801
2801
  /**
2802
- * @description Present on a successful response when this account crossed an account-safety ceiling while the affected budget row is on the default warn posture. The action still happened. Field-identical to the BUDGET_EXHAUSTED error body except that blocked is false, so one branch handles both postures and switching the account to enforce is a configuration change rather than a client rewrite.
2802
+ * @description Present on a successful response when this account crossed an account-safety ceiling while the affected budget row is on the default warn posture. The action still happened. Field-identical to the BUDGET_EXHAUSTED error body except that blocked is false and hint.message describes the outcome, so one branch handles both postures and switching the account to enforce is a configuration change rather than a client rewrite.
2803
2803
  * @example {
2804
2804
  * "row": "profile_views",
2805
2805
  * "reset_at": "2026-09-05T00:00:00.000Z",
2806
2806
  * "hint": {
2807
2807
  * "parameter": "profile_views.ceiling",
2808
- * "message": "This account is at its configured ceiling for profile_views."
2808
+ * "message": "This account is at its ceiling for profile_views. This action went through because profile_views.posture is warn, and it counted: 101 of 100 this window. Raise profile_views.ceiling, or wait for the window to reset at 2026-09-05T00:00:00.000Z."
2809
2809
  * },
2810
2810
  * "reason": "ceiling",
2811
2811
  * "blocked": false
@@ -2819,7 +2819,7 @@ interface components {
2819
2819
  hint: {
2820
2820
  /** @description The settable parameter on PATCH /v1/{account_id}/safety-policy. */
2821
2821
  parameter: string;
2822
- /** @description What the condition is and what changing that parameter would do. */
2822
+ /** @description What the condition is and what changing that parameter would do. This is the one field whose text differs from the BUDGET_EXHAUSTED refusal: here it says the action went through, and on a ceiling breach how far past the ceiling this row now stands, rather than telling you to set posture to warn when it already is. Branch on parameter, reason and blocked, never on this text. */
2823
2823
  message: string;
2824
2824
  };
2825
2825
  /**
@@ -6806,13 +6806,13 @@ interface operations {
6806
6806
  }[];
6807
6807
  /** @description Opaque cursor for the next page, or null at end-of-list. */
6808
6808
  cursor: string | null;
6809
- /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, or the account is outside its activity window at this hour and enforces it. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
6809
+ /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, the account is outside its activity window at this hour and enforces it, or the account's profile_views budget is at its configured ceiling and enforces that. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
6810
6810
  notices?: {
6811
6811
  /**
6812
- * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy.
6812
+ * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy. EXPANSION_WITHHELD_CEILING: the profile lookups this page needed were refused because the account's profile_views budget is at its configured ceiling and it enforces that, so those people carry public_identifier null and their null does not mean they have no public profile either. Raise the profile_views ceiling on this account's safety policy, or ask for a smaller page.
6813
6813
  * @enum {string}
6814
6814
  */
6815
- code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW";
6815
+ code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW" | "EXPANSION_WITHHELD_CEILING";
6816
6816
  /** @description One sentence explaining the condition and how to resolve it. */
6817
6817
  message: string;
6818
6818
  /** @description The request field the notice is about, here expand. */
@@ -6989,13 +6989,13 @@ interface operations {
6989
6989
  /** @description Message body (content pass-through, never stored). */
6990
6990
  text?: string | null;
6991
6991
  } | null;
6992
- /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, or the account is outside its activity window at this hour and enforces it. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
6992
+ /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, the account is outside its activity window at this hour and enforces it, or the account's profile_views budget is at its configured ceiling and enforces that. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
6993
6993
  notices?: {
6994
6994
  /**
6995
- * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy.
6995
+ * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy. EXPANSION_WITHHELD_CEILING: the profile lookups this page needed were refused because the account's profile_views budget is at its configured ceiling and it enforces that, so those people carry public_identifier null and their null does not mean they have no public profile either. Raise the profile_views ceiling on this account's safety policy, or ask for a smaller page.
6996
6996
  * @enum {string}
6997
6997
  */
6998
- code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW";
6998
+ code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW" | "EXPANSION_WITHHELD_CEILING";
6999
6999
  /** @description One sentence explaining the condition and how to resolve it. */
7000
7000
  message: string;
7001
7001
  /** @description The request field the notice is about, here expand. */
@@ -7165,13 +7165,13 @@ interface operations {
7165
7165
  }[];
7166
7166
  /** @description Opaque cursor for the next page, or null at end-of-list. */
7167
7167
  cursor: string | null;
7168
- /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, or the account is outside its activity window at this hour and enforces it. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
7168
+ /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, the account is outside its activity window at this hour and enforces it, or the account's profile_views budget is at its configured ceiling and enforces that. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
7169
7169
  notices?: {
7170
7170
  /**
7171
- * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy.
7171
+ * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy. EXPANSION_WITHHELD_CEILING: the profile lookups this page needed were refused because the account's profile_views budget is at its configured ceiling and it enforces that, so those people carry public_identifier null and their null does not mean they have no public profile either. Raise the profile_views ceiling on this account's safety policy, or ask for a smaller page.
7172
7172
  * @enum {string}
7173
7173
  */
7174
- code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW";
7174
+ code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW" | "EXPANSION_WITHHELD_CEILING";
7175
7175
  /** @description One sentence explaining the condition and how to resolve it. */
7176
7176
  message: string;
7177
7177
  /** @description The request field the notice is about, here expand. */
@@ -7508,13 +7508,13 @@ interface operations {
7508
7508
  sent_at: number;
7509
7509
  /** @description Message body (content pass-through, never stored). */
7510
7510
  text?: string | null;
7511
- /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, or the account is outside its activity window at this hour and enforces it. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
7511
+ /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, the account is outside its activity window at this hour and enforces it, or the account's profile_views budget is at its configured ceiling and enforces that. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
7512
7512
  notices?: {
7513
7513
  /**
7514
- * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy.
7514
+ * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy. EXPANSION_WITHHELD_CEILING: the profile lookups this page needed were refused because the account's profile_views budget is at its configured ceiling and it enforces that, so those people carry public_identifier null and their null does not mean they have no public profile either. Raise the profile_views ceiling on this account's safety policy, or ask for a smaller page.
7515
7515
  * @enum {string}
7516
7516
  */
7517
- code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW";
7517
+ code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW" | "EXPANSION_WITHHELD_CEILING";
7518
7518
  /** @description One sentence explaining the condition and how to resolve it. */
7519
7519
  message: string;
7520
7520
  /** @description The request field the notice is about, here expand. */
@@ -7714,13 +7714,13 @@ interface operations {
7714
7714
  * @enum {boolean}
7715
7715
  */
7716
7716
  filter_effective?: true;
7717
- /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, or the account is outside its activity window at this hour and enforces it. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
7717
+ /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, the account is outside its activity window at this hour and enforces it, or the account's profile_views budget is at its configured ceiling and enforces that. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
7718
7718
  notices?: {
7719
7719
  /**
7720
- * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy.
7720
+ * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy. EXPANSION_WITHHELD_CEILING: the profile lookups this page needed were refused because the account's profile_views budget is at its configured ceiling and it enforces that, so those people carry public_identifier null and their null does not mean they have no public profile either. Raise the profile_views ceiling on this account's safety policy, or ask for a smaller page.
7721
7721
  * @enum {string}
7722
7722
  */
7723
- code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW";
7723
+ code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW" | "EXPANSION_WITHHELD_CEILING";
7724
7724
  /** @description One sentence explaining the condition and how to resolve it. */
7725
7725
  message: string;
7726
7726
  /** @description The request field the notice is about, here expand. */
@@ -10361,13 +10361,13 @@ interface operations {
10361
10361
  }[];
10362
10362
  /** @description Next-page cursor; follow until items is empty (presence is not a has-more guarantee). */
10363
10363
  cursor?: string | null;
10364
- /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, or the account is outside its activity window at this hour and enforces it. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
10364
+ /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, the account is outside its activity window at this hour and enforces it, or the account's profile_views budget is at its configured ceiling and enforces that. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
10365
10365
  notices?: {
10366
10366
  /**
10367
- * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy.
10367
+ * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy. EXPANSION_WITHHELD_CEILING: the profile lookups this page needed were refused because the account's profile_views budget is at its configured ceiling and it enforces that, so those people carry public_identifier null and their null does not mean they have no public profile either. Raise the profile_views ceiling on this account's safety policy, or ask for a smaller page.
10368
10368
  * @enum {string}
10369
10369
  */
10370
- code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW";
10370
+ code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW" | "EXPANSION_WITHHELD_CEILING";
10371
10371
  /** @description One sentence explaining the condition and how to resolve it. */
10372
10372
  message: string;
10373
10373
  /** @description The request field the notice is about, here expand. */
@@ -10783,13 +10783,13 @@ interface operations {
10783
10783
  /** @description The vanity slug from the profile URL, for example jane-smith. Present only when the request asks for it with expand=public_identifier, and then always present, carrying the slug or null when the platform surfaces none for this person. */
10784
10784
  public_identifier?: string | null;
10785
10785
  };
10786
- /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, or the account is outside its activity window at this hour and enforces it. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
10786
+ /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, the account is outside its activity window at this hour and enforces it, or the account's profile_views budget is at its configured ceiling and enforces that. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
10787
10787
  notices?: {
10788
10788
  /**
10789
- * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy.
10789
+ * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy. EXPANSION_WITHHELD_CEILING: the profile lookups this page needed were refused because the account's profile_views budget is at its configured ceiling and it enforces that, so those people carry public_identifier null and their null does not mean they have no public profile either. Raise the profile_views ceiling on this account's safety policy, or ask for a smaller page.
10790
10790
  * @enum {string}
10791
10791
  */
10792
- code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW";
10792
+ code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW" | "EXPANSION_WITHHELD_CEILING";
10793
10793
  /** @description One sentence explaining the condition and how to resolve it. */
10794
10794
  message: string;
10795
10795
  /** @description The request field the notice is about, here expand. */
@@ -11143,13 +11143,13 @@ interface operations {
11143
11143
  }[];
11144
11144
  /** @description Next-page cursor; follow until items is empty. */
11145
11145
  cursor?: string | null;
11146
- /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, or the account is outside its activity window at this hour and enforces it. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
11146
+ /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, the account is outside its activity window at this hour and enforces it, or the account's profile_views budget is at its configured ceiling and enforces that. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
11147
11147
  notices?: {
11148
11148
  /**
11149
- * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy.
11149
+ * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy. EXPANSION_WITHHELD_CEILING: the profile lookups this page needed were refused because the account's profile_views budget is at its configured ceiling and it enforces that, so those people carry public_identifier null and their null does not mean they have no public profile either. Raise the profile_views ceiling on this account's safety policy, or ask for a smaller page.
11150
11150
  * @enum {string}
11151
11151
  */
11152
- code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW";
11152
+ code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW" | "EXPANSION_WITHHELD_CEILING";
11153
11153
  /** @description One sentence explaining the condition and how to resolve it. */
11154
11154
  message: string;
11155
11155
  /** @description The request field the notice is about, here expand. */
@@ -11519,13 +11519,13 @@ interface operations {
11519
11519
  [key: string]: unknown;
11520
11520
  };
11521
11521
  };
11522
- /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, or the account is outside its activity window at this hour and enforces it. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
11522
+ /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, the account is outside its activity window at this hour and enforces it, or the account's profile_views budget is at its configured ceiling and enforces that. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
11523
11523
  notices?: {
11524
11524
  /**
11525
- * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy.
11525
+ * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy. EXPANSION_WITHHELD_CEILING: the profile lookups this page needed were refused because the account's profile_views budget is at its configured ceiling and it enforces that, so those people carry public_identifier null and their null does not mean they have no public profile either. Raise the profile_views ceiling on this account's safety policy, or ask for a smaller page.
11526
11526
  * @enum {string}
11527
11527
  */
11528
- code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW";
11528
+ code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW" | "EXPANSION_WITHHELD_CEILING";
11529
11529
  /** @description One sentence explaining the condition and how to resolve it. */
11530
11530
  message: string;
11531
11531
  /** @description The request field the notice is about, here expand. */
@@ -12096,7 +12096,7 @@ interface operations {
12096
12096
  getV1AccountIdChatsSearch: {
12097
12097
  parameters: {
12098
12098
  query: {
12099
- /** @description The search term: matches both participant names and message content (e.g. 'sophie keller'). Terms of 3 or more characters are fast; a 1-2 character term is slower. */
12099
+ /** @description The search term: matches both participant names and message content (e.g. 'sophie keller'). Minimum 3 characters. A shorter term cannot use the search index and is rejected with INVALID_REQUEST. */
12100
12100
  query: string;
12101
12101
  /** @description Maximum chats to return per page (1-100, default 20). The server may walk a few internal pages to fill one page. */
12102
12102
  limit?: number;
@@ -12725,13 +12725,13 @@ interface operations {
12725
12725
  }[];
12726
12726
  /** @description Next-page cursor. Follow until items is empty. */
12727
12727
  cursor?: string | null;
12728
- /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, or the account is outside its activity window at this hour and enforces it. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
12728
+ /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, the account is outside its activity window at this hour and enforces it, or the account's profile_views budget is at its configured ceiling and enforces that. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
12729
12729
  notices?: {
12730
12730
  /**
12731
- * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy.
12731
+ * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy. EXPANSION_WITHHELD_CEILING: the profile lookups this page needed were refused because the account's profile_views budget is at its configured ceiling and it enforces that, so those people carry public_identifier null and their null does not mean they have no public profile either. Raise the profile_views ceiling on this account's safety policy, or ask for a smaller page.
12732
12732
  * @enum {string}
12733
12733
  */
12734
- code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW";
12734
+ code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW" | "EXPANSION_WITHHELD_CEILING";
12735
12735
  /** @description One sentence explaining the condition and how to resolve it. */
12736
12736
  message: string;
12737
12737
  /** @description The request field the notice is about, here expand. */
@@ -12985,7 +12985,7 @@ interface operations {
12985
12985
  "application/json": components["schemas"]["Error"];
12986
12986
  };
12987
12987
  };
12988
- /** @description A temporary upstream error occurred, or the upstream response could not be interpreted. Please try again. */
12988
+ /** @description A temporary upstream error occurred, or the upstream response could not be interpreted. Check `retry_likely_to_succeed`: a temporary error is worth retrying, a response that could not be interpreted is not, and carries `retry_hint: {"kind": "never"}`. */
12989
12989
  502: {
12990
12990
  headers: {
12991
12991
  [name: string]: unknown;
@@ -27899,7 +27899,7 @@ interface operations {
27899
27899
  };
27900
27900
  requestBody?: never;
27901
27901
  responses: {
27902
- /** @description The account's metadata and current state, including the quotas[] budget view (one entry per counted action row for this account, for the current window of that row's grain) account_states[], the platform conditions the account is currently in, and activity_window, the hours in which live writes are reported or refused. */
27902
+ /** @description The account's metadata and current state, including the quotas[] budget view (one entry per counted action row for this account, for the current window of that row's grain) account_states[], the platform conditions the account is currently in, activity_window, the hours in which live writes are reported or refused, and event_log, where the account stands against the retained event log's row budget. */
27903
27903
  200: {
27904
27904
  headers: {
27905
27905
  "RateLimit-Policy": components["headers"]["RateLimit-Policy"];
@@ -27972,7 +27972,7 @@ interface operations {
27972
27972
  posture: "warn" | "enforce";
27973
27973
  /** @description Whether something on this row is configured above Curviate's own default. The safety policy carries the detail: which field, the value, the default and how well calibrated that default is. */
27974
27974
  over_default: boolean;
27975
- /** @description An active pause on this row because the platform refused a recent request on it, or `null`. A halt is not a ceiling: no limit you raise lifts it, and it clears itself when it expires. */
27975
+ /** @description An active pause on this row because the platform refused a recent request on it, or `null`. A halt is not a ceiling: no limit you raise lifts it, and it clears itself when it expires. To lift one before it expires, send this row in `clear_halts` on `PATCH /v1/{account_id}/safety-policy`; that is recorded, and the pause returns if the platform refuses the account again. */
27976
27976
  halt: {
27977
27977
  /** @description What the platform did: `rate_limited`, `platform_fault`, or `resend_cooldown` (the same invitation was sent too recently). */
27978
27978
  reason?: string;
@@ -27999,6 +27999,15 @@ interface operations {
27999
27999
  /** @description True when no zone is set, which DISABLES the activity window. Curviate never guesses a zone: a guess eight hours wrong inverts the window, refusing every daytime write and permitting every nocturnal one. If you configured a window and it never fires, this is why. */
28000
28000
  timezone_unset?: boolean;
28001
28001
  };
28002
+ /** @description Where this account stands against the retained event log's row budget. Events are retained for 24 hours so you can read what the platform sent without running a listener; an account may hold at most row_cap of them at once. While at_row_cap is true, further events for this account are still delivered to any webhook you registered but are NOT retained, so the events resource stops being a complete record of what arrived. The budget is a backstop against a misbehaving upstream, sized so ordinary use never approaches it. */
28003
+ event_log?: {
28004
+ /** @description Events currently held for this account. A level, not a total: retention is 24 hours, so this falls on its own as events age out. */
28005
+ retained?: number;
28006
+ /** @description The maximum this account may hold at once. */
28007
+ row_cap?: number;
28008
+ /** @description True while the cap is biting and incoming events are not being retained. Delivery to a registered webhook is unaffected. */
28009
+ at_row_cap?: boolean;
28010
+ };
28002
28011
  safety_warning?: components["schemas"]["SafetyWarning"];
28003
28012
  };
28004
28013
  };
@@ -29753,7 +29762,7 @@ interface operations {
29753
29762
  value: string;
29754
29763
  }[];
29755
29764
  /** @description Messaging events to subscribe to (default: [message.received]) */
29756
- events?: ("message.received" | "message.delivered" | "message.read" | "message.reaction" | "message.edited" | "message.deleted" | "chat.updated" | "chat.deleted")[];
29765
+ events?: ("message.received" | "message.read" | "message.reaction" | "message.edited" | "message.deleted" | "chat.updated" | "chat.deleted")[];
29757
29766
  /**
29758
29767
  * @description Field-remapping keys for the messaging delivery payload
29759
29768
  * @default []
@@ -30514,7 +30523,7 @@ interface operations {
30514
30523
  /** @description IANA zone name the activity window is read in. Null disables the window entirely. */
30515
30524
  activity_window_timezone?: string | null;
30516
30525
  /**
30517
- * @description What the activity window governs. `writes` (the default) covers live writes to LinkedIn; `all` widens it to live reads as well, which is the setting for a persona that should not be seen browsing at 03:00. It is broader than it sounds: `all` covers every live read, including the ones about the account itself, so a nightly analytics or invitation-backlog poll is refused at 03:00 too. A read Curviate answers from its own store never reaches LinkedIn, so it is never subject to the window under either setting, at any hour; the same read IS covered when the store cannot answer it, or when you ask for it live. Inbound events are never subject to it either.
30526
+ * @description What the activity window governs. `writes` (the default) covers live writes to LinkedIn; `all` widens it to live reads as well, which is the setting for a persona that should not be seen browsing at 03:00. It is broader than it sounds: `all` covers every live read, including the ones about the account itself, so a nightly analytics or invitation-backlog poll is refused at 03:00 too. A read Curviate answers from its own store never reaches LinkedIn, so it is never subject to the window under either setting, at any hour; the same read IS covered when the store cannot answer it, or when you ask for it live. Inbound events are never subject to it either. One action set to `all` reaches the whole account's live reads that spend no budget of their own (notifications, profile analytics, SSI, profile visitors, the invitation and saved-list listings): those calls debit no action type, so they have none to read this setting from and take the account-wide answer instead. Reads that DO debit an action type read that action type's own setting.
30518
30527
  * @enum {string}
30519
30528
  */
30520
30529
  activity_window_applies_to?: "writes" | "all";
@@ -30612,6 +30621,8 @@ interface operations {
30612
30621
  * @enum {string|null}
30613
30622
  */
30614
30623
  tenant_default_posture?: "warn" | "enforce" | null;
30624
+ /** @description Lift the platform pause on these action types now, instead of waiting for it to expire. When the platform refuses a call on an account (a rate limit, a server error on a budgeted route, an invitation resend cooldown), 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. Naming an action type here clears that pause: the next call goes out. Read `quotas[].halt` on the account to see which action types are paused and for how long. A type with no active pause is accepted and does nothing, so this is safe to send for a set you have not checked. Clearing is recorded in the account's ledger with the expiry it cut short, who cleared it and when, and it appears on the safety-events surface. It does not disarm anything: if the platform refuses the account again, the pause comes straight back, longer than the one you cleared where the platform says so. Clear a pause when you have reason to believe the refusal was a transient upstream fault rather than the platform pushing back on this account; clearing one and calling straight back into a real rate limit is itself how accounts get restricted. */
30625
+ clear_halts?: ("connection_requests_with_note" | "connection_requests_no_note" | "messages_first_degree" | "inmail" | "open_profile_inmail" | "profile_views" | "search" | "comments" | "post_likes" | "follows" | "content_poll" | "job_poll" | "posts" | "endorsements" | "invite_responses" | "withdrawal_sweep")[];
30615
30626
  /**
30616
30627
  * @description This account's posture default, overriding the tenant default for this account only. Null clears the override.
30617
30628
  * @enum {string|null}
@@ -30651,7 +30662,7 @@ interface operations {
30651
30662
  /** @description IANA zone name the activity window is read in, e.g. `Europe/Berlin`. Must be a real zone; anything else is a 400. Null DISABLES the activity window: a guessed zone inverts it, which is worse than not having one. */
30652
30663
  activity_window_timezone?: string | null;
30653
30664
  /**
30654
- * @description What the activity window governs. `writes` (the default) covers live writes to LinkedIn; `all` widens it to live reads. A read Curviate answers from its own store never reaches LinkedIn and so is never covered; the same read IS covered when the store cannot answer it, or when you ask for it live. Stored reads and inbound events are never subject to the window under either setting, at any hour.
30665
+ * @description What the activity window governs. `writes` (the default) covers live writes to LinkedIn; `all` widens it to live reads. A read Curviate answers from its own store never reaches LinkedIn and so is never covered; the same read IS covered when the store cannot answer it, or when you ask for it live. Stored reads and inbound events are never subject to the window under either setting, at any hour. One action set to `all` reaches the whole account's live reads that spend no budget of their own (notifications, profile analytics, SSI, profile visitors, the invitation and saved-list listings): those calls debit no action type, so they have none to read this setting from and take the account-wide answer instead. Reads that DO debit an action type read that action type's own setting.
30655
30666
  * @enum {string|null}
30656
30667
  */
30657
30668
  activity_window_applies_to?: "writes" | "all" | null;
@@ -30800,7 +30811,7 @@ interface operations {
30800
30811
  /** @description IANA zone name the activity window is read in. Null disables the window entirely. */
30801
30812
  activity_window_timezone?: string | null;
30802
30813
  /**
30803
- * @description What the activity window governs. `writes` (the default) covers live writes to LinkedIn; `all` widens it to live reads as well, which is the setting for a persona that should not be seen browsing at 03:00. It is broader than it sounds: `all` covers every live read, including the ones about the account itself, so a nightly analytics or invitation-backlog poll is refused at 03:00 too. A read Curviate answers from its own store never reaches LinkedIn, so it is never subject to the window under either setting, at any hour; the same read IS covered when the store cannot answer it, or when you ask for it live. Inbound events are never subject to it either.
30814
+ * @description What the activity window governs. `writes` (the default) covers live writes to LinkedIn; `all` widens it to live reads as well, which is the setting for a persona that should not be seen browsing at 03:00. It is broader than it sounds: `all` covers every live read, including the ones about the account itself, so a nightly analytics or invitation-backlog poll is refused at 03:00 too. A read Curviate answers from its own store never reaches LinkedIn, so it is never subject to the window under either setting, at any hour; the same read IS covered when the store cannot answer it, or when you ask for it live. Inbound events are never subject to it either. One action set to `all` reaches the whole account's live reads that spend no budget of their own (notifications, profile analytics, SSI, profile visitors, the invitation and saved-list listings): those calls debit no action type, so they have none to read this setting from and take the account-wide answer instead. Reads that DO debit an action type read that action type's own setting.
30804
30815
  * @enum {string}
30805
30816
  */
30806
30817
  activity_window_applies_to?: "writes" | "all";
@@ -30943,11 +30954,11 @@ interface operations {
30943
30954
  */
30944
30955
  budget_row: "connection_requests_with_note" | "connection_requests_no_note" | "messages_first_degree" | "inmail" | "open_profile_inmail" | "profile_views" | "search" | "comments" | "post_likes" | "follows" | "content_poll" | "job_poll" | "posts" | "endorsements" | "invite_responses" | "withdrawal_sweep" | "total_actions" | "pending_invites" | "*";
30945
30956
  /**
30946
- * @description Which rule flagged it, and each one calls for a different response. `budget_exhausted`: the account reached the ceiling configured for that row, which you can raise on the safety policy. `activity_window`: the account was acting outside its configured activity window, so no ceiling was the constraint. Wait for the window to open, move `activity_window_start` or `activity_window_end`, or check `activity_window_timezone` is the zone you meant. `rate_limited`: the platform itself refused this account on that row recently and Curviate is holding the row until the pause expires, which no configuration change lifts.
30957
+ * @description Which rule flagged it, and each one calls for a different response. `budget_exhausted`: the account reached the ceiling configured for that row, which you can raise on the safety policy. `activity_window`: the account was acting outside its configured activity window, so no ceiling was the constraint. Wait for the window to open, move `activity_window_start` or `activity_window_end`, or check `activity_window_timezone` is the zone you meant. `rate_limited`: the platform itself refused this account on that row recently and Curviate is holding the row until the pause expires. No ceiling you raise lifts it; the one thing that does is `clear_halts` on the safety policy, which lifts it deliberately and records that it was lifted. `halt_cleared` is the odd one out and the only entry that is not a refusal: somebody lifted one of those platform pauses early through `clear_halts` on the safety policy, so the row was open again from that instant. It carries `blocked: false` and its `method` is `update_safety_policy` rather than the operation that breached. Read it beside the `rate_limited` entry it lifts: the pause and its lifting are one thread, and an entry list that showed only the first would report a row as still paused.
30947
30958
  * @enum {string}
30948
30959
  */
30949
- reason: "budget_exhausted" | "activity_window" | "rate_limited";
30950
- /** @description Whether the action was stopped. `false` is a warning: the action went through, and this record is the only lasting trace that it crossed a limit. Under the default `warn` posture every event is a warning, which is what makes reading this surface the point of running it. */
30960
+ reason: "budget_exhausted" | "activity_window" | "rate_limited" | "halt_cleared";
30961
+ /** @description Whether the action was stopped. `false` is a warning: the action went through, and this record is the only lasting trace that it crossed a limit. Under the default `warn` posture every event is a warning, which is what makes reading this surface the point of running it. A `halt_cleared` entry is also `false`, for a different reason: it stopped nothing, it lifted a stop. */
30951
30962
  blocked: boolean;
30952
30963
  /** @description The operation the caller was running when it breached. */
30953
30964
  method: string;
@@ -33440,6 +33451,10 @@ interface CurviateEventEnvelope {
33440
33451
  * the generated create-events enum (see `test/webhooks.constructEvent.test.ts`);
33441
33452
  * it must never drift from the served catalogue again.
33442
33453
  *
33454
+ * > Removed in 0.27.0 (BREAKING): `message.delivered`. The platform never
33455
+ * > emitted it, so no `event.event === 'message.delivered'` branch has ever
33456
+ * > run. The read-path replacement is `is_delivered` on the message resource.
33457
+ *
33443
33458
  * @example
33444
33459
  * const event = await constructEvent(rawBody, header, secret);
33445
33460
  * if (event.event === 'message.received') {
@@ -33449,9 +33464,6 @@ interface CurviateEventEnvelope {
33449
33464
  type CurviateEvent = CurviateEventEnvelope & ({
33450
33465
  event: "message.received";
33451
33466
  data: MessagePayload;
33452
- } | {
33453
- event: "message.delivered";
33454
- data: MessagePayload;
33455
33467
  } | {
33456
33468
  event: "message.read";
33457
33469
  data: MessagePayload;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@curviate/sdk",
3
- "version": "0.26.0",
3
+ "version": "0.28.0",
4
4
  "private": false,
5
5
  "description": "TypeScript SDK for the Curviate API.",
6
6
  "license": "MIT",
@@ -2513,7 +2513,7 @@ export interface paths {
2513
2513
  };
2514
2514
  /**
2515
2515
  * List webhook event types
2516
- * @description Returns the complete canonical event catalogue (28 events) grouped by source: messaging (8), user (2), account_status (15), plus 3 tier-gated events. A local catalogue read: no platform call is made.
2516
+ * @description Returns the complete canonical event catalogue (27 events) grouped by source: messaging (7), user (2), account_status (15), plus 3 tier-gated events. A local catalogue read: no platform call is made.
2517
2517
  */
2518
2518
  get: operations["getV1WebhooksEvents"];
2519
2519
  put?: never;
@@ -2591,7 +2591,7 @@ export interface paths {
2591
2591
  head?: never;
2592
2592
  /**
2593
2593
  * Update an account's safety policy
2594
- * @description The single safety-policy write. 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 Curviate default. 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. When the seat and the detected product disagree, the detected product wins the numbers and the read reports the disagreement as `seat_tier_mismatch`.
2594
+ * @description The single safety-policy write. 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 Curviate default. 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. When the seat and the detected product disagree, the detected product wins the numbers and the read reports the disagreement as `seat_tier_mismatch`. 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.
2595
2595
  */
2596
2596
  patch: operations["patchV1AccountIdSafetyPolicy"];
2597
2597
  trace?: never;
@@ -2605,7 +2605,7 @@ export interface paths {
2605
2605
  };
2606
2606
  /**
2607
2607
  * List what Curviate refused or warned about
2608
- * @description Returns this account's safety events, newest first: every action Curviate refused, and every action it let through while flagging that a limit had been crossed. Under the default posture nothing is refused, so everything here is a warning and `blocked` is how you tell the two apart. Each event names the budget row that breached, why, the operation that hit it and when. Filter by `budget_row` for one action type and by `since` / `until` for a period, and page until `cursor` is null. This is a read of what already happened, so it never changes a limit or a count: to change what is refused, update the safety policy. The account resource is the other half of the picture, reporting where each row stands right now rather than what has already been flagged.
2608
+ * @description Returns this account's safety events, newest first: every action Curviate refused, and every action it let through while flagging that a limit had been crossed. Under the default posture nothing is refused, so everything here is a warning and `blocked` is how you tell the two apart. Each event names the budget row that breached, why, the operation that hit it and when. Filter by `budget_row` for one action type and by `since` / `until` for a period, and page until `cursor` is null. This is a read of what already happened, so it never changes a limit or a count: to change what is refused, update the safety policy. The account resource is the other half of the picture, reporting where each row stands right now rather than what has already been flagged. One entry here is not a refusal: `reason: "halt_cleared"` with `blocked: false` records somebody lifting a platform pause early through `clear_halts` on the safety policy, and it sits beside the `rate_limited` entry it lifted so the pause and its end read as one thread.
2609
2609
  */
2610
2610
  get: operations["getV1AccountIdSafetyEvents"];
2611
2611
  put?: never;
@@ -2702,13 +2702,13 @@ export interface components {
2702
2702
  }[];
2703
2703
  };
2704
2704
  /**
2705
- * @description Present on a successful response when this account crossed an account-safety ceiling while the affected budget row is on the default warn posture. The action still happened. Field-identical to the BUDGET_EXHAUSTED error body except that blocked is false, so one branch handles both postures and switching the account to enforce is a configuration change rather than a client rewrite.
2705
+ * @description Present on a successful response when this account crossed an account-safety ceiling while the affected budget row is on the default warn posture. The action still happened. Field-identical to the BUDGET_EXHAUSTED error body except that blocked is false and hint.message describes the outcome, so one branch handles both postures and switching the account to enforce is a configuration change rather than a client rewrite.
2706
2706
  * @example {
2707
2707
  * "row": "profile_views",
2708
2708
  * "reset_at": "2026-09-05T00:00:00.000Z",
2709
2709
  * "hint": {
2710
2710
  * "parameter": "profile_views.ceiling",
2711
- * "message": "This account is at its configured ceiling for profile_views."
2711
+ * "message": "This account is at its ceiling for profile_views. This action went through because profile_views.posture is warn, and it counted: 101 of 100 this window. Raise profile_views.ceiling, or wait for the window to reset at 2026-09-05T00:00:00.000Z."
2712
2712
  * },
2713
2713
  * "reason": "ceiling",
2714
2714
  * "blocked": false
@@ -2722,7 +2722,7 @@ export interface components {
2722
2722
  hint: {
2723
2723
  /** @description The settable parameter on PATCH /v1/{account_id}/safety-policy. */
2724
2724
  parameter: string;
2725
- /** @description What the condition is and what changing that parameter would do. */
2725
+ /** @description What the condition is and what changing that parameter would do. This is the one field whose text differs from the BUDGET_EXHAUSTED refusal: here it says the action went through, and on a ceiling breach how far past the ceiling this row now stands, rather than telling you to set posture to warn when it already is. Branch on parameter, reason and blocked, never on this text. */
2726
2726
  message: string;
2727
2727
  };
2728
2728
  /**
@@ -6710,13 +6710,13 @@ export interface operations {
6710
6710
  }[];
6711
6711
  /** @description Opaque cursor for the next page, or null at end-of-list. */
6712
6712
  cursor: string | null;
6713
- /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, or the account is outside its activity window at this hour and enforces it. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
6713
+ /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, the account is outside its activity window at this hour and enforces it, or the account's profile_views budget is at its configured ceiling and enforces that. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
6714
6714
  notices?: {
6715
6715
  /**
6716
- * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy.
6716
+ * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy. EXPANSION_WITHHELD_CEILING: the profile lookups this page needed were refused because the account's profile_views budget is at its configured ceiling and it enforces that, so those people carry public_identifier null and their null does not mean they have no public profile either. Raise the profile_views ceiling on this account's safety policy, or ask for a smaller page.
6717
6717
  * @enum {string}
6718
6718
  */
6719
- code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW";
6719
+ code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW" | "EXPANSION_WITHHELD_CEILING";
6720
6720
  /** @description One sentence explaining the condition and how to resolve it. */
6721
6721
  message: string;
6722
6722
  /** @description The request field the notice is about, here expand. */
@@ -6893,13 +6893,13 @@ export interface operations {
6893
6893
  /** @description Message body (content pass-through, never stored). */
6894
6894
  text?: string | null;
6895
6895
  } | null;
6896
- /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, or the account is outside its activity window at this hour and enforces it. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
6896
+ /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, the account is outside its activity window at this hour and enforces it, or the account's profile_views budget is at its configured ceiling and enforces that. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
6897
6897
  notices?: {
6898
6898
  /**
6899
- * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy.
6899
+ * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy. EXPANSION_WITHHELD_CEILING: the profile lookups this page needed were refused because the account's profile_views budget is at its configured ceiling and it enforces that, so those people carry public_identifier null and their null does not mean they have no public profile either. Raise the profile_views ceiling on this account's safety policy, or ask for a smaller page.
6900
6900
  * @enum {string}
6901
6901
  */
6902
- code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW";
6902
+ code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW" | "EXPANSION_WITHHELD_CEILING";
6903
6903
  /** @description One sentence explaining the condition and how to resolve it. */
6904
6904
  message: string;
6905
6905
  /** @description The request field the notice is about, here expand. */
@@ -7069,13 +7069,13 @@ export interface operations {
7069
7069
  }[];
7070
7070
  /** @description Opaque cursor for the next page, or null at end-of-list. */
7071
7071
  cursor: string | null;
7072
- /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, or the account is outside its activity window at this hour and enforces it. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
7072
+ /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, the account is outside its activity window at this hour and enforces it, or the account's profile_views budget is at its configured ceiling and enforces that. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
7073
7073
  notices?: {
7074
7074
  /**
7075
- * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy.
7075
+ * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy. EXPANSION_WITHHELD_CEILING: the profile lookups this page needed were refused because the account's profile_views budget is at its configured ceiling and it enforces that, so those people carry public_identifier null and their null does not mean they have no public profile either. Raise the profile_views ceiling on this account's safety policy, or ask for a smaller page.
7076
7076
  * @enum {string}
7077
7077
  */
7078
- code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW";
7078
+ code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW" | "EXPANSION_WITHHELD_CEILING";
7079
7079
  /** @description One sentence explaining the condition and how to resolve it. */
7080
7080
  message: string;
7081
7081
  /** @description The request field the notice is about, here expand. */
@@ -7412,13 +7412,13 @@ export interface operations {
7412
7412
  sent_at: number;
7413
7413
  /** @description Message body (content pass-through, never stored). */
7414
7414
  text?: string | null;
7415
- /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, or the account is outside its activity window at this hour and enforces it. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
7415
+ /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, the account is outside its activity window at this hour and enforces it, or the account's profile_views budget is at its configured ceiling and enforces that. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
7416
7416
  notices?: {
7417
7417
  /**
7418
- * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy.
7418
+ * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy. EXPANSION_WITHHELD_CEILING: the profile lookups this page needed were refused because the account's profile_views budget is at its configured ceiling and it enforces that, so those people carry public_identifier null and their null does not mean they have no public profile either. Raise the profile_views ceiling on this account's safety policy, or ask for a smaller page.
7419
7419
  * @enum {string}
7420
7420
  */
7421
- code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW";
7421
+ code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW" | "EXPANSION_WITHHELD_CEILING";
7422
7422
  /** @description One sentence explaining the condition and how to resolve it. */
7423
7423
  message: string;
7424
7424
  /** @description The request field the notice is about, here expand. */
@@ -7618,13 +7618,13 @@ export interface operations {
7618
7618
  * @enum {boolean}
7619
7619
  */
7620
7620
  filter_effective?: true;
7621
- /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, or the account is outside its activity window at this hour and enforces it. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
7621
+ /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, the account is outside its activity window at this hour and enforces it, or the account's profile_views budget is at its configured ceiling and enforces that. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
7622
7622
  notices?: {
7623
7623
  /**
7624
- * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy.
7624
+ * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy. EXPANSION_WITHHELD_CEILING: the profile lookups this page needed were refused because the account's profile_views budget is at its configured ceiling and it enforces that, so those people carry public_identifier null and their null does not mean they have no public profile either. Raise the profile_views ceiling on this account's safety policy, or ask for a smaller page.
7625
7625
  * @enum {string}
7626
7626
  */
7627
- code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW";
7627
+ code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW" | "EXPANSION_WITHHELD_CEILING";
7628
7628
  /** @description One sentence explaining the condition and how to resolve it. */
7629
7629
  message: string;
7630
7630
  /** @description The request field the notice is about, here expand. */
@@ -10265,13 +10265,13 @@ export interface operations {
10265
10265
  }[];
10266
10266
  /** @description Next-page cursor; follow until items is empty (presence is not a has-more guarantee). */
10267
10267
  cursor?: string | null;
10268
- /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, or the account is outside its activity window at this hour and enforces it. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
10268
+ /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, the account is outside its activity window at this hour and enforces it, or the account's profile_views budget is at its configured ceiling and enforces that. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
10269
10269
  notices?: {
10270
10270
  /**
10271
- * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy.
10271
+ * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy. EXPANSION_WITHHELD_CEILING: the profile lookups this page needed were refused because the account's profile_views budget is at its configured ceiling and it enforces that, so those people carry public_identifier null and their null does not mean they have no public profile either. Raise the profile_views ceiling on this account's safety policy, or ask for a smaller page.
10272
10272
  * @enum {string}
10273
10273
  */
10274
- code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW";
10274
+ code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW" | "EXPANSION_WITHHELD_CEILING";
10275
10275
  /** @description One sentence explaining the condition and how to resolve it. */
10276
10276
  message: string;
10277
10277
  /** @description The request field the notice is about, here expand. */
@@ -10687,13 +10687,13 @@ export interface operations {
10687
10687
  /** @description The vanity slug from the profile URL, for example jane-smith. Present only when the request asks for it with expand=public_identifier, and then always present, carrying the slug or null when the platform surfaces none for this person. */
10688
10688
  public_identifier?: string | null;
10689
10689
  };
10690
- /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, or the account is outside its activity window at this hour and enforces it. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
10690
+ /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, the account is outside its activity window at this hour and enforces it, or the account's profile_views budget is at its configured ceiling and enforces that. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
10691
10691
  notices?: {
10692
10692
  /**
10693
- * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy.
10693
+ * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy. EXPANSION_WITHHELD_CEILING: the profile lookups this page needed were refused because the account's profile_views budget is at its configured ceiling and it enforces that, so those people carry public_identifier null and their null does not mean they have no public profile either. Raise the profile_views ceiling on this account's safety policy, or ask for a smaller page.
10694
10694
  * @enum {string}
10695
10695
  */
10696
- code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW";
10696
+ code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW" | "EXPANSION_WITHHELD_CEILING";
10697
10697
  /** @description One sentence explaining the condition and how to resolve it. */
10698
10698
  message: string;
10699
10699
  /** @description The request field the notice is about, here expand. */
@@ -11047,13 +11047,13 @@ export interface operations {
11047
11047
  }[];
11048
11048
  /** @description Next-page cursor; follow until items is empty. */
11049
11049
  cursor?: string | null;
11050
- /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, or the account is outside its activity window at this hour and enforces it. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
11050
+ /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, the account is outside its activity window at this hour and enforces it, or the account's profile_views budget is at its configured ceiling and enforces that. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
11051
11051
  notices?: {
11052
11052
  /**
11053
- * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy.
11053
+ * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy. EXPANSION_WITHHELD_CEILING: the profile lookups this page needed were refused because the account's profile_views budget is at its configured ceiling and it enforces that, so those people carry public_identifier null and their null does not mean they have no public profile either. Raise the profile_views ceiling on this account's safety policy, or ask for a smaller page.
11054
11054
  * @enum {string}
11055
11055
  */
11056
- code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW";
11056
+ code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW" | "EXPANSION_WITHHELD_CEILING";
11057
11057
  /** @description One sentence explaining the condition and how to resolve it. */
11058
11058
  message: string;
11059
11059
  /** @description The request field the notice is about, here expand. */
@@ -11423,13 +11423,13 @@ export interface operations {
11423
11423
  [key: string]: unknown;
11424
11424
  };
11425
11425
  };
11426
- /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, or the account is outside its activity window at this hour and enforces it. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
11426
+ /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, the account is outside its activity window at this hour and enforces it, or the account's profile_views budget is at its configured ceiling and enforces that. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
11427
11427
  notices?: {
11428
11428
  /**
11429
- * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy.
11429
+ * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy. EXPANSION_WITHHELD_CEILING: the profile lookups this page needed were refused because the account's profile_views budget is at its configured ceiling and it enforces that, so those people carry public_identifier null and their null does not mean they have no public profile either. Raise the profile_views ceiling on this account's safety policy, or ask for a smaller page.
11430
11430
  * @enum {string}
11431
11431
  */
11432
- code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW";
11432
+ code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW" | "EXPANSION_WITHHELD_CEILING";
11433
11433
  /** @description One sentence explaining the condition and how to resolve it. */
11434
11434
  message: string;
11435
11435
  /** @description The request field the notice is about, here expand. */
@@ -12000,7 +12000,7 @@ export interface operations {
12000
12000
  getV1AccountIdChatsSearch: {
12001
12001
  parameters: {
12002
12002
  query: {
12003
- /** @description The search term: matches both participant names and message content (e.g. 'sophie keller'). Terms of 3 or more characters are fast; a 1-2 character term is slower. */
12003
+ /** @description The search term: matches both participant names and message content (e.g. 'sophie keller'). Minimum 3 characters. A shorter term cannot use the search index and is rejected with INVALID_REQUEST. */
12004
12004
  query: string;
12005
12005
  /** @description Maximum chats to return per page (1-100, default 20). The server may walk a few internal pages to fill one page. */
12006
12006
  limit?: number;
@@ -12629,13 +12629,13 @@ export interface operations {
12629
12629
  }[];
12630
12630
  /** @description Next-page cursor. Follow until items is empty. */
12631
12631
  cursor?: string | null;
12632
- /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, or the account is outside its activity window at this hour and enforces it. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
12632
+ /** @description Present only when expand=public_identifier was asked for and some people on this page went unresolved for a reason the payload cannot show: more of them needed a profile lookup than one request performs, the account is outside its activity window at this hour and enforces it, or the account's profile_views budget is at its configured ceiling and enforces that. Absent whenever there is nothing to report, so a response that resolved everyone carries no such key. Branch on each entry's code, never on its message. */
12633
12633
  notices?: {
12634
12634
  /**
12635
- * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy.
12635
+ * @description EXPANSION_LIMIT_REACHED: more people on this page needed a profile lookup than one request performs, so the ones past the budget carry public_identifier null without ever having been looked up. Their null therefore does not mean the person has no public profile. Ask for a smaller page to resolve everyone. EXPANSION_WITHHELD_ACTIVITY_WINDOW: the profile lookups this page needed were refused because the account is outside its activity window at this hour and enforces it, so those people carry public_identifier null and their null does not mean they have no public profile either. Ask again inside the window, or widen the window on this account's safety policy. EXPANSION_WITHHELD_CEILING: the profile lookups this page needed were refused because the account's profile_views budget is at its configured ceiling and it enforces that, so those people carry public_identifier null and their null does not mean they have no public profile either. Raise the profile_views ceiling on this account's safety policy, or ask for a smaller page.
12636
12636
  * @enum {string}
12637
12637
  */
12638
- code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW";
12638
+ code: "EXPANSION_LIMIT_REACHED" | "EXPANSION_WITHHELD_ACTIVITY_WINDOW" | "EXPANSION_WITHHELD_CEILING";
12639
12639
  /** @description One sentence explaining the condition and how to resolve it. */
12640
12640
  message: string;
12641
12641
  /** @description The request field the notice is about, here expand. */
@@ -12889,7 +12889,7 @@ export interface operations {
12889
12889
  "application/json": components["schemas"]["Error"];
12890
12890
  };
12891
12891
  };
12892
- /** @description A temporary upstream error occurred, or the upstream response could not be interpreted. Please try again. */
12892
+ /** @description A temporary upstream error occurred, or the upstream response could not be interpreted. Check `retry_likely_to_succeed`: a temporary error is worth retrying, a response that could not be interpreted is not, and carries `retry_hint: {"kind": "never"}`. */
12893
12893
  502: {
12894
12894
  headers: {
12895
12895
  [name: string]: unknown;
@@ -27803,7 +27803,7 @@ export interface operations {
27803
27803
  };
27804
27804
  requestBody?: never;
27805
27805
  responses: {
27806
- /** @description The account's metadata and current state, including the quotas[] budget view (one entry per counted action row for this account, for the current window of that row's grain) account_states[], the platform conditions the account is currently in, and activity_window, the hours in which live writes are reported or refused. */
27806
+ /** @description The account's metadata and current state, including the quotas[] budget view (one entry per counted action row for this account, for the current window of that row's grain) account_states[], the platform conditions the account is currently in, activity_window, the hours in which live writes are reported or refused, and event_log, where the account stands against the retained event log's row budget. */
27807
27807
  200: {
27808
27808
  headers: {
27809
27809
  "RateLimit-Policy": components["headers"]["RateLimit-Policy"];
@@ -27876,7 +27876,7 @@ export interface operations {
27876
27876
  posture: "warn" | "enforce";
27877
27877
  /** @description Whether something on this row is configured above Curviate's own default. The safety policy carries the detail: which field, the value, the default and how well calibrated that default is. */
27878
27878
  over_default: boolean;
27879
- /** @description An active pause on this row because the platform refused a recent request on it, or `null`. A halt is not a ceiling: no limit you raise lifts it, and it clears itself when it expires. */
27879
+ /** @description An active pause on this row because the platform refused a recent request on it, or `null`. A halt is not a ceiling: no limit you raise lifts it, and it clears itself when it expires. To lift one before it expires, send this row in `clear_halts` on `PATCH /v1/{account_id}/safety-policy`; that is recorded, and the pause returns if the platform refuses the account again. */
27880
27880
  halt: {
27881
27881
  /** @description What the platform did: `rate_limited`, `platform_fault`, or `resend_cooldown` (the same invitation was sent too recently). */
27882
27882
  reason?: string;
@@ -27903,6 +27903,15 @@ export interface operations {
27903
27903
  /** @description True when no zone is set, which DISABLES the activity window. Curviate never guesses a zone: a guess eight hours wrong inverts the window, refusing every daytime write and permitting every nocturnal one. If you configured a window and it never fires, this is why. */
27904
27904
  timezone_unset?: boolean;
27905
27905
  };
27906
+ /** @description Where this account stands against the retained event log's row budget. Events are retained for 24 hours so you can read what the platform sent without running a listener; an account may hold at most row_cap of them at once. While at_row_cap is true, further events for this account are still delivered to any webhook you registered but are NOT retained, so the events resource stops being a complete record of what arrived. The budget is a backstop against a misbehaving upstream, sized so ordinary use never approaches it. */
27907
+ event_log?: {
27908
+ /** @description Events currently held for this account. A level, not a total: retention is 24 hours, so this falls on its own as events age out. */
27909
+ retained?: number;
27910
+ /** @description The maximum this account may hold at once. */
27911
+ row_cap?: number;
27912
+ /** @description True while the cap is biting and incoming events are not being retained. Delivery to a registered webhook is unaffected. */
27913
+ at_row_cap?: boolean;
27914
+ };
27906
27915
  safety_warning?: components["schemas"]["SafetyWarning"];
27907
27916
  };
27908
27917
  };
@@ -29657,7 +29666,7 @@ export interface operations {
29657
29666
  value: string;
29658
29667
  }[];
29659
29668
  /** @description Messaging events to subscribe to (default: [message.received]) */
29660
- events?: ("message.received" | "message.delivered" | "message.read" | "message.reaction" | "message.edited" | "message.deleted" | "chat.updated" | "chat.deleted")[];
29669
+ events?: ("message.received" | "message.read" | "message.reaction" | "message.edited" | "message.deleted" | "chat.updated" | "chat.deleted")[];
29661
29670
  /**
29662
29671
  * @description Field-remapping keys for the messaging delivery payload
29663
29672
  * @default []
@@ -30418,7 +30427,7 @@ export interface operations {
30418
30427
  /** @description IANA zone name the activity window is read in. Null disables the window entirely. */
30419
30428
  activity_window_timezone?: string | null;
30420
30429
  /**
30421
- * @description What the activity window governs. `writes` (the default) covers live writes to LinkedIn; `all` widens it to live reads as well, which is the setting for a persona that should not be seen browsing at 03:00. It is broader than it sounds: `all` covers every live read, including the ones about the account itself, so a nightly analytics or invitation-backlog poll is refused at 03:00 too. A read Curviate answers from its own store never reaches LinkedIn, so it is never subject to the window under either setting, at any hour; the same read IS covered when the store cannot answer it, or when you ask for it live. Inbound events are never subject to it either.
30430
+ * @description What the activity window governs. `writes` (the default) covers live writes to LinkedIn; `all` widens it to live reads as well, which is the setting for a persona that should not be seen browsing at 03:00. It is broader than it sounds: `all` covers every live read, including the ones about the account itself, so a nightly analytics or invitation-backlog poll is refused at 03:00 too. A read Curviate answers from its own store never reaches LinkedIn, so it is never subject to the window under either setting, at any hour; the same read IS covered when the store cannot answer it, or when you ask for it live. Inbound events are never subject to it either. One action set to `all` reaches the whole account's live reads that spend no budget of their own (notifications, profile analytics, SSI, profile visitors, the invitation and saved-list listings): those calls debit no action type, so they have none to read this setting from and take the account-wide answer instead. Reads that DO debit an action type read that action type's own setting.
30422
30431
  * @enum {string}
30423
30432
  */
30424
30433
  activity_window_applies_to?: "writes" | "all";
@@ -30516,6 +30525,8 @@ export interface operations {
30516
30525
  * @enum {string|null}
30517
30526
  */
30518
30527
  tenant_default_posture?: "warn" | "enforce" | null;
30528
+ /** @description Lift the platform pause on these action types now, instead of waiting for it to expire. When the platform refuses a call on an account (a rate limit, a server error on a budgeted route, an invitation resend cooldown), 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. Naming an action type here clears that pause: the next call goes out. Read `quotas[].halt` on the account to see which action types are paused and for how long. A type with no active pause is accepted and does nothing, so this is safe to send for a set you have not checked. Clearing is recorded in the account's ledger with the expiry it cut short, who cleared it and when, and it appears on the safety-events surface. It does not disarm anything: if the platform refuses the account again, the pause comes straight back, longer than the one you cleared where the platform says so. Clear a pause when you have reason to believe the refusal was a transient upstream fault rather than the platform pushing back on this account; clearing one and calling straight back into a real rate limit is itself how accounts get restricted. */
30529
+ clear_halts?: ("connection_requests_with_note" | "connection_requests_no_note" | "messages_first_degree" | "inmail" | "open_profile_inmail" | "profile_views" | "search" | "comments" | "post_likes" | "follows" | "content_poll" | "job_poll" | "posts" | "endorsements" | "invite_responses" | "withdrawal_sweep")[];
30519
30530
  /**
30520
30531
  * @description This account's posture default, overriding the tenant default for this account only. Null clears the override.
30521
30532
  * @enum {string|null}
@@ -30555,7 +30566,7 @@ export interface operations {
30555
30566
  /** @description IANA zone name the activity window is read in, e.g. `Europe/Berlin`. Must be a real zone; anything else is a 400. Null DISABLES the activity window: a guessed zone inverts it, which is worse than not having one. */
30556
30567
  activity_window_timezone?: string | null;
30557
30568
  /**
30558
- * @description What the activity window governs. `writes` (the default) covers live writes to LinkedIn; `all` widens it to live reads. A read Curviate answers from its own store never reaches LinkedIn and so is never covered; the same read IS covered when the store cannot answer it, or when you ask for it live. Stored reads and inbound events are never subject to the window under either setting, at any hour.
30569
+ * @description What the activity window governs. `writes` (the default) covers live writes to LinkedIn; `all` widens it to live reads. A read Curviate answers from its own store never reaches LinkedIn and so is never covered; the same read IS covered when the store cannot answer it, or when you ask for it live. Stored reads and inbound events are never subject to the window under either setting, at any hour. One action set to `all` reaches the whole account's live reads that spend no budget of their own (notifications, profile analytics, SSI, profile visitors, the invitation and saved-list listings): those calls debit no action type, so they have none to read this setting from and take the account-wide answer instead. Reads that DO debit an action type read that action type's own setting.
30559
30570
  * @enum {string|null}
30560
30571
  */
30561
30572
  activity_window_applies_to?: "writes" | "all" | null;
@@ -30704,7 +30715,7 @@ export interface operations {
30704
30715
  /** @description IANA zone name the activity window is read in. Null disables the window entirely. */
30705
30716
  activity_window_timezone?: string | null;
30706
30717
  /**
30707
- * @description What the activity window governs. `writes` (the default) covers live writes to LinkedIn; `all` widens it to live reads as well, which is the setting for a persona that should not be seen browsing at 03:00. It is broader than it sounds: `all` covers every live read, including the ones about the account itself, so a nightly analytics or invitation-backlog poll is refused at 03:00 too. A read Curviate answers from its own store never reaches LinkedIn, so it is never subject to the window under either setting, at any hour; the same read IS covered when the store cannot answer it, or when you ask for it live. Inbound events are never subject to it either.
30718
+ * @description What the activity window governs. `writes` (the default) covers live writes to LinkedIn; `all` widens it to live reads as well, which is the setting for a persona that should not be seen browsing at 03:00. It is broader than it sounds: `all` covers every live read, including the ones about the account itself, so a nightly analytics or invitation-backlog poll is refused at 03:00 too. A read Curviate answers from its own store never reaches LinkedIn, so it is never subject to the window under either setting, at any hour; the same read IS covered when the store cannot answer it, or when you ask for it live. Inbound events are never subject to it either. One action set to `all` reaches the whole account's live reads that spend no budget of their own (notifications, profile analytics, SSI, profile visitors, the invitation and saved-list listings): those calls debit no action type, so they have none to read this setting from and take the account-wide answer instead. Reads that DO debit an action type read that action type's own setting.
30708
30719
  * @enum {string}
30709
30720
  */
30710
30721
  activity_window_applies_to?: "writes" | "all";
@@ -30847,11 +30858,11 @@ export interface operations {
30847
30858
  */
30848
30859
  budget_row: "connection_requests_with_note" | "connection_requests_no_note" | "messages_first_degree" | "inmail" | "open_profile_inmail" | "profile_views" | "search" | "comments" | "post_likes" | "follows" | "content_poll" | "job_poll" | "posts" | "endorsements" | "invite_responses" | "withdrawal_sweep" | "total_actions" | "pending_invites" | "*";
30849
30860
  /**
30850
- * @description Which rule flagged it, and each one calls for a different response. `budget_exhausted`: the account reached the ceiling configured for that row, which you can raise on the safety policy. `activity_window`: the account was acting outside its configured activity window, so no ceiling was the constraint. Wait for the window to open, move `activity_window_start` or `activity_window_end`, or check `activity_window_timezone` is the zone you meant. `rate_limited`: the platform itself refused this account on that row recently and Curviate is holding the row until the pause expires, which no configuration change lifts.
30861
+ * @description Which rule flagged it, and each one calls for a different response. `budget_exhausted`: the account reached the ceiling configured for that row, which you can raise on the safety policy. `activity_window`: the account was acting outside its configured activity window, so no ceiling was the constraint. Wait for the window to open, move `activity_window_start` or `activity_window_end`, or check `activity_window_timezone` is the zone you meant. `rate_limited`: the platform itself refused this account on that row recently and Curviate is holding the row until the pause expires. No ceiling you raise lifts it; the one thing that does is `clear_halts` on the safety policy, which lifts it deliberately and records that it was lifted. `halt_cleared` is the odd one out and the only entry that is not a refusal: somebody lifted one of those platform pauses early through `clear_halts` on the safety policy, so the row was open again from that instant. It carries `blocked: false` and its `method` is `update_safety_policy` rather than the operation that breached. Read it beside the `rate_limited` entry it lifts: the pause and its lifting are one thread, and an entry list that showed only the first would report a row as still paused.
30851
30862
  * @enum {string}
30852
30863
  */
30853
- reason: "budget_exhausted" | "activity_window" | "rate_limited";
30854
- /** @description Whether the action was stopped. `false` is a warning: the action went through, and this record is the only lasting trace that it crossed a limit. Under the default `warn` posture every event is a warning, which is what makes reading this surface the point of running it. */
30864
+ reason: "budget_exhausted" | "activity_window" | "rate_limited" | "halt_cleared";
30865
+ /** @description Whether the action was stopped. `false` is a warning: the action went through, and this record is the only lasting trace that it crossed a limit. Under the default `warn` posture every event is a warning, which is what makes reading this surface the point of running it. A `halt_cleared` entry is also `false`, for a different reason: it stopped nothing, it lifted a stop. */
30855
30866
  blocked: boolean;
30856
30867
  /** @description The operation the caller was running when it breached. */
30857
30868
  method: string;