@allisall/sdk 0.2.0 → 0.4.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.
Files changed (40) hide show
  1. package/README.md +5 -2
  2. package/dist/client.d.ts +6 -0
  3. package/dist/client.js +8 -0
  4. package/dist/generated/openapi.d.ts +1820 -47
  5. package/dist/generated/operations.d.ts +6 -1
  6. package/dist/generated/operations.js +191 -0
  7. package/dist/import-mapping.d.ts +10 -0
  8. package/dist/import-mapping.js +20 -0
  9. package/dist/index.d.ts +2 -1
  10. package/dist/index.js +1 -0
  11. package/dist/multipart.d.ts +3 -1
  12. package/dist/request.d.ts +9 -0
  13. package/dist/request.js +43 -3
  14. package/dist/resources/agents.d.ts +7 -0
  15. package/dist/resources/agents.js +7 -0
  16. package/dist/resources/calculations.d.ts +21 -1
  17. package/dist/resources/calculations.js +22 -0
  18. package/dist/resources/clients.d.ts +28 -0
  19. package/dist/resources/clients.js +28 -0
  20. package/dist/resources/cost.d.ts +7 -0
  21. package/dist/resources/cost.js +7 -0
  22. package/dist/resources/dashboard.d.ts +8 -0
  23. package/dist/resources/dashboard.js +8 -0
  24. package/dist/resources/events.d.ts +70 -1
  25. package/dist/resources/events.js +78 -2
  26. package/dist/resources/imports.d.ts +24 -1
  27. package/dist/resources/imports.js +27 -1
  28. package/dist/resources/onboarding.d.ts +29 -0
  29. package/dist/resources/onboarding.js +34 -0
  30. package/dist/resources/reports.d.ts +16 -1
  31. package/dist/resources/reports.js +17 -0
  32. package/dist/resources/value-models.d.ts +7 -0
  33. package/dist/resources/value-models.js +7 -0
  34. package/dist/resources/workspace.d.ts +15 -0
  35. package/dist/resources/workspace.js +18 -0
  36. package/dist/types.d.ts +28 -1
  37. package/dist/types.js +6 -0
  38. package/dist/version.d.ts +1 -1
  39. package/dist/version.js +1 -1
  40. package/package.json +1 -1
@@ -72,7 +72,11 @@ export interface paths {
72
72
  path?: never;
73
73
  cookie?: never;
74
74
  };
75
- get?: never;
75
+ /**
76
+ * List the workspace's events
77
+ * @description Every event in the workspace whose `timestamp` falls in the period, newest first, held still under an arrival limit, `as_of`: the list holds only events the API stored before it. A view's first request sends no `as_of`, and the response issues one. Send it on later requests, or follow `next_cursor`, which carries it, to read the same events while new ones arrive. Pass `page` for a numbered page with its `total`, or `cursor` to continue a walk, not both. `total` counts at most 10,000 events, and `total_capped` says when more matched. In the default order, `timestamp` descending, the cursor is a keyset position. Any other order needs `page`, or a cursor issued in that order, and its cursor is an offset; walk in the default order. Filtered by `import_batch_id`, the period is optional, `as_of` is issued but not applied, and `total` is exact. Otherwise an event appears a second or two after the API stores it, and later while a long request, such as a large import, is still in progress, so a read straight after an ingest may not include it yet.
78
+ */
79
+ get: operations["listEvents"];
76
80
  put?: never;
77
81
  /**
78
82
  * Ingest a batch of events
@@ -85,6 +89,46 @@ export interface paths {
85
89
  patch?: never;
86
90
  trace?: never;
87
91
  };
92
+ "/v1/events/summary": {
93
+ parameters: {
94
+ query?: never;
95
+ header?: never;
96
+ path?: never;
97
+ cookie?: never;
98
+ };
99
+ /**
100
+ * Count the workspace's events per day and per category
101
+ * @description Counts the events `GET /v1/events` holds under the same period, filters and `as_of`: in all, per day and per category. A day is 24 hours counted from `from`, so sending local midnight with its offset as `from` gives local days. The last day is shorter when the period is not a whole number of days. The period is required, also with `import_batch_id`. Without `import_batch_id`, an event is counted a second or two after the API stores it, and later while a long request, such as a large import, is still in progress, so a read straight after an ingest may not count it yet.
102
+ */
103
+ get: operations["getEventSummary"];
104
+ put?: never;
105
+ post?: never;
106
+ delete?: never;
107
+ options?: never;
108
+ head?: never;
109
+ patch?: never;
110
+ trace?: never;
111
+ };
112
+ "/v1/events/arrivals": {
113
+ parameters: {
114
+ query?: never;
115
+ header?: never;
116
+ path?: never;
117
+ cookie?: never;
118
+ };
119
+ /**
120
+ * List the workspace's events as they arrived
121
+ * @description The workspace's events in the order the API stored them, newest first, below an arrival limit, `as_of`, which the response issues. Without `since`, the first page holds the latest arrivals. With `since`, the list holds the events that arrived at or after it, and `count` counts them. To poll, send each response's `as_of` as the next request's `since`: consecutive windows then meet without a gap or an overlap. `from` and `to` filter by `timestamp`, and each is optional on its own. An event falls below `as_of` a second or two after the API stores it, and later while a long request, such as a large import, is still in progress. A read straight after an ingest may not include it yet; poll with `since` until it does.
122
+ */
123
+ get: operations["listEventArrivals"];
124
+ put?: never;
125
+ post?: never;
126
+ delete?: never;
127
+ options?: never;
128
+ head?: never;
129
+ patch?: never;
130
+ trace?: never;
131
+ };
88
132
  "/v1/imports/preview": {
89
133
  parameters: {
90
134
  query?: never;
@@ -112,7 +156,11 @@ export interface paths {
112
156
  path?: never;
113
157
  cookie?: never;
114
158
  };
115
- get?: never;
159
+ /**
160
+ * List imports
161
+ * @description The workspace's CSV imports, newest first, each with its counts. Pass `page` for a numbered page and its `total`, or `cursor` to continue a walk, not both. Read an import for the mapping it ran with.
162
+ */
163
+ get: operations["listImports"];
116
164
  put?: never;
117
165
  /**
118
166
  * Import a CSV file
@@ -125,6 +173,26 @@ export interface paths {
125
173
  patch?: never;
126
174
  trace?: never;
127
175
  };
176
+ "/v1/imports/{id}": {
177
+ parameters: {
178
+ query?: never;
179
+ header?: never;
180
+ path?: never;
181
+ cookie?: never;
182
+ };
183
+ /**
184
+ * Read an import
185
+ * @description One CSV import, with its counts and the mapping it ran with. Send the mapping back as the next import's `mapping` to map a file of the same layout.
186
+ */
187
+ get: operations["getImport"];
188
+ put?: never;
189
+ post?: never;
190
+ delete?: never;
191
+ options?: never;
192
+ head?: never;
193
+ patch?: never;
194
+ trace?: never;
195
+ };
128
196
  "/v1/clients": {
129
197
  parameters: {
130
198
  query?: never;
@@ -132,7 +200,10 @@ export interface paths {
132
200
  path?: never;
133
201
  cookie?: never;
134
202
  };
135
- /** List clients */
203
+ /**
204
+ * List clients
205
+ * @description The workspace's clients. Pass `page` for a numbered page and its `total`, or `cursor` to continue a walk, not both. `q` searches the name.
206
+ */
136
207
  get: operations["listClients"];
137
208
  put?: never;
138
209
  /** Create a client */
@@ -361,7 +432,10 @@ export interface paths {
361
432
  path?: never;
362
433
  cookie?: never;
363
434
  };
364
- /** List agents */
435
+ /**
436
+ * List agents
437
+ * @description The workspace's agents, including those ingest created. Pass `page` for a numbered page and its `total`, or `cursor` to continue a walk, not both. `q` searches the name.
438
+ */
365
439
  get: operations["listAgents"];
366
440
  put?: never;
367
441
  /** Create an agent */
@@ -404,7 +478,10 @@ export interface paths {
404
478
  path?: never;
405
479
  cookie?: never;
406
480
  };
407
- /** List value models */
481
+ /**
482
+ * List value models
483
+ * @description The workspace's value models across clients, archived ones included. Pass `page` for a numbered page and its `total`, or `cursor` to continue a walk, not both. `q` searches the model's own name.
484
+ */
408
485
  get: operations["listValueModels"];
409
486
  put?: never;
410
487
  post?: never;
@@ -475,7 +552,10 @@ export interface paths {
475
552
  path?: never;
476
553
  cookie?: never;
477
554
  };
478
- /** List cost line items */
555
+ /**
556
+ * List cost line items
557
+ * @description The workspace's cost line items. Pass `page` for a numbered page and its `total`, or `cursor` to continue a walk, not both. `q` searches the label.
558
+ */
479
559
  get: operations["listCostLineItems"];
480
560
  put?: never;
481
561
  /** Create a cost line item */
@@ -523,6 +603,26 @@ export interface paths {
523
603
  patch?: never;
524
604
  trace?: never;
525
605
  };
606
+ "/v1/calculations": {
607
+ parameters: {
608
+ query?: never;
609
+ header?: never;
610
+ path?: never;
611
+ cookie?: never;
612
+ };
613
+ /**
614
+ * List calculations
615
+ * @description The workspace's calculations across clients, without snapshots, in the order a client's list uses. Pass `page` for a numbered page and its `total`, or `cursor` to continue a walk, not both. `is_current` is decided among each client's own calculations for the period, before any filter or page applies.
616
+ */
617
+ get: operations["listCalculations"];
618
+ put?: never;
619
+ post?: never;
620
+ delete?: never;
621
+ options?: never;
622
+ head?: never;
623
+ patch?: never;
624
+ trace?: never;
625
+ };
526
626
  "/v1/calculations/{id}": {
527
627
  parameters: {
528
628
  query?: never;
@@ -622,6 +722,26 @@ export interface paths {
622
722
  patch?: never;
623
723
  trace?: never;
624
724
  };
725
+ "/v1/reports": {
726
+ parameters: {
727
+ query?: never;
728
+ header?: never;
729
+ path?: never;
730
+ cookie?: never;
731
+ };
732
+ /**
733
+ * List reports
734
+ * @description The workspace's reports across calculations, newest first, each without its disclosures. Pass `page` for a numbered page and its `total`, or `cursor` to continue a walk, not both.
735
+ */
736
+ get: operations["listReports"];
737
+ put?: never;
738
+ post?: never;
739
+ delete?: never;
740
+ options?: never;
741
+ head?: never;
742
+ patch?: never;
743
+ trace?: never;
744
+ };
625
745
  "/v1/reports/{id}": {
626
746
  parameters: {
627
747
  query?: never;
@@ -710,7 +830,7 @@ export interface paths {
710
830
  };
711
831
  /**
712
832
  * List renewal readiness
713
- * @description Reads each client's latest published figures, whatever month the dashboard shows.
833
+ * @description Lists each active client with a renewal date, with its latest published figures, whatever month the dashboard shows. A client with a renewal term shows its next renewal on or after `today`. Pass `page` for a numbered page and its `total`, or `cursor` to continue a walk, not both; here `page` and the cursor are one offset.
714
834
  */
715
835
  get: operations["listRenewals"];
716
836
  put?: never;
@@ -779,6 +899,110 @@ export interface paths {
779
899
  patch?: never;
780
900
  trace?: never;
781
901
  };
902
+ "/v1/invite": {
903
+ parameters: {
904
+ query?: never;
905
+ header?: never;
906
+ path?: never;
907
+ cookie?: never;
908
+ };
909
+ /**
910
+ * Read the open invite
911
+ * @description Returns the open invite to the signed-in session's email address, so an invitee who signed in can create their workspace without the invite link. It never returns the invite's token. The first call to this operation or to `POST /v1/workspace` with a session for the invited address, within the 24 hours after the invite was sent, records that the address signed in. From then on the invite no longer expires, though its link still does. That call records the sign-in whatever it then answers, except a `400`, `413` or `414`: those refuse a query parameter or a body, which this operation does not take, and record nothing. With no open invite to the address, or a session with no email address, the answer is `404` `not_found`. An open invite whose address did not sign in within its 24 hours is `409` `invite_expired`. A session or address that already belongs to a workspace is `409` `email_has_workspace`. Session-only.
912
+ */
913
+ get: operations["getInvite"];
914
+ put?: never;
915
+ post?: never;
916
+ delete?: never;
917
+ options?: never;
918
+ head?: never;
919
+ patch?: never;
920
+ trace?: never;
921
+ };
922
+ "/v1/invite/redeem": {
923
+ parameters: {
924
+ query?: never;
925
+ header?: never;
926
+ path?: never;
927
+ cookie?: never;
928
+ };
929
+ get?: never;
930
+ put?: never;
931
+ /**
932
+ * Redeem an invite
933
+ * @description Sent when the link in an invite email is opened, with the token from the link as `Authorization: Invite <token>`. Makes sure the invited address can sign in, and returns it with the link's expiry, so the address can be offered for an email-code sign-in. The invite stays usable until a workspace is created with it, so the link may be opened again. The link stops working 24 hours after the invite was sent, even if the address has signed in; an invitee who signed in then reads the invite with `GET /v1/invite` instead. Every response carries `Cache-Control: no-store`. A missing, malformed or unknown token is one indistinguishable `404`. A `409` says which state the invite is in. Takes no request body: any non-empty body, `{}` included and whatever its media type, is refused with `400` `validation_failed`, one error coded `unknown_field` at pointer `""`.
934
+ */
935
+ post: operations["redeemInvite"];
936
+ delete?: never;
937
+ options?: never;
938
+ head?: never;
939
+ patch?: never;
940
+ trace?: never;
941
+ };
942
+ "/v1/workspace": {
943
+ parameters: {
944
+ query?: never;
945
+ header?: never;
946
+ path?: never;
947
+ cookie?: never;
948
+ };
949
+ /**
950
+ * Read the workspace
951
+ * @description The workspace the credential belongs to.
952
+ */
953
+ get: operations["getWorkspace"];
954
+ put?: never;
955
+ /**
956
+ * Create a workspace from an invite
957
+ * @description Creates the signed-in invitee's workspace, with them as its owner, and uses the invite up. The session must be for the address the invite was sent to. Without `invite_token`, the invite is the open invite to the session's address, under the same checks; with no open invite and no workspace for the session, the answer is `403` `account_not_provisioned`. A session whose user has no workspace yet is accepted here and by `GET /v1/invite`, and nowhere else. The first call to either, within the 24 hours after the invite was sent, records that the address signed in, whatever it then answers. The exceptions are a refusal of a query parameter, `400` or `414`, and of a body over the size limit, `413`, which record nothing. From then on the invite no longer expires. One owner has one workspace, so a session that already has one gets `409` `email_has_workspace`. No API key is created. This operation does not take `Idempotency-Key`. A retry after a successful create never creates a second workspace: it gets `409` `invite_used` when it sent `invite_token`, and `409` `email_has_workspace` when it did not. Read `GET /v1/workspace` to see the workspace. Session-only.
958
+ */
959
+ post: operations["createWorkspace"];
960
+ delete?: never;
961
+ options?: never;
962
+ head?: never;
963
+ patch?: never;
964
+ trace?: never;
965
+ };
966
+ "/v1/onboarding": {
967
+ parameters: {
968
+ query?: never;
969
+ header?: never;
970
+ path?: never;
971
+ cookie?: never;
972
+ };
973
+ /**
974
+ * Read the guided setup's progress
975
+ * @description The five setup steps in their fixed order, each with whether the workspace's data completes it and when it was skipped, and `current_step`, the first step neither completed nor skipped. Completion is read from the workspace's data, so finishing a step by any route, such as ingesting events with an API key, completes it.
976
+ */
977
+ get: operations["getOnboarding"];
978
+ put?: never;
979
+ post?: never;
980
+ delete?: never;
981
+ options?: never;
982
+ head?: never;
983
+ patch?: never;
984
+ trace?: never;
985
+ };
986
+ "/v1/onboarding/skipped-steps": {
987
+ parameters: {
988
+ query?: never;
989
+ header?: never;
990
+ path?: never;
991
+ cookie?: never;
992
+ };
993
+ get?: never;
994
+ /**
995
+ * Replace the skipped steps
996
+ * @description Replaces the set of skipped steps and returns the whole progress. A step already skipped keeps its `skipped_at`, a newly listed step gets the current time, and a step left out is no longer skipped. `[]` clears every skip. Skipping a completed step is allowed and does not change `completed`. Safe to retry: the same request leaves the same set.
997
+ */
998
+ put: operations["setOnboardingSkippedSteps"];
999
+ post?: never;
1000
+ delete?: never;
1001
+ options?: never;
1002
+ head?: never;
1003
+ patch?: never;
1004
+ trace?: never;
1005
+ };
782
1006
  }
783
1007
  export type webhooks = Record<string, never>;
784
1008
  export interface components {
@@ -829,6 +1053,11 @@ export interface components {
829
1053
  * @example JPY
830
1054
  */
831
1055
  Currency: string;
1056
+ /**
1057
+ * @description Text to search for: 1 to 200 characters, with no whitespace at either end.
1058
+ * @example acme
1059
+ */
1060
+ SearchText: string;
832
1061
  /**
833
1062
  * @description The number of decimal places the money figures beside it were rounded to: the ISO 4217 exponent of `currency`.
834
1063
  * @example 0
@@ -873,6 +1102,26 @@ export interface components {
873
1102
  * @enum {string}
874
1103
  */
875
1104
  CalculationState: "draft" | "validated" | "published";
1105
+ /**
1106
+ * @description A report's position in its lifecycle: `draft` until it is shared, `shared` while its link works, and `revoked` once the link is revoked. A state only moves forward.
1107
+ * @enum {string}
1108
+ */
1109
+ ReportState: "draft" | "shared" | "revoked";
1110
+ /**
1111
+ * @description How often a client's renewal recurs: every month, or every year. Each renewal is the date as set plus whole terms, on the same day of the month, or on the month's last day when the month is shorter: a monthly renewal set on 31 January falls on 28 February, then 31 March.
1112
+ * @enum {string}
1113
+ */
1114
+ RenewalTerm: "monthly" | "annual";
1115
+ /**
1116
+ * @description A renewal term to list, or `none` for a client with no term.
1117
+ * @enum {string}
1118
+ */
1119
+ RenewalTermFilter: "monthly" | "annual" | "none";
1120
+ /**
1121
+ * @description Which renewal dates to list, measured from `today`: `overdue`, before `today`; `next_30_days` and `next_90_days`, from `today` to 30 or 90 days after it, both ends included; `upcoming`, on or after `today`.
1122
+ * @enum {string}
1123
+ */
1124
+ RenewalWindow: "overdue" | "next_30_days" | "next_90_days" | "upcoming";
876
1125
  /**
877
1126
  * @description An API key scope. Scopes are independent: `write` grants neither `read` nor `ingest`.
878
1127
  * @enum {string}
@@ -914,7 +1163,7 @@ export interface components {
914
1163
  */
915
1164
  HealthUnavailable: "never_published" | "no_prior_period" | "ratio_undefined";
916
1165
  /** @description The request-level error catalogue. Each code is sent with exactly one status, given as `x-status`, and has a fixed `title`. Clients branch on `code`, and fall back on the HTTP status for a code they do not recognise: new codes are additive. Once `/v1` is declared stable, a code is never renamed or repurposed. */
917
- ErrorCode: "invalid_json" | "validation_failed" | "unauthenticated" | "insufficient_scope" | "session_required" | "account_not_provisioned" | "not_found" | "no_active_value_model" | "method_not_allowed" | "idempotency_key_in_use" | "client_key_in_use" | "agent_key_in_use" | "client_has_events" | "client_has_calculations" | "agent_has_events" | "client_key_has_events" | "value_model_exists" | "value_model_version_stale" | "calculation_transition_invalid" | "calculation_not_draft" | "calculation_not_published" | "report_shared" | "report_not_shared" | "api_key_revoked" | "payload_too_large" | "uri_too_long" | "unsupported_media_type" | "idempotency_key_reused" | "rate_limited" | "internal_error";
1166
+ ErrorCode: "invalid_json" | "validation_failed" | "unauthenticated" | "insufficient_scope" | "session_required" | "account_not_provisioned" | "not_found" | "no_active_value_model" | "method_not_allowed" | "idempotency_key_in_use" | "client_key_in_use" | "agent_key_in_use" | "client_has_events" | "client_has_calculations" | "agent_has_events" | "client_key_has_events" | "value_model_exists" | "value_model_version_stale" | "calculation_transition_invalid" | "calculation_not_draft" | "calculation_not_published" | "report_shared" | "report_not_shared" | "api_key_revoked" | "invite_expired" | "invite_used" | "invite_revoked" | "invite_email_mismatch" | "email_has_workspace" | "payload_too_large" | "uri_too_long" | "unsupported_media_type" | "idempotency_key_reused" | "rate_limited" | "internal_error" | "upstream_failed";
918
1167
  /** @description The field-level code of one `errors` entry, or of an ingest or CSV row error. The vocabulary is open: new codes are additive. */
919
1168
  FieldErrorCode: "required" | "unknown_field" | "immutable" | "invalid_type" | "invalid_format" | "invalid_value" | "too_long" | "too_many" | "out_of_range" | "too_precise" | "duplicate" | "too_large" | "mutually_exclusive" | "unknown_reference" | "client_key_required" | "currency_mismatch";
920
1169
  /** @description One problem in a request. It carries exactly one primary locator: `pointer` for the JSON body, `parameter` for a query parameter, `header` for a request header, or `part` for a part of a `multipart/form-data` body. Only `part` takes a sub-locator: `pointer` into a JSON part, or `column` naming a column of a CSV part, at most one of the two. A `pointer` beside `part` is relative to that part, never to the request. A problem with the part as a whole, such as a missing or misordered part, carries `part` alone. */
@@ -990,8 +1239,12 @@ export interface components {
990
1239
  /** @description Free text, at most 200 characters. */
991
1240
  name: string;
992
1241
  status: components["schemas"]["ClientStatus"] | (string & {});
1242
+ /** @description The external identifier partners use for this client in event data. `null` when unset. */
993
1243
  client_key: string | null;
1244
+ /** @description For an active client with a `renewal_term`, the next renewal on or after the current UTC date: the date as set, rolled forward by whole terms once it passes, keeping its day of the month, or the month's last day when the month is shorter. Otherwise the date as set, which may be past. `null` when unset. */
994
1245
  renewal_date: components["schemas"]["Date"] | null;
1246
+ /** @description How often the renewal recurs. `null` when the client has no term, and its renewal date stays as set. A client can hold a term without a renewal date; the term applies once a date is set. */
1247
+ renewal_term: (components["schemas"]["RenewalTerm"] | (string & {})) | null;
995
1248
  /** @description Free text, `""` when empty. */
996
1249
  notes: string;
997
1250
  created_at: components["schemas"]["Instant"];
@@ -1007,23 +1260,34 @@ export interface components {
1007
1260
  ClientDetail: components["schemas"]["Client"] & {
1008
1261
  /** @description The assigned agents, ordered by name, case-insensitively. */
1009
1262
  agents: components["schemas"]["AssignedAgent"][];
1263
+ /** @description The first instant anything about this client could be true: its earliest attributed event, or the start of the earliest charge reaching it. `null` when it has neither. */
1010
1264
  earliest_activity_at: components["schemas"]["Instant"] | null;
1011
1265
  };
1012
1266
  ClientCreate: {
1013
1267
  /** @description Free text, trimmed of white space (the Unicode `White_Space` property) at both ends. The trimmed name is stored. It holds 1 to 200 characters, counted in Unicode code points after trimming: blank after trimming is `required`, and longer than 200 characters after trimming is `too_long`. U+0000 is `invalid_format`, as in every request string. No JSON Schema keyword measures a length after trimming, so the schema states no `maxLength`; a `maxLength` of 200 would refuse a padded name the server accepts. */
1014
1268
  name: string;
1015
1269
  status: components["schemas"]["ClientStatus"];
1270
+ /** @description At most 200 characters, counted as sent. Not trimmed: a key with white space (the Unicode `White_Space` property) at either end, or white space only, is refused with `invalid_format`. Unique in the workspace ignoring case: a key another client holds in any case, such as `acme` beside `Acme`, is refused with `client_key_in_use`. Absent or `null` leaves it unset; `""` is refused with `invalid_format`. */
1016
1271
  client_key?: string | null;
1272
+ /** @description The renewal date. A date before the request's UTC date less one day is refused with `out_of_range`, so no time zone's today is refused. Absent or `null` leaves it unset; `""` is refused with `invalid_format`. */
1017
1273
  renewal_date?: components["schemas"]["DateInput"] | null;
1274
+ /** @description How often the renewal recurs: an active client's renewal date then rolls forward by whole terms once it passes. Absent or `null` is no term, and the date stays as set. Any other value, `""` included, is refused with `invalid_value`. */
1275
+ renewal_term?: components["schemas"]["RenewalTerm"] | null;
1276
+ /** @description Free text, at most 2,000 characters. Absent or `null` stores `""`. */
1018
1277
  notes?: string | null;
1019
1278
  };
1020
- /** @description A JSON Merge Patch (RFC 7396): an absent member is unchanged, `null` clears a member. The merged client is validated whole. */
1279
+ /** @description A JSON Merge Patch (RFC 7396): an absent member is unchanged, `null` clears a member. The merged client is validated whole. A client's renewal schedule starts at the date as set: each renewal is that date plus whole terms. A patch that keeps the date but changes `renewal_term`, or changes `status`, saves the date the client shows on the current UTC day as the new start of its schedule, so the date shown does not jump; this happens without the patch sending a date. A client that is not active stops rolling and keeps the date it showed. A date the schedule already shows cannot become the new start in one patch: to move a client renewing on the 31st to the 30th, send a later 30th. */
1021
1280
  ClientPatch: {
1022
1281
  /** @description Free text, trimmed of white space (the Unicode `White_Space` property) at both ends. The trimmed name is stored. It holds 1 to 200 characters, counted in Unicode code points after trimming: blank after trimming is `required`, and longer than 200 characters after trimming is `too_long`. U+0000 is `invalid_format`, as in every request string. No JSON Schema keyword measures a length after trimming, so the schema states no `maxLength`; a `maxLength` of 200 would refuse a padded name the server accepts. */
1023
1282
  name?: string;
1024
1283
  status?: components["schemas"]["ClientStatus"];
1284
+ /** @description `null` clears it, refused with `client_key_has_events` while events carry the key. `""` does not clear it: it is refused with `invalid_format`. At most 200 characters, counted as sent. Not trimmed: a key with white space (the Unicode `White_Space` property) at either end, or white space only, is refused with `invalid_format`. Unique in the workspace ignoring case: a key another client holds in any case is refused with `client_key_in_use`. */
1025
1285
  client_key?: string | null;
1286
+ /** @description A date on the client's renewal schedule, up to the one it shows on the next UTC day, leaves the schedule unchanged, so sending back the `renewal_date` a read returned keeps it. Any other date is a new renewal date, refused with `out_of_range` when before the request's UTC date less one day. `null` clears it and keeps the term; `""` is refused with `invalid_format`. */
1026
1287
  renewal_date?: components["schemas"]["DateInput"] | null;
1288
+ /** @description How often the renewal recurs. `null` clears it, and the date then stays as set. Any other value, `""` included, is refused with `invalid_value`. */
1289
+ renewal_term?: components["schemas"]["RenewalTerm"] | null;
1290
+ /** @description Free text, at most 2,000 characters. `null` clears it to `""`. */
1027
1291
  notes?: string | null;
1028
1292
  };
1029
1293
  ClientAgentsSet: {
@@ -1080,7 +1344,9 @@ export interface components {
1080
1344
  agent_key: string;
1081
1345
  /** @description Free text, trimmed of white space (the Unicode `White_Space` property) at both ends. The trimmed name is stored. It holds 1 to 200 characters, counted in Unicode code points after trimming: blank after trimming is `required`, and longer than 200 characters after trimming is `too_long`. U+0000 is `invalid_format`, as in every request string. No JSON Schema keyword measures a length after trimming, so the schema states no `maxLength`; a `maxLength` of 200 would refuse a padded name the server accepts. */
1082
1346
  name: string;
1347
+ /** @description Free text, at most 100 characters. */
1083
1348
  framework?: string | null;
1349
+ /** @description Free text, at most 100 characters. */
1084
1350
  version?: string | null;
1085
1351
  status: components["schemas"]["AgentStatus"];
1086
1352
  };
@@ -1088,7 +1354,9 @@ export interface components {
1088
1354
  AgentPatch: {
1089
1355
  /** @description Free text, trimmed of white space (the Unicode `White_Space` property) at both ends. The trimmed name is stored. It holds 1 to 200 characters, counted in Unicode code points after trimming: blank after trimming is `required`, and longer than 200 characters after trimming is `too_long`. U+0000 is `invalid_format`, as in every request string. No JSON Schema keyword measures a length after trimming, so the schema states no `maxLength`; a `maxLength` of 200 would refuse a padded name the server accepts. */
1090
1356
  name?: string;
1357
+ /** @description Free text, at most 100 characters. `null` clears it to `""`. */
1091
1358
  framework?: string | null;
1359
+ /** @description Free text, at most 100 characters. `null` clears it to `""`. */
1092
1360
  version?: string | null;
1093
1361
  status?: components["schemas"]["AgentStatus"];
1094
1362
  };
@@ -1118,6 +1386,8 @@ export interface components {
1118
1386
  currency: components["schemas"]["Currency"];
1119
1387
  created_at: components["schemas"]["Instant"];
1120
1388
  updated_at: components["schemas"]["Instant"];
1389
+ /** @description When the model was archived; `null` unless `status` is `archived`. */
1390
+ archived_at: components["schemas"]["Instant"] | null;
1121
1391
  /** @description At most 50, ordered by `position`. */
1122
1392
  line_items: components["schemas"]["ValueLineItem"][];
1123
1393
  };
@@ -1138,10 +1408,12 @@ export interface components {
1138
1408
  ValueModelCreate: {
1139
1409
  /** @description Free text, trimmed of white space (the Unicode `White_Space` property) at both ends. The trimmed name is stored. It holds 1 to 200 characters, counted in Unicode code points after trimming: blank after trimming is `required`, and longer than 200 characters after trimming is `too_long`. U+0000 is `invalid_format`, as in every request string. No JSON Schema keyword measures a length after trimming, so the schema states no `maxLength`; a `maxLength` of 200 would refuse a padded name the server accepts. */
1140
1410
  name: string;
1411
+ /** @description Create-only: start from this built-in template's line items. An unknown id is refused with `unknown_reference`. Absent or `null` means no template; `""` is refused with `invalid_format`. */
1141
1412
  template_id?: string | null;
1413
+ /** @description Create-only: start from a copy of this model's line items. An id naming no model in the workspace is refused with `unknown_reference`. Absent or `null` means no source; `""` is refused with `invalid_format`. */
1142
1414
  copy_from_model_id?: components["schemas"]["UuidInput"] | null;
1143
1415
  };
1144
- /** @description A JSON Merge Patch (RFC 7396) of the client's active model. Setting `status` to `archived` frees the client for a new active model. */
1416
+ /** @description A JSON Merge Patch (RFC 7396) of the client's active model. Setting `status` to `archived` sets `archived_at` and frees the client for a new active model. */
1145
1417
  ValueModelPatch: {
1146
1418
  /** @description Free text, trimmed of white space (the Unicode `White_Space` property) at both ends. The trimmed name is stored. It holds 1 to 200 characters, counted in Unicode code points after trimming: blank after trimming is `required`, and longer than 200 characters after trimming is `too_long`. U+0000 is `invalid_format`, as in every request string. No JSON Schema keyword measures a length after trimming, so the schema states no `maxLength`; a `maxLength` of 200 would refuse a padded name the server accepts. */
1147
1419
  name?: string;
@@ -1154,6 +1426,7 @@ export interface components {
1154
1426
  label: string;
1155
1427
  /** @description At least 0 and below 100,000,000, with at most 4 decimal places; more is refused with `too_precise`, never rounded. Absent means 0, because templates ship every unit value as 0 on purpose. */
1156
1428
  unit_value?: components["schemas"]["Money"];
1429
+ /** @description Free text, at most 1,000 characters. */
1157
1430
  provenance_note?: string | null;
1158
1431
  };
1159
1432
  ValueLineItemsSet: {
@@ -1188,6 +1461,7 @@ export interface components {
1188
1461
  events: number;
1189
1462
  /** @description The summed event quantity. */
1190
1463
  quantity: number;
1464
+ /** @description Whether the client's active value model prices this outcome type. `null` where no single client's model applies: the workspace-wide list and value coverage findings. */
1191
1465
  priced: boolean | null;
1192
1466
  };
1193
1467
  /** @description What a cost line item is charged to: a client or an agent. */
@@ -1212,6 +1486,7 @@ export interface components {
1212
1486
  monthly_amount: components["schemas"]["Money"];
1213
1487
  currency: components["schemas"]["Currency"];
1214
1488
  start_date: components["schemas"]["Date"];
1489
+ /** @description Inclusive. `null` while the charge is still running. */
1215
1490
  end_date: components["schemas"]["Date"] | null;
1216
1491
  created_at: components["schemas"]["Instant"];
1217
1492
  updated_at: components["schemas"]["Instant"];
@@ -1223,6 +1498,7 @@ export interface components {
1223
1498
  /** @description In the workspace currency. At least 0 and below 100,000,000, with at most 4 decimal places; more is refused with `too_precise`. Required: absent or `null` is refused with `required`, and `0` must be sent explicitly. */
1224
1499
  monthly_amount: components["schemas"]["Money"];
1225
1500
  start_date: components["schemas"]["DateInput"];
1501
+ /** @description Inclusive; not before `start_date`. Absent or `null` makes the charge open-ended; `""` is refused with `invalid_format`. */
1226
1502
  end_date?: components["schemas"]["DateInput"] | null;
1227
1503
  };
1228
1504
  /** @description A JSON Merge Patch (RFC 7396). The merged line item is validated whole. */
@@ -1233,6 +1509,7 @@ export interface components {
1233
1509
  /** @description In the workspace currency. At least 0 and below 100,000,000, with at most 4 decimal places; more is refused with `too_precise`. */
1234
1510
  monthly_amount?: components["schemas"]["Money"];
1235
1511
  start_date?: components["schemas"]["DateInput"];
1512
+ /** @description Inclusive; not before `start_date`. `null` makes the charge open-ended; `""` is refused with `invalid_format`. */
1236
1513
  end_date?: components["schemas"]["DateInput"] | null;
1237
1514
  };
1238
1515
  /** @description One model's token prices. */
@@ -1266,7 +1543,9 @@ export interface components {
1266
1543
  };
1267
1544
  /** @description The two return ratios. Both are `null` together, exactly when `undefined_reason` is set. */
1268
1545
  Ratios: {
1546
+ /** @description `(value − cost) / cost`, from the rounded totals. */
1269
1547
  roi: components["schemas"]["Ratio"] | null;
1548
+ /** @description `value / cost`, from the rounded totals. */
1270
1549
  value_to_cost: components["schemas"]["Ratio"] | null;
1271
1550
  undefined_reason: (components["schemas"]["UndefinedReason"] | (string & {})) | null;
1272
1551
  };
@@ -1313,6 +1592,7 @@ export interface components {
1313
1592
  value_model: components["schemas"]["ValueModelRef"] | null;
1314
1593
  /** @description One line for each line item of the model, in line-item order, so at most 50. An outcome type no line item prices is never a line; it is listed in `coverage.unpriced_outcome_types`. */
1315
1594
  lines: components["schemas"]["ValueLine"][];
1595
+ /** @description `null` together with `value_model` when the client has no active model: not priced, which differs from zero. */
1316
1596
  total: components["schemas"]["Money"] | null;
1317
1597
  coverage: components["schemas"]["ValueCoverage"];
1318
1598
  };
@@ -1452,7 +1732,7 @@ export interface components {
1452
1732
  /** @description How many unmapped outcome types `unmapped_outcome_types` leaves out, `0` when it lists every one. */
1453
1733
  unmapped_outcome_types_omitted: number;
1454
1734
  };
1455
- /** @description One event behind a client's totals. */
1735
+ /** @description An event as stored, with its agent's name and the client it counts toward. */
1456
1736
  AttributedEvent: {
1457
1737
  /** @description The event id: a 64-bit integer as a decimal string, because JavaScript numbers lose precision above 2^53. */
1458
1738
  id: string;
@@ -1463,25 +1743,108 @@ export interface components {
1463
1743
  event_type: string;
1464
1744
  outcome_type: string | null;
1465
1745
  quantity: number;
1746
+ /** @description In the response's `currency`. */
1466
1747
  cost: components["schemas"]["Money"] | null;
1467
1748
  tokens_in: number | null;
1468
1749
  tokens_out: number | null;
1469
1750
  model: string | null;
1751
+ /** @description The key the event carried, as stored: as sent to `POST /v1/events`, trimmed by a CSV import. `null` when it carried none, or only whitespace. */
1470
1752
  client_key: string | null;
1471
1753
  source: components["schemas"]["EventSource"] | (string & {});
1472
- };
1473
- /** @description The events behind a client's totals. The shared list envelope plus this list's own members. It is the one list that also takes `page` and returns `total`; `page` and the cursor are one offset with two spellings. */
1754
+ /** @description When the API stored the event. An imported or late event arrives after its `timestamp`, sometimes long after. */
1755
+ created_at: components["schemas"]["Instant"];
1756
+ /** @description The CSV import that wrote the event, or `null` when it was sent to `POST /v1/events`. */
1757
+ import_batch_id: components["schemas"]["Uuid"] | null;
1758
+ /** @description The client the event counts toward: the client whose key it carried, or, when it carried none, the one client its agent is assigned to. `null` when it counts toward no client: its key names none, or it carried no key and its agent is assigned to no client or to several. */
1759
+ client_id: components["schemas"]["Uuid"] | null;
1760
+ /** @description The name of the client in `client_id`, or `null` with it. */
1761
+ client_name: string | null;
1762
+ };
1763
+ /** @description The events behind a client's totals. The shared list envelope plus this list's own members. It is the one list that returns `total` on every request, and the one whose `page` and cursor are one offset with two spellings. */
1474
1764
  ClientEventList: {
1475
1765
  client_id: components["schemas"]["Uuid"];
1476
1766
  period: components["schemas"]["Period"];
1477
1767
  /** @description The currency of every `cost` in `data`, given once here. An event's stored `currency` is not exposed: it is always `null` or the workspace currency, because a mismatching event is refused. */
1478
1768
  currency: components["schemas"]["Currency"];
1769
+ /** @description The page requested, or `null` when the request used `cursor`. */
1479
1770
  page: number | null;
1480
1771
  /** @description Every event matching the filters, not only this page. */
1481
1772
  total: number;
1482
1773
  /** @description At most `limit`, in the requested order; ties break on the event id, descending. */
1483
1774
  data: components["schemas"]["AttributedEvent"][];
1484
1775
  has_more: boolean;
1776
+ /** @description Opaque. Encodes the offset after this page. */
1777
+ next_cursor: string | null;
1778
+ };
1779
+ /** @description The workspace's events: newest first by `timestamp`, then by id, unless `sort` asks for another order. */
1780
+ EventList: {
1781
+ /** @description The arrival limit this page was read under: the `as_of` sent, the cursor's, or the one issued. Send it on later requests to read the same events. */
1782
+ as_of: components["schemas"]["Instant"];
1783
+ /** @description The period sent. Both bounds are `null` when neither was sent. */
1784
+ period: components["schemas"]["Period"];
1785
+ /** @description The `client_id` filter, or `null` when none was sent. */
1786
+ client_id: components["schemas"]["Uuid"] | null;
1787
+ /** @description The currency of every `cost` in `data`, given once here. */
1788
+ currency: components["schemas"]["Currency"];
1789
+ /** @description The page requested, or `null` when the request did not send `page`. */
1790
+ page: number | null;
1791
+ /** @description Every event matching the filters, up to 10,000, or `null` when the request did not send `page`. With `import_batch_id` it is exact, and may pass 10,000. */
1792
+ total: number | null;
1793
+ /** @description `true` when more than 10,000 events matched and `total` is 10,000; `false` when `total` is exact; `null` when the request did not send `page`. */
1794
+ total_capped: boolean | null;
1795
+ /** @description At most `limit`, in the requested order; ties break on the event id, descending. */
1796
+ data: components["schemas"]["AttributedEvent"][];
1797
+ /** @description Whether another page exists. */
1798
+ has_more: boolean;
1799
+ /** @description The opaque cursor for the next page. It carries `as_of`. Clients must not parse it. */
1800
+ next_cursor: string | null;
1801
+ };
1802
+ /** @description How many events a view of the workspace's events holds: in all, per day and per category. */
1803
+ EventSummary: {
1804
+ /** @description The arrival limit the counts were read under, as on the list. */
1805
+ as_of: components["schemas"]["Instant"];
1806
+ period: components["schemas"]["Period"];
1807
+ /** @description The `client_id` filter, or `null` when none was sent. */
1808
+ client_id: components["schemas"]["Uuid"] | null;
1809
+ /** @description Every event the view holds, counted exactly. Under the same parameters it equals the list's `total` whenever the list's `total_capped` is `false`. */
1810
+ total: number;
1811
+ /** @description One entry per 24 hours from `from`, ascending, zeros included. The last is shorter when the period is not a whole number of days. Empty when `from` equals `to`. */
1812
+ days: components["schemas"]["EventDayCount"][];
1813
+ /** @description One entry per category, in the order `session`, `task`, `model`, `outcome`, `exception`, zeros included. With `category` sent, the others are `0`. */
1814
+ categories: components["schemas"]["EventCategoryCount"][];
1815
+ };
1816
+ /** @description The events whose `timestamp` falls in one day of the period. */
1817
+ EventDayCount: {
1818
+ /** @description Where the day starts. It ends 24 hours later, or at the period's end. */
1819
+ start: components["schemas"]["Instant"];
1820
+ count: number;
1821
+ };
1822
+ /** @description The events of one category. */
1823
+ EventCategoryCount: {
1824
+ category: components["schemas"]["EventCategory"] | (string & {});
1825
+ count: number;
1826
+ };
1827
+ /** @description The workspace's events in the order the API stored them, newest first, then by id descending. */
1828
+ EventArrivalList: {
1829
+ /** @description The end of the arrival window, exclusive. Send it as the next poll's `since`. */
1830
+ as_of: components["schemas"]["Instant"];
1831
+ /** @description The start of the arrival window, inclusive, or `null` when none was sent. */
1832
+ since: components["schemas"]["Instant"] | null;
1833
+ /** @description The bounds sent. A bound not sent is `null`. */
1834
+ period: components["schemas"]["Period"];
1835
+ /** @description The `client_id` filter, or `null` when none was sent. */
1836
+ client_id: components["schemas"]["Uuid"] | null;
1837
+ /** @description The currency of every `cost` in `data`, given once here. */
1838
+ currency: components["schemas"]["Currency"];
1839
+ /** @description The matching events in the window, from `since` to `as_of`, up to 10,000; `null` without `since`. */
1840
+ count: number | null;
1841
+ /** @description `true` when more than 10,000 events matched and `count` is 10,000; `null` without `since`. */
1842
+ count_capped: boolean | null;
1843
+ /** @description At most `limit`, newest arrival first; ties break on the event id, descending. */
1844
+ data: components["schemas"]["AttributedEvent"][];
1845
+ /** @description Whether another page exists. */
1846
+ has_more: boolean;
1847
+ /** @description The opaque cursor for the next page. It carries `as_of`. Clients must not parse it. */
1485
1848
  next_cursor: string | null;
1486
1849
  };
1487
1850
  /** @description The validation checklist: the attestation recorded when the calculation was validated. All four checks are `false` until the calculation is validated. */
@@ -1503,6 +1866,7 @@ export interface components {
1503
1866
  costs_reviewed: true;
1504
1867
  /** @constant */
1505
1868
  unit_values_current: true;
1869
+ /** @description Free text, at most 2,000 characters. Absent or `null` is stored as `""`. */
1506
1870
  note?: string | null;
1507
1871
  };
1508
1872
  /** @description The ROI result frozen when the calculation was created, never rewritten. It is served with the field names it was stored with. A change to its shape increments `snapshot_version`, and this spec describes every version still stored. Version 1 is the `RoiResult` shape. Every list is stored whole. When served, each list the live ROI read limits is put in the same order and limited the same way, and its count of omitted entries is added beside it, so a snapshot and a live read of the same data match. The frozen totals cover every entry. */
@@ -1518,6 +1882,7 @@ export interface components {
1518
1882
  period: components["schemas"]["Period"];
1519
1883
  currency: components["schemas"]["Currency"];
1520
1884
  minor_units: components["schemas"]["MinorUnits"];
1885
+ /** @description `null` when the client had no active value model. */
1521
1886
  value_total: components["schemas"]["Money"] | null;
1522
1887
  cost_total: components["schemas"]["Money"];
1523
1888
  ratios: components["schemas"]["Ratios"];
@@ -1527,14 +1892,17 @@ export interface components {
1527
1892
  published_at: components["schemas"]["Instant"] | null;
1528
1893
  snapshot: components["schemas"]["CalculationSnapshot"];
1529
1894
  };
1530
- /** @description A calculation as the list returns it: without `snapshot`, with `is_current`. */
1895
+ /** @description A calculation as the lists return it: without `snapshot`, with `is_current`, the client's name and the number of coverage findings. */
1531
1896
  CalculationSummary: {
1532
1897
  id: components["schemas"]["Uuid"];
1533
1898
  client_id: components["schemas"]["Uuid"];
1899
+ /** @description The client's name as its record holds it now. */
1900
+ client_name: string;
1534
1901
  state: components["schemas"]["CalculationState"] | (string & {});
1535
1902
  period: components["schemas"]["Period"];
1536
1903
  currency: components["schemas"]["Currency"];
1537
1904
  minor_units: components["schemas"]["MinorUnits"];
1905
+ /** @description `null` when the client had no active value model. */
1538
1906
  value_total: components["schemas"]["Money"] | null;
1539
1907
  cost_total: components["schemas"]["Money"];
1540
1908
  ratios: components["schemas"]["Ratios"];
@@ -1542,7 +1910,10 @@ export interface components {
1542
1910
  created_at: components["schemas"]["Instant"];
1543
1911
  validated_at: components["schemas"]["Instant"] | null;
1544
1912
  published_at: components["schemas"]["Instant"] | null;
1913
+ /** @description Whether this is the figure for its period: the latest publication covering it. `null` when the calculation is not published. */
1545
1914
  is_current: boolean | null;
1915
+ /** @description How many coverage findings the calculation's frozen figures hold: the disclosures a report on it would list, including those a report leaves out of the shared copy by default. */
1916
+ coverage_findings: number;
1546
1917
  };
1547
1918
  CalculationCreate: {
1548
1919
  /** @description The ended period to freeze. Digits below a microsecond are dropped from each bound before any check, because storage keeps no finer. A bound before `1900-01-01T00:00:00Z` is refused with `out_of_range` at its own pointer. `from` must be before `to`: a period with `from` at or after `to` holds no instant, and is refused with `out_of_range` at `/period/from`. `to` may be at most 731 days after `from`; a longer period is refused with `out_of_range` at `/period`. `to` must be at or before the start of the current UTC day, and after the client's first recorded activity; either failure is refused with `out_of_range` at `/period/to`. A client with no recorded events or charges at all is refused with `out_of_range` at `/period`, because no period can succeed. */
@@ -1555,26 +1926,36 @@ export interface components {
1555
1926
  facts: Record<string, unknown>;
1556
1927
  /** @description Whether the finding goes out on the shared report. */
1557
1928
  included: boolean;
1929
+ /** @description The owner's own wording. `null` means use the default sentence, which `""` would not. */
1558
1930
  text: string | null;
1559
1931
  };
1560
1932
  DisclosureEdit: {
1561
1933
  /** @description Names one of the report's stored findings, spelled as a read returns it. A kind that is not one of them is refused with `invalid_value` at `/disclosures/<index>/kind`. */
1562
1934
  kind: components["schemas"]["DisclosureKind"];
1563
1935
  included: boolean;
1936
+ /** @description At most 500 characters. `null` restores the default sentence. */
1564
1937
  text?: string | null;
1565
1938
  };
1566
1939
  /** @description A report: the editorial layer over a published calculation. */
1567
1940
  Report: {
1568
1941
  id: components["schemas"]["Uuid"];
1569
1942
  calculation_id: components["schemas"]["Uuid"];
1570
- /** @description Free text, as the recipient sees it. */
1943
+ /** @description The client of the report's calculation. */
1944
+ client_id: components["schemas"]["Uuid"];
1945
+ /** @description The client's name as its record holds it now, so renaming the client renames it on every report. The recipient sees `letterhead_client_name` instead. */
1571
1946
  client_name: string;
1572
- /** @description Free text, as the recipient sees it. */
1573
- workspace_name: string;
1947
+ /** @description The period of the report's calculation. */
1948
+ period: components["schemas"]["Period"];
1949
+ state: components["schemas"]["ReportState"] | (string & {});
1950
+ /** @description Free text, as the recipient sees it: the letterhead's "For" line. It starts as the client's name and may differ from it. */
1951
+ letterhead_client_name: string;
1952
+ /** @description Free text, as the recipient sees it: the letterhead's "From" line. It starts as the workspace's name and may differ from it. */
1953
+ letterhead_workspace_name: string;
1574
1954
  /** @description Free text, `""` when empty. */
1575
1955
  note: string;
1576
1956
  /** @description In the order the calculation's coverage produced them. At most 12: each kind appears at most once. */
1577
1957
  disclosures: components["schemas"]["Disclosure"][];
1958
+ /** @description The link token, once shared. `null` before the report is shared. */
1578
1959
  share_token: string | null;
1579
1960
  shared_at: components["schemas"]["Instant"] | null;
1580
1961
  revoked_at: components["schemas"]["Instant"] | null;
@@ -1586,12 +1967,20 @@ export interface components {
1586
1967
  ReportSummary: {
1587
1968
  id: components["schemas"]["Uuid"];
1588
1969
  calculation_id: components["schemas"]["Uuid"];
1589
- /** @description Free text, as the recipient sees it. */
1970
+ /** @description The client of the report's calculation. */
1971
+ client_id: components["schemas"]["Uuid"];
1972
+ /** @description The client's name as its record holds it now, so renaming the client renames it on every report. The recipient sees `letterhead_client_name` instead. */
1590
1973
  client_name: string;
1591
- /** @description Free text, as the recipient sees it. */
1592
- workspace_name: string;
1974
+ /** @description The period of the report's calculation. */
1975
+ period: components["schemas"]["Period"];
1976
+ state: components["schemas"]["ReportState"] | (string & {});
1977
+ /** @description Free text, as the recipient sees it: the letterhead's "For" line. It starts as the client's name and may differ from it. */
1978
+ letterhead_client_name: string;
1979
+ /** @description Free text, as the recipient sees it: the letterhead's "From" line. It starts as the workspace's name and may differ from it. */
1980
+ letterhead_workspace_name: string;
1593
1981
  /** @description Free text, `""` when empty. */
1594
1982
  note: string;
1983
+ /** @description The link token, once shared. `null` before the report is shared. */
1595
1984
  share_token: string | null;
1596
1985
  shared_at: components["schemas"]["Instant"] | null;
1597
1986
  revoked_at: components["schemas"]["Instant"] | null;
@@ -1601,14 +1990,16 @@ export interface components {
1601
1990
  };
1602
1991
  /** @description A report with its recipient preview, as the single read returns it. */
1603
1992
  ReportWithPreview: components["schemas"]["Report"] & {
1993
+ /** @description Exactly what `GET /report` would return. `null` when the preview cannot be rendered. */
1604
1994
  preview: components["schemas"]["PublicReport"] | null;
1605
1995
  };
1606
1996
  /** @description A JSON Merge Patch (RFC 7396). An array replaces the stored array whole. A shared report is refused with `report_shared`. */
1607
1997
  ReportPatch: {
1608
1998
  /** @description Free text, 1 to 200 characters counted in Unicode code points, padding included. Not trimmed: the value is stored as sent. Blank after trimming white space is `required`, and longer than 200 characters is `too_long`. */
1609
- client_name?: string;
1999
+ letterhead_client_name?: string;
1610
2000
  /** @description Free text, 1 to 200 characters counted in Unicode code points, padding included. Not trimmed: the value is stored as sent. Blank after trimming white space is `required`, and longer than 200 characters is `too_long`. */
1611
- workspace_name?: string;
2001
+ letterhead_workspace_name?: string;
2002
+ /** @description Free text, at most 2,000 characters. `null` clears it to `""`. */
1612
2003
  note?: string | null;
1613
2004
  /** @description Replaces the editorial state of every finding. It must name each stored finding exactly once: a missing one is `required`, an unknown one `invalid_value`, a repeated one `duplicate`. At most 50: a longer array is refused at its 51st element with one `too_many` at `/disclosures`. */
1614
2005
  disclosures?: components["schemas"]["DisclosureEdit"][];
@@ -1647,6 +2038,7 @@ export interface components {
1647
2038
  total: components["schemas"]["Money"];
1648
2039
  };
1649
2040
  };
2041
+ /** @description The client's abutting prior published period. */
1650
2042
  compared_to: {
1651
2043
  period: components["schemas"]["Period"];
1652
2044
  value_total: components["schemas"]["Money"] | null;
@@ -1734,9 +2126,15 @@ export interface components {
1734
2126
  Renewal: {
1735
2127
  client_id: components["schemas"]["Uuid"];
1736
2128
  name: string;
2129
+ /** @description For a client with a `renewal_term`, the next renewal on or after the list's `today`. Otherwise the date as set, which may be before `today`. */
1737
2130
  renewal_date: components["schemas"]["Date"];
2131
+ /** @description How often the renewal recurs. `null` when the client has no term. */
2132
+ renewal_term: (components["schemas"]["RenewalTerm"] | (string & {})) | null;
1738
2133
  roi: components["schemas"]["Ratio"] | null;
2134
+ /** @description The client's latest published period. `null` when it has none. */
1739
2135
  period: components["schemas"]["Period"] | null;
2136
+ /** @description The published calculation `roi` and `period` come from. `null` exactly when `period` is. */
2137
+ calculation_id: components["schemas"]["Uuid"] | null;
1740
2138
  health: {
1741
2139
  direction: components["schemas"]["HealthDirection"] | (string & {});
1742
2140
  /** @description The change in percentage points, one decimal place. */
@@ -1757,6 +2155,7 @@ export interface components {
1757
2155
  /** @description In the order `ingest`, `read`, `write`. */
1758
2156
  scopes: (components["schemas"]["Scope"] | (string & {}))[];
1759
2157
  created_at: components["schemas"]["Instant"];
2158
+ /** @description Accurate to 60 seconds. */
1760
2159
  last_used_at: components["schemas"]["Instant"] | null;
1761
2160
  revoked_at: components["schemas"]["Instant"] | null;
1762
2161
  };
@@ -1773,22 +2172,32 @@ export interface components {
1773
2172
  };
1774
2173
  /** @description A canonical event. A problem with one event rejects that event only, as row errors; an unknown member is such a problem. `category` outside `EventCategory` is refused with `invalid_value`. `currency` is not part of the deduplication hash. */
1775
2174
  EventInput: {
2175
+ /** @description An optional sender-chosen id. A repeat within the workspace is a duplicate. The SDKs generate one per event. At most 200 characters, counted as sent; more is refused with `too_long`. */
1776
2176
  event_id?: string | null;
1777
2177
  /** @description When the event happened. At most 24 hours in the future. */
1778
2178
  timestamp: components["schemas"]["InstantInput"];
1779
2179
  /** @description The agent that acted. An agent not seen before is created. 1 to 200 characters, counted as sent; more is refused with `too_long`. */
1780
2180
  agent_key: string;
2181
+ /** @description The client the event belongs to. Required on a `model` or `outcome` event whose agent is assigned to two or more clients; without it the row is refused with `client_key_required`. A key of white space only counts as no key. At most 200 characters, counted as sent; more is refused with `too_long`. */
1781
2182
  client_key?: string | null;
1782
2183
  category: components["schemas"]["EventCategory"];
1783
2184
  /** @description What the agent did. 1 to 200 characters, counted as sent; more is refused with `too_long`. */
1784
2185
  event_type: string;
2186
+ /** @description Required when `category` is `outcome`. At most 200 characters, counted as sent; more is refused with `too_long`, whatever the `category`. */
1785
2187
  outcome_type?: string | null;
2188
+ /** @description Absent, `null` or `0` means 1. Its magnitude is below 10,000,000,000. */
1786
2189
  quantity?: number | null;
2190
+ /** @description In `currency`, or the workspace currency. Its magnitude is below 100,000,000, with at most 6 decimal places; more is refused with `too_precise`. May be negative: a vendor credit. */
1787
2191
  cost?: components["schemas"]["Money"] | null;
2192
+ /** @description A negative count is refused with `out_of_range`. */
1788
2193
  tokens_in?: number | null;
2194
+ /** @description A negative count is refused with `out_of_range`. */
1789
2195
  tokens_out?: number | null;
2196
+ /** @description The model the agent invoked. The price table is keyed by it. At most 200 characters, counted as sent; more is refused with `too_long`. */
1790
2197
  model?: string | null;
2198
+ /** @description The currency of `cost`. Absent means the workspace currency. A different currency is refused with `currency_mismatch`, never converted. */
1791
2199
  currency?: components["schemas"]["Currency"] | null;
2200
+ /** @description Free-form. Any members, at most 8 KB serialised; more is refused with `too_large`. A repeated member name is refused with `duplicate`. */
1792
2201
  metadata?: Record<string, unknown> | null;
1793
2202
  };
1794
2203
  EventBatch: {
@@ -1846,13 +2255,14 @@ export interface components {
1846
2255
  /** @description Two parts, in this order: `mapping`, then `file`. The server reads them in that order and never buffers the file whole. A request-level problem in this body is located by `part` (see `FieldError`): a mapping member by `part` `mapping` and a `pointer` into the mapping, such as `/columns/client_key`; a mapped column absent from the file header by `part` `file` and that `column`; a missing or misordered part by `part` alone. A part after `file` is refused with `unknown_field` on that part, and a `mapping` part over 65,536 bytes with `too_large`. A header that names a column more than once is refused with `duplicate` on `part` `file` and that `column`, one entry per repeated name in the order each first repeats, before any `required` entry for a mapped column the header lacks. Names compare exactly, untrimmed, so `Bot` and `Bot ` are two columns. Blank header cells may repeat unless the mapping binds the blank name. */
1847
2256
  ImportUpload: {
1848
2257
  mapping: components["schemas"]["ImportMapping"];
1849
- /** @description The CSV file, with a header row. At most 250,000 data rows. Each header name is at most 256 bytes of UTF-8; a longer one is refused with `too_long` on `part` `file`, located by its position in the `detail` and carrying no `column`, before any repeated-name or missing-column check. A header name that is not valid UTF-8 is accepted, but the mapping cannot bind it, and the response writes each such byte as U+FFFD wherever it names the column. The part's file name is stored with the import, so one that is not valid UTF-8 is refused with `invalid_format` on `part` `file`, as one holding U+0000 is. */
2258
+ /** @description The CSV file, with a header row. At most 250,000 data rows. Each header name is at most 256 bytes of UTF-8; a longer one is refused with `too_long` on `part` `file`, located by its position in the `detail` and carrying no `column`, before any repeated-name or missing-column check. A header name that is not valid UTF-8 is accepted, but the mapping cannot bind it, and the response writes each such byte as U+FFFD wherever it names the column. The part's file name is stored with the import, so one that is not valid UTF-8 is refused with `invalid_format` on `part` `file`, as one holding U+0000 is. A file name of more than 255 characters, counted as Unicode code points after a directory part separated by `/` is dropped, is refused with `too_long` on `part` `file`. A backslash is not a separator: `C:\ops\august.csv` is counted and stored whole. */
1850
2259
  file: string;
1851
2260
  };
1852
2261
  /** @description One problem with a rejected CSV row. A row with several problems has one entry for each, all carrying its `row`. */
1853
2262
  ImportRowError: {
1854
2263
  /** @description The one-based line number in the file, counting the header. */
1855
2264
  row: number;
2265
+ /** @description The file's column the problem is in. `null` when the value came from a constant or the problem has no column. */
1856
2266
  column: string | null;
1857
2267
  code: components["schemas"]["FieldErrorCode"] | (string & {});
1858
2268
  detail: string;
@@ -1898,6 +2308,7 @@ export interface components {
1898
2308
  ignored_columns: string[];
1899
2309
  /** @description How many columns the mapping does not bind beyond the 100 in `ignored_columns`. `0` when the list is complete. */
1900
2310
  ignored_columns_omitted: number;
2311
+ /** @description Set when the file has timestamps without an offset and the last import used a different timezone, so re-imported rows would not deduplicate. Human text. */
1901
2312
  timezone_warning: string | null;
1902
2313
  };
1903
2314
  /** @description The outcome of a CSV import. Partial acceptance is a success. */
@@ -1912,34 +2323,113 @@ export interface components {
1912
2323
  /** @description Whether `errors` omits any problem, as on the preview. */
1913
2324
  errors_truncated: boolean;
1914
2325
  };
2326
+ /** @description One CSV import and its counts. `total_rows` is `accepted` plus `duplicates` plus `rejected`. */
2327
+ ImportSummary: {
2328
+ id: components["schemas"]["Uuid"];
2329
+ /** @description The file part's file name, without a directory part separated by `/`: a part named `exports/august.csv` is stored as `august.csv`. A backslash is not a separator, so `C:\ops\august.csv` is stored whole. `""` when the file part named none. */
2330
+ filename: string;
2331
+ /** @description The file's data rows, not counting the header. */
2332
+ total_rows: number;
2333
+ /** @description The events this import wrote, counted when the import is read: the `import_batch_id` of each is the import's `id`. */
2334
+ accepted: number;
2335
+ /** @description `total_rows` less `rejected` and `accepted`. At the commit, these are the valid rows that wrote no event: an event with the same `event_id`, or the same content hash, was already stored, or an earlier row of the same file had the same `event_id`. Identical rows of one file without an `event_id` are each written, so they are not counted here. */
2336
+ duplicates: number;
2337
+ /** @description Rows refused, counted once each however many problems they had. */
2338
+ rejected: number;
2339
+ created_at: components["schemas"]["Instant"];
2340
+ };
2341
+ /** @description One CSV import, its counts and the mapping it ran with. */
2342
+ Import: {
2343
+ id: components["schemas"]["Uuid"];
2344
+ /** @description The file part's file name, without a directory part separated by `/`: a part named `exports/august.csv` is stored as `august.csv`. A backslash is not a separator, so `C:\ops\august.csv` is stored whole. `""` when the file part named none. */
2345
+ filename: string;
2346
+ /** @description The file's data rows, not counting the header. */
2347
+ total_rows: number;
2348
+ /** @description The events this import wrote, counted when the import is read: the `import_batch_id` of each is the import's `id`. */
2349
+ accepted: number;
2350
+ /** @description `total_rows` less `rejected` and `accepted`. At the commit, these are the valid rows that wrote no event: an event with the same `event_id`, or the same content hash, was already stored, or an earlier row of the same file had the same `event_id`. Identical rows of one file without an `event_id` are each written, so they are not counted here. */
2351
+ duplicates: number;
2352
+ /** @description Rows refused, counted once each however many problems they had. */
2353
+ rejected: number;
2354
+ created_at: components["schemas"]["Instant"];
2355
+ mapping: components["schemas"]["AppliedImportMapping"];
2356
+ };
2357
+ /** @description The mapping an import ran with, with every member present: a member the import did not send holds the value it applied. It has the members of `ImportMapping`, so it can be sent as the next import's `mapping`. A value the server's current rules refuse is refused then as in any mapping. */
2358
+ AppliedImportMapping: {
2359
+ /** @description Canonical field name to the file's column name, as in `ImportMapping`. `{}` when the import bound none. */
2360
+ columns: {
2361
+ [key: string]: string;
2362
+ };
2363
+ /** @description Canonical field name to the value used for every row, as in `ImportMapping`. `{}` when the import had none. */
2364
+ constants: {
2365
+ [key: string]: string;
2366
+ };
2367
+ /** @description The IANA zone applied to timestamps without an offset. `UTC` when the import named none. */
2368
+ timezone: string;
2369
+ /** @description The field delimiter. `,` when the import named none. */
2370
+ delimiter: components["schemas"]["ImportDelimiter"] | (string & {});
2371
+ };
2372
+ /**
2373
+ * @description A CSV field delimiter, a comma, a semicolon or a tab.
2374
+ * @enum {string}
2375
+ */
2376
+ ImportDelimiter: "," | ";" | "\t";
1915
2377
  /** @description Liveness. */
1916
2378
  Health: {
1917
2379
  status: "ok" | (string & {});
1918
2380
  /** @description The build version. */
1919
2381
  version: string;
1920
2382
  };
2383
+ /** @description The workspace's imports: newest first, then id. */
2384
+ ImportList: {
2385
+ /** @description The page requested, or `null` when the request did not send `page`. */
2386
+ page: number | null;
2387
+ /** @description Every import in the workspace, not only this page, or `null` when the request did not send `page`. */
2388
+ total: number | null;
2389
+ /** @description One page of items, at most `limit`, in the documented order. */
2390
+ data: components["schemas"]["ImportSummary"][];
2391
+ /** @description Whether another page exists. */
2392
+ has_more: boolean;
2393
+ /** @description The opaque cursor for the next page. Clients must not parse it. */
2394
+ next_cursor: string | null;
2395
+ };
1921
2396
  /** @description Clients, ordered by name case-insensitively, then id. */
1922
2397
  ClientList: {
2398
+ /** @description The page requested, or `null` when the request did not send `page`. */
2399
+ page: number | null;
2400
+ /** @description Every client matching the filters and search, not only this page, or `null` when the request did not send `page`. */
2401
+ total: number | null;
1923
2402
  /** @description One page of items, at most `limit`, in the documented order. */
1924
2403
  data: components["schemas"]["Client"][];
1925
2404
  /** @description Whether another page exists. */
1926
2405
  has_more: boolean;
2406
+ /** @description The opaque cursor for the next page. Clients must not parse it. */
1927
2407
  next_cursor: string | null;
1928
2408
  };
1929
2409
  /** @description Agents, ordered by name case-insensitively, then id. Includes agents ingest created. */
1930
2410
  AgentList: {
2411
+ /** @description The page requested, or `null` when the request did not send `page`. */
2412
+ page: number | null;
2413
+ /** @description Every agent matching the filters and search, not only this page, or `null` when the request did not send `page`. */
2414
+ total: number | null;
1931
2415
  /** @description One page of items, at most `limit`, in the documented order. */
1932
2416
  data: components["schemas"]["AgentListItem"][];
1933
2417
  /** @description Whether another page exists. */
1934
2418
  has_more: boolean;
2419
+ /** @description The opaque cursor for the next page. Clients must not parse it. */
1935
2420
  next_cursor: string | null;
1936
2421
  };
1937
2422
  /** @description Value models: active first, then newest first, then id. */
1938
2423
  ValueModelList: {
2424
+ /** @description The page requested, or `null` when the request did not send `page`. */
2425
+ page: number | null;
2426
+ /** @description Every value model matching the filters and search, not only this page, or `null` when the request did not send `page`. */
2427
+ total: number | null;
1939
2428
  /** @description One page of items, at most `limit`, in the documented order. */
1940
2429
  data: components["schemas"]["ValueModelSummary"][];
1941
2430
  /** @description Whether another page exists. */
1942
2431
  has_more: boolean;
2432
+ /** @description The opaque cursor for the next page. Clients must not parse it. */
1943
2433
  next_cursor: string | null;
1944
2434
  };
1945
2435
  /** @description Outcome types by summed quantity, largest first, then by name. */
@@ -1948,6 +2438,7 @@ export interface components {
1948
2438
  data: components["schemas"]["OutcomeTypeUsage"][];
1949
2439
  /** @description Whether another page exists. */
1950
2440
  has_more: boolean;
2441
+ /** @description The opaque cursor for the next page. Clients must not parse it. */
1951
2442
  next_cursor: string | null;
1952
2443
  };
1953
2444
  /** @description Templates in display order. */
@@ -1956,14 +2447,20 @@ export interface components {
1956
2447
  data: components["schemas"]["ValueTemplate"][];
1957
2448
  /** @description Whether another page exists. */
1958
2449
  has_more: boolean;
2450
+ /** @description The opaque cursor for the next page. Clients must not parse it. */
1959
2451
  next_cursor: string | null;
1960
2452
  };
1961
2453
  /** @description Line items, newest first, then id. */
1962
2454
  CostLineItemList: {
2455
+ /** @description The page requested, or `null` when the request did not send `page`. */
2456
+ page: number | null;
2457
+ /** @description Every line item matching the filters and search, not only this page, or `null` when the request did not send `page`. */
2458
+ total: number | null;
1963
2459
  /** @description One page of items, at most `limit`, in the documented order. */
1964
2460
  data: components["schemas"]["CostLineItem"][];
1965
2461
  /** @description Whether another page exists. */
1966
2462
  has_more: boolean;
2463
+ /** @description The opaque cursor for the next page. Clients must not parse it. */
1967
2464
  next_cursor: string | null;
1968
2465
  };
1969
2466
  /** @description A client's calculations: latest period first, then newest first, then id. */
@@ -1972,6 +2469,7 @@ export interface components {
1972
2469
  data: components["schemas"]["CalculationSummary"][];
1973
2470
  /** @description Whether another page exists. */
1974
2471
  has_more: boolean;
2472
+ /** @description The opaque cursor for the next page. Clients must not parse it. */
1975
2473
  next_cursor: string | null;
1976
2474
  };
1977
2475
  /** @description A calculation's reports, newest first, then id. */
@@ -1980,24 +2478,113 @@ export interface components {
1980
2478
  data: components["schemas"]["ReportSummary"][];
1981
2479
  /** @description Whether another page exists. */
1982
2480
  has_more: boolean;
2481
+ /** @description The opaque cursor for the next page. Clients must not parse it. */
1983
2482
  next_cursor: string | null;
1984
2483
  };
1985
- /** @description Clients with a renewal date, by renewal date, then name, then id. */
1986
- RenewalList: {
2484
+ /** @description The workspace's calculations: latest period first, then newest first, then id. */
2485
+ WorkspaceCalculationList: {
2486
+ /** @description The page requested, or `null` when the request did not send `page`. */
2487
+ page: number | null;
2488
+ /** @description Every calculation matching the filters, not only this page, or `null` when the request did not send `page`. */
2489
+ total: number | null;
1987
2490
  /** @description One page of items, at most `limit`, in the documented order. */
1988
- data: components["schemas"]["Renewal"][];
2491
+ data: components["schemas"]["CalculationSummary"][];
1989
2492
  /** @description Whether another page exists. */
1990
2493
  has_more: boolean;
2494
+ /** @description The opaque cursor for the next page. Clients must not parse it. */
1991
2495
  next_cursor: string | null;
1992
2496
  };
1993
- /** @description Every key in the workspace, revoked keys included, newest first, then id. */
1994
- ApiKeyList: {
2497
+ /** @description The workspace's reports: newest first, then id. */
2498
+ WorkspaceReportList: {
2499
+ /** @description The page requested, or `null` when the request did not send `page`. */
2500
+ page: number | null;
2501
+ /** @description Every report matching the filters, not only this page, or `null` when the request did not send `page`. */
2502
+ total: number | null;
2503
+ /** @description One page of items, at most `limit`, in the documented order. */
2504
+ data: components["schemas"]["ReportSummary"][];
2505
+ /** @description Whether another page exists. */
2506
+ has_more: boolean;
2507
+ /** @description The opaque cursor for the next page. Clients must not parse it. */
2508
+ next_cursor: string | null;
2509
+ };
2510
+ /** @description Active clients with a renewal date, by the renewal date shown, then by name case-insensitively, then by id. */
2511
+ RenewalList: {
2512
+ /** @description The page requested, or `null` when the request did not send `page`. */
2513
+ page: number | null;
2514
+ /** @description Every client matching `window` and `renewal_term`, not only this page, or `null` when the request did not send `page`. */
2515
+ total: number | null;
2516
+ /** @description The date the renewal dates were rolled against and `window` measured from: the `today` sent, or the current UTC date. */
2517
+ today: components["schemas"]["Date"];
2518
+ /** @description One page of items, at most `limit`, in the documented order. */
2519
+ data: components["schemas"]["Renewal"][];
2520
+ /** @description Whether another page exists. */
2521
+ has_more: boolean;
2522
+ /** @description The opaque cursor for the next page. Clients must not parse it. */
2523
+ next_cursor: string | null;
2524
+ };
2525
+ /** @description Every key in the workspace, revoked keys included, newest first, then id. */
2526
+ ApiKeyList: {
1995
2527
  /** @description One page of items, at most `limit`, in the documented order. */
1996
2528
  data: components["schemas"]["ApiKey"][];
1997
2529
  /** @description Whether another page exists. */
1998
2530
  has_more: boolean;
2531
+ /** @description The opaque cursor for the next page. Clients must not parse it. */
1999
2532
  next_cursor: string | null;
2000
2533
  };
2534
+ /** @description A redeemed invite. The address can now sign in with an email code. */
2535
+ InviteRedemption: {
2536
+ /** @description The address the invite was sent to, in lower case. */
2537
+ email: string;
2538
+ /** @description When the invite's link stops working, 24 hours after the invite was sent. An invite whose address signs in before then no longer expires, and its workspace can be created after this instant. */
2539
+ expires_at: components["schemas"]["Instant"];
2540
+ };
2541
+ /** @description The open invite to the signed-in session's email address. Its address has signed in, so it no longer expires. */
2542
+ OpenInvite: {
2543
+ /** @description The address the invite was sent to, in lower case. */
2544
+ email: string;
2545
+ };
2546
+ WorkspaceCreate: {
2547
+ /** @description The token from the invite link, exactly as the link carries it. A value that is not in the form of an invite token, `""` included, is `invalid_format`, and a token that names no invite is `unknown_reference`. Absent or `null` uses the open invite to the session's email address instead. It is used on create only and is never returned. */
2548
+ invite_token?: string | null;
2549
+ /** @description Free text, trimmed of white space (the Unicode `White_Space` property) at both ends. The trimmed name is stored. It holds 1 to 200 characters, counted in Unicode code points after trimming: blank after trimming is `required`, and longer than 200 characters after trimming is `too_long`. U+0000 is `invalid_format`, as in every request string. No JSON Schema keyword measures a length after trimming, so the schema states no `maxLength`; a `maxLength` of 200 would refuse a padded name the server accepts. */
2550
+ name: string;
2551
+ /** @description The workspace's currency, an ISO 4217 code in upper case. A lower-case code is `invalid_format`. Every money figure in the workspace is in it. */
2552
+ currency: components["schemas"]["Currency"];
2553
+ };
2554
+ /** @description The workspace a credential belongs to. */
2555
+ Workspace: {
2556
+ id: components["schemas"]["Uuid"];
2557
+ /** @description Free text. */
2558
+ name: string;
2559
+ currency: components["schemas"]["Currency"];
2560
+ minor_units: components["schemas"]["MinorUnits"];
2561
+ created_at: components["schemas"]["Instant"];
2562
+ };
2563
+ /**
2564
+ * @description A guided-setup step, in its fixed order: `add_client`, `add_agent`, `price_outcomes`, `bring_in_data`, `create_draft_calculation`.
2565
+ * @enum {string}
2566
+ */
2567
+ OnboardingStep: "add_client" | "add_agent" | "price_outcomes" | "bring_in_data" | "create_draft_calculation";
2568
+ OnboardingStepProgress: {
2569
+ step: components["schemas"]["OnboardingStep"] | (string & {});
2570
+ /** @description Whether the workspace's data completes the step: a client; an agent assigned to a client; a line item on an active value model; an event; a calculation in any state. */
2571
+ completed: boolean;
2572
+ /** @description When the step was skipped, or `null` when it is not skipped. */
2573
+ skipped_at: components["schemas"]["Instant"] | null;
2574
+ };
2575
+ /** @description The guided setup's progress. */
2576
+ Onboarding: {
2577
+ /** @description Every step, in the fixed order of `OnboardingStep`. */
2578
+ steps: components["schemas"]["OnboardingStepProgress"][];
2579
+ /** @description The first step neither completed nor skipped: where the owner resumes. `null` once every step is completed or skipped. */
2580
+ current_step: (components["schemas"]["OnboardingStep"] | (string & {})) | null;
2581
+ /** @description Whether any calculation in the workspace is published. */
2582
+ has_published: boolean;
2583
+ };
2584
+ OnboardingSkippedStepsSet: {
2585
+ /** @description The steps to mark skipped, at most five. A repeated step is refused with `duplicate`, an unknown one with `invalid_value`. `[]` clears every skip. */
2586
+ steps: components["schemas"]["OnboardingStep"][];
2587
+ };
2001
2588
  };
2002
2589
  responses: {
2003
2590
  /** @description `invalid_json`: the body is not one JSON object. `validation_failed`: a field, parameter, header or multipart part breaks a rule; `errors` lists every problem. */
@@ -2338,6 +2925,29 @@ export interface components {
2338
2925
  };
2339
2926
  };
2340
2927
  };
2928
+ /** @description A service the operation depends on did not respond successfully. Nothing was kept, so the request may be retried. */
2929
+ UpstreamFailed: {
2930
+ headers: {
2931
+ "X-Request-Id": components["headers"]["X-Request-Id"];
2932
+ [name: string]: unknown;
2933
+ };
2934
+ content: {
2935
+ /**
2936
+ * @example {
2937
+ * "type": "https://api.allisai.ai/errors/upstream_failed",
2938
+ * "title": "A service the API depends on did not respond successfully",
2939
+ * "status": 502,
2940
+ * "detail": "An internal error occurred. Quote the request id if you report it.",
2941
+ * "code": "upstream_failed",
2942
+ * "request_id": "3a9f6c1e2b7d4e5f8a0b1c2d3e4f5a6b"
2943
+ * }
2944
+ */
2945
+ "application/problem+json": components["schemas"]["Problem"] & {
2946
+ /** @enum {unknown} */
2947
+ code?: "upstream_failed";
2948
+ };
2949
+ };
2950
+ };
2341
2951
  /** @description The request is invalid. On `GET` the code is `invalid_json` or `validation_failed`. No body: a response to `HEAD` carries the status and headers only, and no `Content-Length`. `Content-Type` is `application/problem+json`, as on `GET`; send the request as `GET` to read the problem document. */
2342
2952
  BadRequestHead: {
2343
2953
  headers: {
@@ -2386,6 +2996,10 @@ export interface components {
2386
2996
  Limit: number;
2387
2997
  /** @description `next_cursor` from the previous page. Valid only with the filters and sort it was issued under; otherwise refused with `invalid_value`. An empty value is refused with `invalid_format`, like any empty query parameter. `limit` may change between pages. */
2388
2998
  Cursor: string;
2999
+ /** @description Page number, from 1. Reads the list in its documented order at offset `(page − 1) × limit`, and fills `total` with the count of every row matching the filters and search. Without `page` nothing is counted, and `page` and `total` are `null`. Not with `cursor`: both together are refused with `mutually_exclusive` on `cursor`. The offset must not exceed 10,000,000; a larger one is refused with `out_of_range` on `page`. A page past the last returns no rows and the true `total`. The response's `next_cursor` continues the list after the page's last row, so a cursor walk can start from any page. */
3000
+ NumberedPage: number;
3001
+ /** @description Only rows whose name holds this text, matched case-insensitively and anywhere in the name. Every character matches itself: `%`, `_` and `\` are not wildcards. 1 to 200 characters; a longer value is refused with `too_long`. An empty value, or one with leading or trailing whitespace, is refused with `invalid_format`. Combines with the filters by AND, and binds the cursor as a filter does. */
3002
+ NameSearch: components["schemas"]["SearchText"];
2389
3003
  /**
2390
3004
  * @description Start of a half-open range, inclusive. Absent means unbounded. Must not be after `to`, or it is refused with `out_of_range` on `from`. Each sent bound must be at or after `1900-01-01T00:00:00Z` and before `10000-01-01T00:00:00Z`; otherwise it is refused with `out_of_range` on its own parameter. Digits below a microsecond are dropped before any check. When both bounds are sent, `to` may be at most 731 days after `from`; a longer period is refused with `out_of_range` on `from`.
2391
3005
  * @example 2026-08-01T00:00:00Z
@@ -2406,6 +3020,28 @@ export interface components {
2406
3020
  * @example 2026-09-01T00:00:00Z
2407
3021
  */
2408
3022
  ToRequired: components["schemas"]["InstantInput"];
3023
+ /**
3024
+ * @description Start of the period of event time, inclusive. Required, and refused with `required` when missing, unless `import_batch_id` is sent; then `from` and `to` are both sent or neither, and one without the other is refused with `required` on the missing one. Must not be after `to`, or it is refused with `out_of_range` on `from`. Each sent bound must be at or after `1900-01-01T00:00:00Z` and before `10000-01-01T00:00:00Z`; otherwise it is refused with `out_of_range` on its own parameter. Digits below a microsecond are dropped before any check. `to` may be at most 731 days after `from`; a longer period is refused with `out_of_range` on `from`.
3025
+ * @example 2026-08-01T00:00:00Z
3026
+ */
3027
+ EventsFrom: components["schemas"]["InstantInput"];
3028
+ /**
3029
+ * @description End of the period of event time, exclusive. Required, and refused with `required` when missing, unless `import_batch_id` is sent; then `from` and `to` are both sent or neither. Each sent bound must be at or after `1900-01-01T00:00:00Z` and before `10000-01-01T00:00:00Z`; otherwise it is refused with `out_of_range` on its own parameter. Digits below a microsecond are dropped before any check. `to` may be at most 731 days after `from`; a longer period is refused with `out_of_range` on `from`.
3030
+ * @example 2026-09-01T00:00:00Z
3031
+ */
3032
+ EventsTo: components["schemas"]["InstantInput"];
3033
+ /** @description The arrival limit: only events the API stored before this instant. Leave it out on a view's first request, and the response issues one; send that value on later requests to read the same events. A value later than the server can yet hold still is refused with `out_of_range`, and so is one before `1900-01-01T00:00:00Z`. With `cursor`, it must name the cursor's limit, or the cursor is refused with `invalid_value`; without it, the cursor's limit applies. A cursor whose limit is later than the server can yet hold still is refused with `invalid_value` too. That happens only after a rare delay inside the database; reload the view without the cursor. With `import_batch_id`, it is issued and returned but not applied, because an import's events appear together when it commits. Otherwise an event falls below the limit a second or two after the API stores it, and later while a long request, such as a large import, is still in progress. A read straight after an ingest may not include it yet. */
3034
+ AsOf: components["schemas"]["InstantInput"];
3035
+ /** @description Only events that count toward this client: those carrying its client key, compared ignoring case and surrounding spaces, and those carrying no key from an agent assigned to this client alone. They are the events `GET /v1/clients/{id}/events` lists for it. An id that names no client in the workspace matches no event. An id in any spelling but the RFC 9562 string form is refused with `invalid_format`. */
3036
+ EventClientFilter: components["schemas"]["UuidInput"];
3037
+ /** @description Only events from this agent. An id that names no agent in the workspace matches no event. An id in any spelling but the RFC 9562 string form is refused with `invalid_format`. */
3038
+ EventAgentFilter: components["schemas"]["UuidInput"];
3039
+ /** @description Only events of this category. Any other value is refused with `invalid_value`. */
3040
+ EventCategoryFilter: components["schemas"]["EventCategory"];
3041
+ /** @description Only events with this outcome type, compared ignoring case and surrounding spaces. An empty value, or one with leading or trailing whitespace, is refused with `invalid_format`. */
3042
+ EventOutcomeTypeFilter: string;
3043
+ /** @description Only events that arrived this way. Any other value is refused with `invalid_value`. */
3044
+ EventSourceFilter: components["schemas"]["EventSource"];
2409
3045
  /** @description Optional, sent once. 1 to 255 characters of visible ASCII not starting with `"`, or a structured-field String of 1 to 255 visible ASCII characters; the quoted form `"abc"` is the same key as `abc`. A repeat within 24 hours, in the same workspace, with the same method, path, query, media type and body, replays the stored response with `Idempotent-Replayed: true`; with a different request it is `422` `idempotency_key_reused`; while the first is still running it is `409` `idempotency_key_in_use`. Only `2xx` outcomes are stored. A malformed value, `""` included, or the header sent twice is refused with `invalid_format`, located by `header`. */
2410
3046
  IdempotencyKey: string;
2411
3047
  };
@@ -2425,7 +3061,7 @@ export interface components {
2425
3061
  Location: string;
2426
3062
  /** @description `true` when this response is a replay of the stored response to an earlier request with the same `Idempotency-Key`; absent on the first response. The resource was not created again. */
2427
3063
  "Idempotent-Replayed": "true";
2428
- /** @description `no-store`: the response carries a secret or a shared report. */
3064
+ /** @description `no-store`: the request or the response carries a secret, or the response carries a shared report. */
2429
3065
  "Cache-Control": "no-store";
2430
3066
  /** @description The patch formats the resource takes, sent with every `415` to a `PATCH` (RFC 5789 §2.2, §3.1). */
2431
3067
  "Accept-Patch": "application/merge-patch+json, application/json";
@@ -2730,6 +3366,109 @@ export interface operations {
2730
3366
  500: components["responses"]["InternalError"];
2731
3367
  };
2732
3368
  };
3369
+ listEvents: {
3370
+ parameters: {
3371
+ query?: {
3372
+ /**
3373
+ * @description Start of the period of event time, inclusive. Required, and refused with `required` when missing, unless `import_batch_id` is sent; then `from` and `to` are both sent or neither, and one without the other is refused with `required` on the missing one. Must not be after `to`, or it is refused with `out_of_range` on `from`. Each sent bound must be at or after `1900-01-01T00:00:00Z` and before `10000-01-01T00:00:00Z`; otherwise it is refused with `out_of_range` on its own parameter. Digits below a microsecond are dropped before any check. `to` may be at most 731 days after `from`; a longer period is refused with `out_of_range` on `from`.
3374
+ * @example 2026-08-01T00:00:00Z
3375
+ */
3376
+ from?: components["parameters"]["EventsFrom"];
3377
+ /**
3378
+ * @description End of the period of event time, exclusive. Required, and refused with `required` when missing, unless `import_batch_id` is sent; then `from` and `to` are both sent or neither. Each sent bound must be at or after `1900-01-01T00:00:00Z` and before `10000-01-01T00:00:00Z`; otherwise it is refused with `out_of_range` on its own parameter. Digits below a microsecond are dropped before any check. `to` may be at most 731 days after `from`; a longer period is refused with `out_of_range` on `from`.
3379
+ * @example 2026-09-01T00:00:00Z
3380
+ */
3381
+ to?: components["parameters"]["EventsTo"];
3382
+ /** @description The arrival limit: only events the API stored before this instant. Leave it out on a view's first request, and the response issues one; send that value on later requests to read the same events. A value later than the server can yet hold still is refused with `out_of_range`, and so is one before `1900-01-01T00:00:00Z`. With `cursor`, it must name the cursor's limit, or the cursor is refused with `invalid_value`; without it, the cursor's limit applies. A cursor whose limit is later than the server can yet hold still is refused with `invalid_value` too. That happens only after a rare delay inside the database; reload the view without the cursor. With `import_batch_id`, it is issued and returned but not applied, because an import's events appear together when it commits. Otherwise an event falls below the limit a second or two after the API stores it, and later while a long request, such as a large import, is still in progress. A read straight after an ingest may not include it yet. */
3383
+ as_of?: components["parameters"]["AsOf"];
3384
+ /** @description Only events that count toward this client: those carrying its client key, compared ignoring case and surrounding spaces, and those carrying no key from an agent assigned to this client alone. They are the events `GET /v1/clients/{id}/events` lists for it. An id that names no client in the workspace matches no event. An id in any spelling but the RFC 9562 string form is refused with `invalid_format`. */
3385
+ client_id?: components["parameters"]["EventClientFilter"];
3386
+ /** @description Only events from this agent. An id that names no agent in the workspace matches no event. An id in any spelling but the RFC 9562 string form is refused with `invalid_format`. */
3387
+ agent_id?: components["parameters"]["EventAgentFilter"];
3388
+ /** @description Only events of this category. Any other value is refused with `invalid_value`. */
3389
+ category?: components["parameters"]["EventCategoryFilter"];
3390
+ /** @description Only events with this outcome type, compared ignoring case and surrounding spaces. An empty value, or one with leading or trailing whitespace, is refused with `invalid_format`. */
3391
+ outcome_type?: components["parameters"]["EventOutcomeTypeFilter"];
3392
+ /** @description Only events that arrived this way. Any other value is refused with `invalid_value`. */
3393
+ source?: components["parameters"]["EventSourceFilter"];
3394
+ /** @description Only the events one CSV import wrote: the `import_batch_id` the import returned. With it, `from` and `to` are optional, both or neither. `as_of` is issued and returned but not applied, because an import's events appear together when it commits, and `total` is exact. An id that names no import in the workspace matches no event. An id in any spelling but the RFC 9562 string form is refused with `invalid_format`. */
3395
+ import_batch_id?: components["schemas"]["UuidInput"];
3396
+ /** @description Sort key. `timestamp` and `cost` default to descending; `agent_name`, `attributed_by` and `source` to ascending. `attributed_by` sorts events that carried a client key apart from those that did not. `cost` puts events without a cost last in both directions. An order other than `timestamp` descending needs `page` or a cursor issued in that order; without either it is refused with `required` on `page`. */
3397
+ sort?: "timestamp" | "cost" | "agent_name" | "attributed_by" | "source";
3398
+ /** @description Sort direction. Absent means the sort key's default. */
3399
+ dir?: "asc" | "desc";
3400
+ /** @description Page size, 1 to 200. A value outside the range is refused with `out_of_range`, never clamped. */
3401
+ limit?: components["parameters"]["Limit"];
3402
+ /** @description `next_cursor` from the previous page. Valid only with the filters and sort it was issued under; otherwise refused with `invalid_value`. An empty value is refused with `invalid_format`, like any empty query parameter. `limit` may change between pages. */
3403
+ cursor?: components["parameters"]["Cursor"];
3404
+ /** @description Page number, from 1. Reads the list in the requested order at offset `(page − 1) × limit`, and fills `total` and `total_capped`. Without `page` nothing is counted, and `page`, `total` and `total_capped` are `null`. Not with `cursor`: both together are refused with `mutually_exclusive` on `cursor`. The offset must not exceed 10,000,000; a larger one is refused with `out_of_range` on `page`. A page past the last returns no rows. Under one `as_of`, a page's rows and their numbers stay the same on every request. */
3405
+ page?: number;
3406
+ };
3407
+ header?: never;
3408
+ path?: never;
3409
+ cookie?: never;
3410
+ };
3411
+ requestBody?: never;
3412
+ responses: {
3413
+ /** @description OK. */
3414
+ 200: {
3415
+ headers: {
3416
+ "X-Request-Id": components["headers"]["X-Request-Id"];
3417
+ RateLimit: components["headers"]["RateLimit"];
3418
+ "RateLimit-Policy": components["headers"]["RateLimit-Policy"];
3419
+ [name: string]: unknown;
3420
+ };
3421
+ content: {
3422
+ /**
3423
+ * @example {
3424
+ * "as_of": "2026-08-31T05:02:00Z",
3425
+ * "period": {
3426
+ * "from": "2026-08-24T05:02:00Z",
3427
+ * "to": "2026-08-31T05:02:00Z"
3428
+ * },
3429
+ * "client_id": null,
3430
+ * "currency": "JPY",
3431
+ * "page": 1,
3432
+ * "total": 1,
3433
+ * "total_capped": false,
3434
+ * "data": [
3435
+ * {
3436
+ * "id": "9007199254740993",
3437
+ * "timestamp": "2026-08-30T03:12:45.5Z",
3438
+ * "agent_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
3439
+ * "agent_name": "Support bot",
3440
+ * "category": "outcome",
3441
+ * "event_type": "ticket_closed",
3442
+ * "outcome_type": "ticket_resolved",
3443
+ * "quantity": 1,
3444
+ * "cost": null,
3445
+ * "tokens_in": null,
3446
+ * "tokens_out": null,
3447
+ * "model": null,
3448
+ * "client_key": "acme",
3449
+ * "source": "api",
3450
+ * "created_at": "2026-08-30T03:12:46.102Z",
3451
+ * "import_batch_id": null,
3452
+ * "client_id": "6f1c2d3e-4b5a-4c6d-8e7f-90a1b2c3d4e5",
3453
+ * "client_name": "Acme Logistics"
3454
+ * }
3455
+ * ],
3456
+ * "has_more": false,
3457
+ * "next_cursor": null
3458
+ * }
3459
+ */
3460
+ "application/json": components["schemas"]["EventList"];
3461
+ };
3462
+ };
3463
+ 400: components["responses"]["BadRequest"];
3464
+ 401: components["responses"]["Unauthenticated"];
3465
+ 403: components["responses"]["ForbiddenKeyOrSession"];
3466
+ 413: components["responses"]["PayloadTooLarge"];
3467
+ 414: components["responses"]["UriTooLong"];
3468
+ 429: components["responses"]["RateLimited"];
3469
+ 500: components["responses"]["InternalError"];
3470
+ };
3471
+ };
2733
3472
  ingestEvents: {
2734
3473
  parameters: {
2735
3474
  query?: never;
@@ -2818,6 +3557,205 @@ export interface operations {
2818
3557
  500: components["responses"]["InternalError"];
2819
3558
  };
2820
3559
  };
3560
+ getEventSummary: {
3561
+ parameters: {
3562
+ query: {
3563
+ /**
3564
+ * @description Start of the period, inclusive. Must not be after `to`, or it is refused with `out_of_range` on `from`. Each sent bound must be at or after `1900-01-01T00:00:00Z` and before `10000-01-01T00:00:00Z`; otherwise it is refused with `out_of_range` on its own parameter. Digits below a microsecond are dropped before any check. When both bounds are sent, `to` may be at most 731 days after `from`; a longer period is refused with `out_of_range` on `from`.
3565
+ * @example 2026-08-01T00:00:00Z
3566
+ */
3567
+ from: components["parameters"]["FromRequired"];
3568
+ /**
3569
+ * @description End of the period, exclusive. Required: an open period would prorate to the current day, so the figure would change with the day it was read. Each sent bound must be at or after `1900-01-01T00:00:00Z` and before `10000-01-01T00:00:00Z`; otherwise it is refused with `out_of_range` on its own parameter. Digits below a microsecond are dropped before any check. When both bounds are sent, `to` may be at most 731 days after `from`; a longer period is refused with `out_of_range` on `from`.
3570
+ * @example 2026-09-01T00:00:00Z
3571
+ */
3572
+ to: components["parameters"]["ToRequired"];
3573
+ /** @description The arrival limit: only events the API stored before this instant. Leave it out on a view's first request, and the response issues one; send that value on later requests to read the same events. A value later than the server can yet hold still is refused with `out_of_range`, and so is one before `1900-01-01T00:00:00Z`. With `cursor`, it must name the cursor's limit, or the cursor is refused with `invalid_value`; without it, the cursor's limit applies. A cursor whose limit is later than the server can yet hold still is refused with `invalid_value` too. That happens only after a rare delay inside the database; reload the view without the cursor. With `import_batch_id`, it is issued and returned but not applied, because an import's events appear together when it commits. Otherwise an event falls below the limit a second or two after the API stores it, and later while a long request, such as a large import, is still in progress. A read straight after an ingest may not include it yet. */
3574
+ as_of?: components["parameters"]["AsOf"];
3575
+ /** @description Only events that count toward this client: those carrying its client key, compared ignoring case and surrounding spaces, and those carrying no key from an agent assigned to this client alone. They are the events `GET /v1/clients/{id}/events` lists for it. An id that names no client in the workspace matches no event. An id in any spelling but the RFC 9562 string form is refused with `invalid_format`. */
3576
+ client_id?: components["parameters"]["EventClientFilter"];
3577
+ /** @description Only events from this agent. An id that names no agent in the workspace matches no event. An id in any spelling but the RFC 9562 string form is refused with `invalid_format`. */
3578
+ agent_id?: components["parameters"]["EventAgentFilter"];
3579
+ /** @description Only events of this category. Any other value is refused with `invalid_value`. */
3580
+ category?: components["parameters"]["EventCategoryFilter"];
3581
+ /** @description Only events with this outcome type, compared ignoring case and surrounding spaces. An empty value, or one with leading or trailing whitespace, is refused with `invalid_format`. */
3582
+ outcome_type?: components["parameters"]["EventOutcomeTypeFilter"];
3583
+ /** @description Only events that arrived this way. Any other value is refused with `invalid_value`. */
3584
+ source?: components["parameters"]["EventSourceFilter"];
3585
+ /** @description Only the events one CSV import wrote: the `import_batch_id` the import returned. `as_of` is then issued and returned but not applied, as on the list. An id that names no import in the workspace matches no event. An id in any spelling but the RFC 9562 string form is refused with `invalid_format`. */
3586
+ import_batch_id?: components["schemas"]["UuidInput"];
3587
+ };
3588
+ header?: never;
3589
+ path?: never;
3590
+ cookie?: never;
3591
+ };
3592
+ requestBody?: never;
3593
+ responses: {
3594
+ /** @description OK. */
3595
+ 200: {
3596
+ headers: {
3597
+ "X-Request-Id": components["headers"]["X-Request-Id"];
3598
+ RateLimit: components["headers"]["RateLimit"];
3599
+ "RateLimit-Policy": components["headers"]["RateLimit-Policy"];
3600
+ [name: string]: unknown;
3601
+ };
3602
+ content: {
3603
+ /**
3604
+ * @example {
3605
+ * "as_of": "2026-08-31T05:02:00Z",
3606
+ * "period": {
3607
+ * "from": "2026-08-28T15:00:00Z",
3608
+ * "to": "2026-08-31T15:00:00Z"
3609
+ * },
3610
+ * "client_id": null,
3611
+ * "total": 5,
3612
+ * "days": [
3613
+ * {
3614
+ * "start": "2026-08-28T15:00:00Z",
3615
+ * "count": 3
3616
+ * },
3617
+ * {
3618
+ * "start": "2026-08-29T15:00:00Z",
3619
+ * "count": 0
3620
+ * },
3621
+ * {
3622
+ * "start": "2026-08-30T15:00:00Z",
3623
+ * "count": 2
3624
+ * }
3625
+ * ],
3626
+ * "categories": [
3627
+ * {
3628
+ * "category": "session",
3629
+ * "count": 0
3630
+ * },
3631
+ * {
3632
+ * "category": "task",
3633
+ * "count": 1
3634
+ * },
3635
+ * {
3636
+ * "category": "model",
3637
+ * "count": 3
3638
+ * },
3639
+ * {
3640
+ * "category": "outcome",
3641
+ * "count": 1
3642
+ * },
3643
+ * {
3644
+ * "category": "exception",
3645
+ * "count": 0
3646
+ * }
3647
+ * ]
3648
+ * }
3649
+ */
3650
+ "application/json": components["schemas"]["EventSummary"];
3651
+ };
3652
+ };
3653
+ 400: components["responses"]["BadRequest"];
3654
+ 401: components["responses"]["Unauthenticated"];
3655
+ 403: components["responses"]["ForbiddenKeyOrSession"];
3656
+ 413: components["responses"]["PayloadTooLarge"];
3657
+ 414: components["responses"]["UriTooLong"];
3658
+ 429: components["responses"]["RateLimited"];
3659
+ 500: components["responses"]["InternalError"];
3660
+ };
3661
+ };
3662
+ listEventArrivals: {
3663
+ parameters: {
3664
+ query?: {
3665
+ /** @description Start of the arrival window, inclusive: only events the API stored at or after this instant. At most 24 hours before the request; an earlier one is refused with `out_of_range`, and a feed further behind reloads without `since`. It must not be after the response's `as_of`, the one sent, the cursor's or the one issued, or it is refused with `out_of_range`; reload the feed without `since`. Equal to it, the window is empty. Without it, `count` and `count_capped` are `null`. */
3666
+ since?: components["schemas"]["InstantInput"];
3667
+ /** @description The arrival limit: only events the API stored before this instant. Leave it out on a view's first request, and the response issues one; send that value on later requests to read the same events. A value later than the server can yet hold still is refused with `out_of_range`, and so is one before `1900-01-01T00:00:00Z`. With `cursor`, it must name the cursor's limit, or the cursor is refused with `invalid_value`; without it, the cursor's limit applies. A cursor whose limit is later than the server can yet hold still is refused with `invalid_value` too. That happens only after a rare delay inside the database; reload the view without the cursor. With `import_batch_id`, it is issued and returned but not applied, because an import's events appear together when it commits. Otherwise an event falls below the limit a second or two after the API stores it, and later while a long request, such as a large import, is still in progress. A read straight after an ingest may not include it yet. */
3668
+ as_of?: components["parameters"]["AsOf"];
3669
+ /**
3670
+ * @description Start of a half-open range, inclusive. Absent means unbounded. Must not be after `to`, or it is refused with `out_of_range` on `from`. Each sent bound must be at or after `1900-01-01T00:00:00Z` and before `10000-01-01T00:00:00Z`; otherwise it is refused with `out_of_range` on its own parameter. Digits below a microsecond are dropped before any check. When both bounds are sent, `to` may be at most 731 days after `from`; a longer period is refused with `out_of_range` on `from`.
3671
+ * @example 2026-08-01T00:00:00Z
3672
+ */
3673
+ from?: components["parameters"]["FromOptional"];
3674
+ /**
3675
+ * @description End of a half-open range, exclusive. Absent means unbounded. Each sent bound must be at or after `1900-01-01T00:00:00Z` and before `10000-01-01T00:00:00Z`; otherwise it is refused with `out_of_range` on its own parameter. Digits below a microsecond are dropped before any check. When both bounds are sent, `to` may be at most 731 days after `from`; a longer period is refused with `out_of_range` on `from`.
3676
+ * @example 2026-09-01T00:00:00Z
3677
+ */
3678
+ to?: components["parameters"]["ToOptional"];
3679
+ /** @description Only events that count toward this client: those carrying its client key, compared ignoring case and surrounding spaces, and those carrying no key from an agent assigned to this client alone. They are the events `GET /v1/clients/{id}/events` lists for it. An id that names no client in the workspace matches no event. An id in any spelling but the RFC 9562 string form is refused with `invalid_format`. */
3680
+ client_id?: components["parameters"]["EventClientFilter"];
3681
+ /** @description Only events from this agent. An id that names no agent in the workspace matches no event. An id in any spelling but the RFC 9562 string form is refused with `invalid_format`. */
3682
+ agent_id?: components["parameters"]["EventAgentFilter"];
3683
+ /** @description Only events of this category. Any other value is refused with `invalid_value`. */
3684
+ category?: components["parameters"]["EventCategoryFilter"];
3685
+ /** @description Only events with this outcome type, compared ignoring case and surrounding spaces. An empty value, or one with leading or trailing whitespace, is refused with `invalid_format`. */
3686
+ outcome_type?: components["parameters"]["EventOutcomeTypeFilter"];
3687
+ /** @description Only events that arrived this way. Any other value is refused with `invalid_value`. */
3688
+ source?: components["parameters"]["EventSourceFilter"];
3689
+ /** @description Page size, 1 to 200. A value outside the range is refused with `out_of_range`, never clamped. */
3690
+ limit?: components["parameters"]["Limit"];
3691
+ /** @description `next_cursor` from the previous page. Valid only with the filters and sort it was issued under; otherwise refused with `invalid_value`. An empty value is refused with `invalid_format`, like any empty query parameter. `limit` may change between pages. */
3692
+ cursor?: components["parameters"]["Cursor"];
3693
+ };
3694
+ header?: never;
3695
+ path?: never;
3696
+ cookie?: never;
3697
+ };
3698
+ requestBody?: never;
3699
+ responses: {
3700
+ /** @description OK. */
3701
+ 200: {
3702
+ headers: {
3703
+ "X-Request-Id": components["headers"]["X-Request-Id"];
3704
+ RateLimit: components["headers"]["RateLimit"];
3705
+ "RateLimit-Policy": components["headers"]["RateLimit-Policy"];
3706
+ [name: string]: unknown;
3707
+ };
3708
+ content: {
3709
+ /**
3710
+ * @example {
3711
+ * "as_of": "2026-08-31T05:02:05Z",
3712
+ * "since": "2026-08-31T05:02:00Z",
3713
+ * "period": {
3714
+ * "from": null,
3715
+ * "to": null
3716
+ * },
3717
+ * "client_id": null,
3718
+ * "currency": "JPY",
3719
+ * "count": 1,
3720
+ * "count_capped": false,
3721
+ * "data": [
3722
+ * {
3723
+ * "id": "9007199254741001",
3724
+ * "timestamp": "2026-08-31T05:02:01Z",
3725
+ * "agent_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
3726
+ * "agent_name": "Support bot",
3727
+ * "category": "model",
3728
+ * "event_type": "completion",
3729
+ * "outcome_type": null,
3730
+ * "quantity": 1,
3731
+ * "cost": 0.3683,
3732
+ * "tokens_in": 1840,
3733
+ * "tokens_out": 312,
3734
+ * "model": "gpt-4o",
3735
+ * "client_key": null,
3736
+ * "source": "api",
3737
+ * "created_at": "2026-08-31T05:02:02.481Z",
3738
+ * "import_batch_id": null,
3739
+ * "client_id": "6f1c2d3e-4b5a-4c6d-8e7f-90a1b2c3d4e5",
3740
+ * "client_name": "Acme Logistics"
3741
+ * }
3742
+ * ],
3743
+ * "has_more": false,
3744
+ * "next_cursor": null
3745
+ * }
3746
+ */
3747
+ "application/json": components["schemas"]["EventArrivalList"];
3748
+ };
3749
+ };
3750
+ 400: components["responses"]["BadRequest"];
3751
+ 401: components["responses"]["Unauthenticated"];
3752
+ 403: components["responses"]["ForbiddenKeyOrSession"];
3753
+ 413: components["responses"]["PayloadTooLarge"];
3754
+ 414: components["responses"]["UriTooLong"];
3755
+ 429: components["responses"]["RateLimited"];
3756
+ 500: components["responses"]["InternalError"];
3757
+ };
3758
+ };
2821
3759
  previewImport: {
2822
3760
  parameters: {
2823
3761
  query?: never;
@@ -2939,6 +3877,62 @@ export interface operations {
2939
3877
  500: components["responses"]["InternalError"];
2940
3878
  };
2941
3879
  };
3880
+ listImports: {
3881
+ parameters: {
3882
+ query?: {
3883
+ /** @description Page size, 1 to 200. A value outside the range is refused with `out_of_range`, never clamped. */
3884
+ limit?: components["parameters"]["Limit"];
3885
+ /** @description `next_cursor` from the previous page. Valid only with the filters and sort it was issued under; otherwise refused with `invalid_value`. An empty value is refused with `invalid_format`, like any empty query parameter. `limit` may change between pages. */
3886
+ cursor?: components["parameters"]["Cursor"];
3887
+ /** @description Page number, from 1. Reads the list in its documented order at offset `(page − 1) × limit`, and fills `total` with the count of every row matching the filters and search. Without `page` nothing is counted, and `page` and `total` are `null`. Not with `cursor`: both together are refused with `mutually_exclusive` on `cursor`. The offset must not exceed 10,000,000; a larger one is refused with `out_of_range` on `page`. A page past the last returns no rows and the true `total`. The response's `next_cursor` continues the list after the page's last row, so a cursor walk can start from any page. */
3888
+ page?: components["parameters"]["NumberedPage"];
3889
+ };
3890
+ header?: never;
3891
+ path?: never;
3892
+ cookie?: never;
3893
+ };
3894
+ requestBody?: never;
3895
+ responses: {
3896
+ /** @description OK. */
3897
+ 200: {
3898
+ headers: {
3899
+ "X-Request-Id": components["headers"]["X-Request-Id"];
3900
+ RateLimit: components["headers"]["RateLimit"];
3901
+ "RateLimit-Policy": components["headers"]["RateLimit-Policy"];
3902
+ [name: string]: unknown;
3903
+ };
3904
+ content: {
3905
+ /**
3906
+ * @example {
3907
+ * "page": 1,
3908
+ * "total": 1,
3909
+ * "data": [
3910
+ * {
3911
+ * "id": "9c0d1e2f-3a4b-4c5d-9e6f-708192a3b4c5",
3912
+ * "filename": "support-bot-august.csv",
3913
+ * "total_rows": 1200,
3914
+ * "accepted": 1180,
3915
+ * "duplicates": 15,
3916
+ * "rejected": 5,
3917
+ * "created_at": "2026-09-01T02:30:00Z"
3918
+ * }
3919
+ * ],
3920
+ * "has_more": false,
3921
+ * "next_cursor": null
3922
+ * }
3923
+ */
3924
+ "application/json": components["schemas"]["ImportList"];
3925
+ };
3926
+ };
3927
+ 400: components["responses"]["BadRequest"];
3928
+ 401: components["responses"]["Unauthenticated"];
3929
+ 403: components["responses"]["ForbiddenKeyOrSession"];
3930
+ 413: components["responses"]["PayloadTooLarge"];
3931
+ 414: components["responses"]["UriTooLong"];
3932
+ 429: components["responses"]["RateLimited"];
3933
+ 500: components["responses"]["InternalError"];
3934
+ };
3935
+ };
2942
3936
  commitImport: {
2943
3937
  parameters: {
2944
3938
  query?: never;
@@ -3046,13 +4040,77 @@ export interface operations {
3046
4040
  500: components["responses"]["InternalError"];
3047
4041
  };
3048
4042
  };
4043
+ getImport: {
4044
+ parameters: {
4045
+ query?: never;
4046
+ header?: never;
4047
+ path: {
4048
+ /** @description A resource id, in the RFC 9562 string form in either case. A malformed or unknown id is `404` `not_found`, so the response never reveals whether a resource exists; a spelling such as `{<uuid>}` or `urn:uuid:<uuid>` is malformed. */
4049
+ id: components["parameters"]["Id"];
4050
+ };
4051
+ cookie?: never;
4052
+ };
4053
+ requestBody?: never;
4054
+ responses: {
4055
+ /** @description OK. */
4056
+ 200: {
4057
+ headers: {
4058
+ "X-Request-Id": components["headers"]["X-Request-Id"];
4059
+ RateLimit: components["headers"]["RateLimit"];
4060
+ "RateLimit-Policy": components["headers"]["RateLimit-Policy"];
4061
+ [name: string]: unknown;
4062
+ };
4063
+ content: {
4064
+ /**
4065
+ * @example {
4066
+ * "id": "9c0d1e2f-3a4b-4c5d-9e6f-708192a3b4c5",
4067
+ * "filename": "support-bot-august.csv",
4068
+ * "total_rows": 1200,
4069
+ * "accepted": 1180,
4070
+ * "duplicates": 15,
4071
+ * "rejected": 5,
4072
+ * "created_at": "2026-09-01T02:30:00Z",
4073
+ * "mapping": {
4074
+ * "columns": {
4075
+ * "timestamp": "Time",
4076
+ * "agent_key": "Agent",
4077
+ * "client_key": "Client",
4078
+ * "category": "Category",
4079
+ * "event_type": "Type",
4080
+ * "cost": "Cost"
4081
+ * },
4082
+ * "constants": {},
4083
+ * "timezone": "Asia/Tokyo",
4084
+ * "delimiter": ","
4085
+ * }
4086
+ * }
4087
+ */
4088
+ "application/json": components["schemas"]["Import"];
4089
+ };
4090
+ };
4091
+ 400: components["responses"]["BadRequest"];
4092
+ 401: components["responses"]["Unauthenticated"];
4093
+ 403: components["responses"]["ForbiddenKeyOrSession"];
4094
+ 404: components["responses"]["NotFound"];
4095
+ 413: components["responses"]["PayloadTooLarge"];
4096
+ 414: components["responses"]["UriTooLong"];
4097
+ 429: components["responses"]["RateLimited"];
4098
+ 500: components["responses"]["InternalError"];
4099
+ };
4100
+ };
3049
4101
  listClients: {
3050
4102
  parameters: {
3051
4103
  query?: {
4104
+ /** @description Only rows whose name holds this text, matched case-insensitively and anywhere in the name. Every character matches itself: `%`, `_` and `\` are not wildcards. 1 to 200 characters; a longer value is refused with `too_long`. An empty value, or one with leading or trailing whitespace, is refused with `invalid_format`. Combines with the filters by AND, and binds the cursor as a filter does. */
4105
+ q?: components["parameters"]["NameSearch"];
4106
+ /** @description Only clients with this status. Any other value is refused with `invalid_value`. */
4107
+ status?: components["schemas"]["ClientStatus"];
3052
4108
  /** @description Page size, 1 to 200. A value outside the range is refused with `out_of_range`, never clamped. */
3053
4109
  limit?: components["parameters"]["Limit"];
3054
4110
  /** @description `next_cursor` from the previous page. Valid only with the filters and sort it was issued under; otherwise refused with `invalid_value`. An empty value is refused with `invalid_format`, like any empty query parameter. `limit` may change between pages. */
3055
4111
  cursor?: components["parameters"]["Cursor"];
4112
+ /** @description Page number, from 1. Reads the list in its documented order at offset `(page − 1) × limit`, and fills `total` with the count of every row matching the filters and search. Without `page` nothing is counted, and `page` and `total` are `null`. Not with `cursor`: both together are refused with `mutually_exclusive` on `cursor`. The offset must not exceed 10,000,000; a larger one is refused with `out_of_range` on `page`. A page past the last returns no rows and the true `total`. The response's `next_cursor` continues the list after the page's last row, so a cursor walk can start from any page. */
4113
+ page?: components["parameters"]["NumberedPage"];
3056
4114
  };
3057
4115
  header?: never;
3058
4116
  path?: never;
@@ -3071,13 +4129,16 @@ export interface operations {
3071
4129
  content: {
3072
4130
  /**
3073
4131
  * @example {
4132
+ * "page": 1,
4133
+ * "total": 1,
3074
4134
  * "data": [
3075
4135
  * {
3076
4136
  * "id": "6f1c2d3e-4b5a-4c6d-8e7f-90a1b2c3d4e5",
3077
4137
  * "name": "Acme Logistics",
3078
4138
  * "status": "active",
3079
4139
  * "client_key": "acme",
3080
- * "renewal_date": "2026-12-31",
4140
+ * "renewal_date": "2030-12-31",
4141
+ * "renewal_term": "annual",
3081
4142
  * "notes": "",
3082
4143
  * "created_at": "2026-07-14T09:30:00Z"
3083
4144
  * }
@@ -3115,7 +4176,8 @@ export interface operations {
3115
4176
  * "name": "Acme Logistics",
3116
4177
  * "status": "active",
3117
4178
  * "client_key": "acme",
3118
- * "renewal_date": "2026-12-31"
4179
+ * "renewal_date": "2030-12-31",
4180
+ * "renewal_term": "annual"
3119
4181
  * }
3120
4182
  */
3121
4183
  "application/json": components["schemas"]["ClientCreate"];
@@ -3139,7 +4201,8 @@ export interface operations {
3139
4201
  * "name": "Acme Logistics",
3140
4202
  * "status": "active",
3141
4203
  * "client_key": "acme",
3142
- * "renewal_date": "2026-12-31",
4204
+ * "renewal_date": "2030-12-31",
4205
+ * "renewal_term": "annual",
3143
4206
  * "notes": "",
3144
4207
  * "created_at": "2026-07-14T09:30:00Z"
3145
4208
  * }
@@ -3164,7 +4227,7 @@ export interface operations {
3164
4227
  * "type": "https://api.allisai.ai/errors/client_key_in_use",
3165
4228
  * "title": "The client key is in use",
3166
4229
  * "status": 409,
3167
- * "detail": "Another client in the workspace already has this `client_key`.",
4230
+ * "detail": "Another client in the workspace already has this `client_key`; keys are compared ignoring case.",
3168
4231
  * "code": "client_key_in_use",
3169
4232
  * "request_id": "3a9f6c1e2b7d4e5f8a0b1c2d3e4f5a6b"
3170
4233
  * }
@@ -3210,7 +4273,8 @@ export interface operations {
3210
4273
  * "name": "Acme Logistics",
3211
4274
  * "status": "active",
3212
4275
  * "client_key": "acme",
3213
- * "renewal_date": "2026-12-31",
4276
+ * "renewal_date": "2030-12-31",
4277
+ * "renewal_term": "annual",
3214
4278
  * "notes": "",
3215
4279
  * "created_at": "2026-07-14T09:30:00Z",
3216
4280
  * "agents": [
@@ -3327,7 +4391,8 @@ export interface operations {
3327
4391
  * "name": "Acme Logistics",
3328
4392
  * "status": "churned",
3329
4393
  * "client_key": "acme",
3330
- * "renewal_date": "2026-12-31",
4394
+ * "renewal_date": "2030-12-31",
4395
+ * "renewal_term": "annual",
3331
4396
  * "notes": "",
3332
4397
  * "created_at": "2026-07-14T09:30:00Z"
3333
4398
  * }
@@ -3460,6 +4525,7 @@ export interface operations {
3460
4525
  * "currency": "JPY",
3461
4526
  * "created_at": "2026-07-20T01:00:00Z",
3462
4527
  * "updated_at": "2026-08-02T04:15:00Z",
4528
+ * "archived_at": null,
3463
4529
  * "line_items": [
3464
4530
  * {
3465
4531
  * "id": "4d5e6f7a-8b9c-4d0e-9f1a-3b4c5d6e7f80",
@@ -3563,6 +4629,7 @@ export interface operations {
3563
4629
  * "currency": "JPY",
3564
4630
  * "created_at": "2026-07-20T01:00:00Z",
3565
4631
  * "updated_at": "2026-07-20T01:00:00Z",
4632
+ * "archived_at": null,
3566
4633
  * "line_items": [
3567
4634
  * {
3568
4635
  * "id": "4d5e6f7a-8b9c-4d0e-9f1a-3b4c5d6e7f80",
@@ -3718,6 +4785,7 @@ export interface operations {
3718
4785
  * "currency": "JPY",
3719
4786
  * "created_at": "2026-07-20T01:00:00Z",
3720
4787
  * "updated_at": "2026-08-02T04:15:00Z",
4788
+ * "archived_at": "2026-08-02T04:15:00Z",
3721
4789
  * "line_items": [
3722
4790
  * {
3723
4791
  * "id": "4d5e6f7a-8b9c-4d0e-9f1a-3b4c5d6e7f80",
@@ -3829,6 +4897,7 @@ export interface operations {
3829
4897
  * "currency": "JPY",
3830
4898
  * "created_at": "2026-07-20T01:00:00Z",
3831
4899
  * "updated_at": "2026-08-02T04:15:00Z",
4900
+ * "archived_at": null,
3832
4901
  * "line_items": [
3833
4902
  * {
3834
4903
  * "id": "4d5e6f7a-8b9c-4d0e-9f1a-3b4c5d6e7f80",
@@ -4405,7 +5474,11 @@ export interface operations {
4405
5474
  * "tokens_out": null,
4406
5475
  * "model": null,
4407
5476
  * "client_key": "acme",
4408
- * "source": "api"
5477
+ * "source": "api",
5478
+ * "created_at": "2026-08-14T03:12:46.102Z",
5479
+ * "import_batch_id": null,
5480
+ * "client_id": "6f1c2d3e-4b5a-4c6d-8e7f-90a1b2c3d4e5",
5481
+ * "client_name": "Acme Logistics"
4409
5482
  * },
4410
5483
  * {
4411
5484
  * "id": "9007199254740992",
@@ -4421,7 +5494,11 @@ export interface operations {
4421
5494
  * "tokens_out": 312,
4422
5495
  * "model": "gpt-4o",
4423
5496
  * "client_key": null,
4424
- * "source": "csv"
5497
+ * "source": "csv",
5498
+ * "created_at": "2026-09-01T00:20:00Z",
5499
+ * "import_batch_id": "4d3c2b1a-0f9e-4d8c-b7a6-5f4e3d2c1b0a",
5500
+ * "client_id": "6f1c2d3e-4b5a-4c6d-8e7f-90a1b2c3d4e5",
5501
+ * "client_name": "Acme Logistics"
4425
5502
  * }
4426
5503
  * ],
4427
5504
  * "has_more": false,
@@ -4473,6 +5550,7 @@ export interface operations {
4473
5550
  * {
4474
5551
  * "id": "7a8b9c0d-1e2f-4a3b-9c4d-5e6f708192a3",
4475
5552
  * "client_id": "6f1c2d3e-4b5a-4c6d-8e7f-90a1b2c3d4e5",
5553
+ * "client_name": "Acme Logistics",
4476
5554
  * "state": "published",
4477
5555
  * "period": {
4478
5556
  * "from": "2026-08-01T00:00:00Z",
@@ -4497,7 +5575,8 @@ export interface operations {
4497
5575
  * "created_at": "2026-09-02T00:10:00Z",
4498
5576
  * "validated_at": "2026-09-02T00:40:00Z",
4499
5577
  * "published_at": "2026-09-02T00:45:00Z",
4500
- * "is_current": true
5578
+ * "is_current": true,
5579
+ * "coverage_findings": 2
4501
5580
  * }
4502
5581
  * ],
4503
5582
  * "has_more": false,
@@ -4809,10 +5888,16 @@ export interface operations {
4809
5888
  listAgents: {
4810
5889
  parameters: {
4811
5890
  query?: {
5891
+ /** @description Only rows whose name holds this text, matched case-insensitively and anywhere in the name. Every character matches itself: `%`, `_` and `\` are not wildcards. 1 to 200 characters; a longer value is refused with `too_long`. An empty value, or one with leading or trailing whitespace, is refused with `invalid_format`. Combines with the filters by AND, and binds the cursor as a filter does. */
5892
+ q?: components["parameters"]["NameSearch"];
5893
+ /** @description Only agents with this status. Any other value is refused with `invalid_value`. */
5894
+ status?: components["schemas"]["AgentStatus"];
4812
5895
  /** @description Page size, 1 to 200. A value outside the range is refused with `out_of_range`, never clamped. */
4813
5896
  limit?: components["parameters"]["Limit"];
4814
5897
  /** @description `next_cursor` from the previous page. Valid only with the filters and sort it was issued under; otherwise refused with `invalid_value`. An empty value is refused with `invalid_format`, like any empty query parameter. `limit` may change between pages. */
4815
5898
  cursor?: components["parameters"]["Cursor"];
5899
+ /** @description Page number, from 1. Reads the list in its documented order at offset `(page − 1) × limit`, and fills `total` with the count of every row matching the filters and search. Without `page` nothing is counted, and `page` and `total` are `null`. Not with `cursor`: both together are refused with `mutually_exclusive` on `cursor`. The offset must not exceed 10,000,000; a larger one is refused with `out_of_range` on `page`. A page past the last returns no rows and the true `total`. The response's `next_cursor` continues the list after the page's last row, so a cursor walk can start from any page. */
5900
+ page?: components["parameters"]["NumberedPage"];
4816
5901
  };
4817
5902
  header?: never;
4818
5903
  path?: never;
@@ -4831,6 +5916,8 @@ export interface operations {
4831
5916
  content: {
4832
5917
  /**
4833
5918
  * @example {
5919
+ * "page": null,
5920
+ * "total": null,
4834
5921
  * "data": [
4835
5922
  * {
4836
5923
  * "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
@@ -5137,10 +6224,18 @@ export interface operations {
5137
6224
  listValueModels: {
5138
6225
  parameters: {
5139
6226
  query?: {
6227
+ /** @description Only rows whose name holds this text, matched case-insensitively and anywhere in the name. Every character matches itself: `%`, `_` and `\` are not wildcards. 1 to 200 characters; a longer value is refused with `too_long`. An empty value, or one with leading or trailing whitespace, is refused with `invalid_format`. Combines with the filters by AND, and binds the cursor as a filter does. */
6228
+ q?: components["parameters"]["NameSearch"];
6229
+ /** @description Only models with this status. Any other value is refused with `invalid_value`. */
6230
+ status?: components["schemas"]["ValueModelStatus"];
6231
+ /** @description Only this client's models. An id that names no client in the workspace matches no model, so the list is empty. An id in any spelling but the RFC 9562 string form is refused with `invalid_format`. */
6232
+ client_id?: components["schemas"]["UuidInput"];
5140
6233
  /** @description Page size, 1 to 200. A value outside the range is refused with `out_of_range`, never clamped. */
5141
6234
  limit?: components["parameters"]["Limit"];
5142
6235
  /** @description `next_cursor` from the previous page. Valid only with the filters and sort it was issued under; otherwise refused with `invalid_value`. An empty value is refused with `invalid_format`, like any empty query parameter. `limit` may change between pages. */
5143
6236
  cursor?: components["parameters"]["Cursor"];
6237
+ /** @description Page number, from 1. Reads the list in its documented order at offset `(page − 1) × limit`, and fills `total` with the count of every row matching the filters and search. Without `page` nothing is counted, and `page` and `total` are `null`. Not with `cursor`: both together are refused with `mutually_exclusive` on `cursor`. The offset must not exceed 10,000,000; a larger one is refused with `out_of_range` on `page`. A page past the last returns no rows and the true `total`. The response's `next_cursor` continues the list after the page's last row, so a cursor walk can start from any page. */
6238
+ page?: components["parameters"]["NumberedPage"];
5144
6239
  };
5145
6240
  header?: never;
5146
6241
  path?: never;
@@ -5159,6 +6254,8 @@ export interface operations {
5159
6254
  content: {
5160
6255
  /**
5161
6256
  * @example {
6257
+ * "page": null,
6258
+ * "total": null,
5162
6259
  * "data": [
5163
6260
  * {
5164
6261
  * "id": "3c4d5e6f-7a8b-4c9d-8e0f-2a3b4c5d6e7f",
@@ -5219,6 +6316,7 @@ export interface operations {
5219
6316
  * "currency": "JPY",
5220
6317
  * "created_at": "2026-07-20T01:00:00Z",
5221
6318
  * "updated_at": "2026-08-02T04:15:00Z",
6319
+ * "archived_at": null,
5222
6320
  * "line_items": [
5223
6321
  * {
5224
6322
  * "id": "4d5e6f7a-8b9c-4d0e-9f1a-3b4c5d6e7f80",
@@ -5370,10 +6468,18 @@ export interface operations {
5370
6468
  listCostLineItems: {
5371
6469
  parameters: {
5372
6470
  query?: {
6471
+ /** @description Only line items whose label holds this text, matched case-insensitively and anywhere in the label. Every character matches itself: `%`, `_` and `\` are not wildcards. 1 to 200 characters; a longer value is refused with `too_long`. An empty value, or one with leading or trailing whitespace, is refused with `invalid_format`. Combines with the filters by AND, and binds the cursor as a filter does. */
6472
+ q?: components["schemas"]["SearchText"];
6473
+ /** @description Only line items charged to a client, or only those charged to an agent. Any other value is refused with `invalid_value`. */
6474
+ target_kind?: components["schemas"]["CostTargetKind"];
6475
+ /** @description Only line items charged to this client or agent, the line item's `target.id`. An id that names nothing in the workspace matches no line item, so the list is empty. An id in any spelling but the RFC 9562 string form is refused with `invalid_format`. */
6476
+ target_id?: components["schemas"]["UuidInput"];
5373
6477
  /** @description Page size, 1 to 200. A value outside the range is refused with `out_of_range`, never clamped. */
5374
6478
  limit?: components["parameters"]["Limit"];
5375
6479
  /** @description `next_cursor` from the previous page. Valid only with the filters and sort it was issued under; otherwise refused with `invalid_value`. An empty value is refused with `invalid_format`, like any empty query parameter. `limit` may change between pages. */
5376
6480
  cursor?: components["parameters"]["Cursor"];
6481
+ /** @description Page number, from 1. Reads the list in its documented order at offset `(page − 1) × limit`, and fills `total` with the count of every row matching the filters and search. Without `page` nothing is counted, and `page` and `total` are `null`. Not with `cursor`: both together are refused with `mutually_exclusive` on `cursor`. The offset must not exceed 10,000,000; a larger one is refused with `out_of_range` on `page`. A page past the last returns no rows and the true `total`. The response's `next_cursor` continues the list after the page's last row, so a cursor walk can start from any page. */
6482
+ page?: components["parameters"]["NumberedPage"];
5377
6483
  };
5378
6484
  header?: never;
5379
6485
  path?: never;
@@ -5392,6 +6498,8 @@ export interface operations {
5392
6498
  content: {
5393
6499
  /**
5394
6500
  * @example {
6501
+ * "page": null,
6502
+ * "total": null,
5395
6503
  * "data": [
5396
6504
  * {
5397
6505
  * "id": "5e6f7a8b-9c0d-4e1f-8a2b-4c5d6e7f8091",
@@ -5785,6 +6893,90 @@ export interface operations {
5785
6893
  500: components["responses"]["InternalError"];
5786
6894
  };
5787
6895
  };
6896
+ listCalculations: {
6897
+ parameters: {
6898
+ query?: {
6899
+ /** @description Only this client's calculations. An id that names no client in the workspace matches no calculation, so the list is empty. An id in any spelling but the RFC 9562 string form is refused with `invalid_format`. */
6900
+ client_id?: components["schemas"]["UuidInput"];
6901
+ /** @description Only calculations in this state. Any other value is refused with `invalid_value`. */
6902
+ state?: components["schemas"]["CalculationState"];
6903
+ /** @description Only calculations whose period is exactly this calendar month in UTC, from its first instant to the first instant of the next. A period with any other bounds, such as a quarter, a week inside the month, or the month bounded at another offset, does not match. A value not in `YYYY-MM` form is refused with `invalid_format`, and a month before `1900-01` or after `9999-12` with `out_of_range`. */
6904
+ month?: components["schemas"]["Month"];
6905
+ /** @description Page size, 1 to 200. A value outside the range is refused with `out_of_range`, never clamped. */
6906
+ limit?: components["parameters"]["Limit"];
6907
+ /** @description `next_cursor` from the previous page. Valid only with the filters and sort it was issued under; otherwise refused with `invalid_value`. An empty value is refused with `invalid_format`, like any empty query parameter. `limit` may change between pages. */
6908
+ cursor?: components["parameters"]["Cursor"];
6909
+ /** @description Page number, from 1. Reads the list in its documented order at offset `(page − 1) × limit`, and fills `total` with the count of every row matching the filters and search. Without `page` nothing is counted, and `page` and `total` are `null`. Not with `cursor`: both together are refused with `mutually_exclusive` on `cursor`. The offset must not exceed 10,000,000; a larger one is refused with `out_of_range` on `page`. A page past the last returns no rows and the true `total`. The response's `next_cursor` continues the list after the page's last row, so a cursor walk can start from any page. */
6910
+ page?: components["parameters"]["NumberedPage"];
6911
+ };
6912
+ header?: never;
6913
+ path?: never;
6914
+ cookie?: never;
6915
+ };
6916
+ requestBody?: never;
6917
+ responses: {
6918
+ /** @description OK. */
6919
+ 200: {
6920
+ headers: {
6921
+ "X-Request-Id": components["headers"]["X-Request-Id"];
6922
+ RateLimit: components["headers"]["RateLimit"];
6923
+ "RateLimit-Policy": components["headers"]["RateLimit-Policy"];
6924
+ [name: string]: unknown;
6925
+ };
6926
+ content: {
6927
+ /**
6928
+ * @example {
6929
+ * "page": 1,
6930
+ * "total": 1,
6931
+ * "data": [
6932
+ * {
6933
+ * "id": "7a8b9c0d-1e2f-4a3b-9c4d-5e6f708192a3",
6934
+ * "client_id": "6f1c2d3e-4b5a-4c6d-8e7f-90a1b2c3d4e5",
6935
+ * "client_name": "Acme Logistics",
6936
+ * "state": "published",
6937
+ * "period": {
6938
+ * "from": "2026-08-01T00:00:00Z",
6939
+ * "to": "2026-09-01T00:00:00Z"
6940
+ * },
6941
+ * "currency": "JPY",
6942
+ * "minor_units": 0,
6943
+ * "value_total": 408000,
6944
+ * "cost_total": 85100,
6945
+ * "ratios": {
6946
+ * "roi": 3.7943595769682728,
6947
+ * "value_to_cost": 4.794359576968272,
6948
+ * "undefined_reason": null
6949
+ * },
6950
+ * "checklist": {
6951
+ * "coverage_confirmed": true,
6952
+ * "counts_spot_checked": true,
6953
+ * "costs_reviewed": true,
6954
+ * "unit_values_current": true,
6955
+ * "note": "Spot-checked 20 tickets against the helpdesk export."
6956
+ * },
6957
+ * "created_at": "2026-09-02T00:10:00Z",
6958
+ * "validated_at": "2026-09-02T00:40:00Z",
6959
+ * "published_at": "2026-09-02T00:45:00Z",
6960
+ * "is_current": true,
6961
+ * "coverage_findings": 2
6962
+ * }
6963
+ * ],
6964
+ * "has_more": false,
6965
+ * "next_cursor": null
6966
+ * }
6967
+ */
6968
+ "application/json": components["schemas"]["WorkspaceCalculationList"];
6969
+ };
6970
+ };
6971
+ 400: components["responses"]["BadRequest"];
6972
+ 401: components["responses"]["Unauthenticated"];
6973
+ 403: components["responses"]["ForbiddenKeyOrSession"];
6974
+ 413: components["responses"]["PayloadTooLarge"];
6975
+ 414: components["responses"]["UriTooLong"];
6976
+ 429: components["responses"]["RateLimited"];
6977
+ 500: components["responses"]["InternalError"];
6978
+ };
6979
+ };
5788
6980
  getCalculation: {
5789
6981
  parameters: {
5790
6982
  query?: never;
@@ -6628,8 +7820,15 @@ export interface operations {
6628
7820
  * {
6629
7821
  * "id": "8b9c0d1e-2f3a-4b4c-8d5e-6f708192a3b4",
6630
7822
  * "calculation_id": "7a8b9c0d-1e2f-4a3b-9c4d-5e6f708192a3",
7823
+ * "client_id": "6f1c2d3e-4b5a-4c6d-8e7f-90a1b2c3d4e5",
6631
7824
  * "client_name": "Acme Logistics",
6632
- * "workspace_name": "Northwind AI",
7825
+ * "period": {
7826
+ * "from": "2026-08-01T00:00:00Z",
7827
+ * "to": "2026-09-01T00:00:00Z"
7828
+ * },
7829
+ * "state": "draft",
7830
+ * "letterhead_client_name": "Acme Logistics",
7831
+ * "letterhead_workspace_name": "Northwind AI",
6633
7832
  * "note": "August was the first full month on the new routing rules.",
6634
7833
  * "share_token": null,
6635
7834
  * "shared_at": null,
@@ -6686,8 +7885,15 @@ export interface operations {
6686
7885
  * @example {
6687
7886
  * "id": "8b9c0d1e-2f3a-4b4c-8d5e-6f708192a3b4",
6688
7887
  * "calculation_id": "7a8b9c0d-1e2f-4a3b-9c4d-5e6f708192a3",
7888
+ * "client_id": "6f1c2d3e-4b5a-4c6d-8e7f-90a1b2c3d4e5",
6689
7889
  * "client_name": "Acme Logistics",
6690
- * "workspace_name": "Northwind AI",
7890
+ * "period": {
7891
+ * "from": "2026-08-01T00:00:00Z",
7892
+ * "to": "2026-09-01T00:00:00Z"
7893
+ * },
7894
+ * "state": "draft",
7895
+ * "letterhead_client_name": "Acme Logistics",
7896
+ * "letterhead_workspace_name": "Northwind AI",
6691
7897
  * "note": "August was the first full month on the new routing rules.",
6692
7898
  * "disclosures": [
6693
7899
  * {
@@ -6760,6 +7966,77 @@ export interface operations {
6760
7966
  500: components["responses"]["InternalError"];
6761
7967
  };
6762
7968
  };
7969
+ listReports: {
7970
+ parameters: {
7971
+ query?: {
7972
+ /** @description Only reports on this client's calculations. An id that names no client in the workspace matches no report, so the list is empty. An id in any spelling but the RFC 9562 string form is refused with `invalid_format`. */
7973
+ client_id?: components["schemas"]["UuidInput"];
7974
+ /** @description Only reports in this state. Any other value is refused with `invalid_value`. */
7975
+ state?: components["schemas"]["ReportState"];
7976
+ /** @description Page size, 1 to 200. A value outside the range is refused with `out_of_range`, never clamped. */
7977
+ limit?: components["parameters"]["Limit"];
7978
+ /** @description `next_cursor` from the previous page. Valid only with the filters and sort it was issued under; otherwise refused with `invalid_value`. An empty value is refused with `invalid_format`, like any empty query parameter. `limit` may change between pages. */
7979
+ cursor?: components["parameters"]["Cursor"];
7980
+ /** @description Page number, from 1. Reads the list in its documented order at offset `(page − 1) × limit`, and fills `total` with the count of every row matching the filters and search. Without `page` nothing is counted, and `page` and `total` are `null`. Not with `cursor`: both together are refused with `mutually_exclusive` on `cursor`. The offset must not exceed 10,000,000; a larger one is refused with `out_of_range` on `page`. A page past the last returns no rows and the true `total`. The response's `next_cursor` continues the list after the page's last row, so a cursor walk can start from any page. */
7981
+ page?: components["parameters"]["NumberedPage"];
7982
+ };
7983
+ header?: never;
7984
+ path?: never;
7985
+ cookie?: never;
7986
+ };
7987
+ requestBody?: never;
7988
+ responses: {
7989
+ /** @description OK. */
7990
+ 200: {
7991
+ headers: {
7992
+ "X-Request-Id": components["headers"]["X-Request-Id"];
7993
+ RateLimit: components["headers"]["RateLimit"];
7994
+ "RateLimit-Policy": components["headers"]["RateLimit-Policy"];
7995
+ [name: string]: unknown;
7996
+ };
7997
+ content: {
7998
+ /**
7999
+ * @example {
8000
+ * "page": null,
8001
+ * "total": null,
8002
+ * "data": [
8003
+ * {
8004
+ * "id": "8b9c0d1e-2f3a-4b4c-8d5e-6f708192a3b4",
8005
+ * "calculation_id": "7a8b9c0d-1e2f-4a3b-9c4d-5e6f708192a3",
8006
+ * "client_id": "6f1c2d3e-4b5a-4c6d-8e7f-90a1b2c3d4e5",
8007
+ * "client_name": "Acme Logistics",
8008
+ * "period": {
8009
+ * "from": "2026-08-01T00:00:00Z",
8010
+ * "to": "2026-09-01T00:00:00Z"
8011
+ * },
8012
+ * "state": "shared",
8013
+ * "letterhead_client_name": "Acme Logistics K.K.",
8014
+ * "letterhead_workspace_name": "Northwind AI",
8015
+ * "note": "August was the first full month on the new routing rules.",
8016
+ * "share_token": "q3Vb8Kx0dT1uYwZr5LmN2oPa7sCe4fGh9iJk6lMn0Qp",
8017
+ * "shared_at": "2026-09-03T01:00:00Z",
8018
+ * "revoked_at": null,
8019
+ * "first_viewed_at": "2026-09-03T05:20:00Z",
8020
+ * "last_viewed_at": "2026-09-04T09:10:00Z",
8021
+ * "created_at": "2026-09-02T01:00:00Z"
8022
+ * }
8023
+ * ],
8024
+ * "has_more": false,
8025
+ * "next_cursor": null
8026
+ * }
8027
+ */
8028
+ "application/json": components["schemas"]["WorkspaceReportList"];
8029
+ };
8030
+ };
8031
+ 400: components["responses"]["BadRequest"];
8032
+ 401: components["responses"]["Unauthenticated"];
8033
+ 403: components["responses"]["ForbiddenKeyOrSession"];
8034
+ 413: components["responses"]["PayloadTooLarge"];
8035
+ 414: components["responses"]["UriTooLong"];
8036
+ 429: components["responses"]["RateLimited"];
8037
+ 500: components["responses"]["InternalError"];
8038
+ };
8039
+ };
6763
8040
  getReport: {
6764
8041
  parameters: {
6765
8042
  query?: never;
@@ -6785,8 +8062,15 @@ export interface operations {
6785
8062
  * @example {
6786
8063
  * "id": "8b9c0d1e-2f3a-4b4c-8d5e-6f708192a3b4",
6787
8064
  * "calculation_id": "7a8b9c0d-1e2f-4a3b-9c4d-5e6f708192a3",
8065
+ * "client_id": "6f1c2d3e-4b5a-4c6d-8e7f-90a1b2c3d4e5",
6788
8066
  * "client_name": "Acme Logistics",
6789
- * "workspace_name": "Northwind AI",
8067
+ * "period": {
8068
+ * "from": "2026-08-01T00:00:00Z",
8069
+ * "to": "2026-09-01T00:00:00Z"
8070
+ * },
8071
+ * "state": "draft",
8072
+ * "letterhead_client_name": "Acme Logistics",
8073
+ * "letterhead_workspace_name": "Northwind AI",
6790
8074
  * "note": "August was the first full month on the new routing rules.",
6791
8075
  * "disclosures": [
6792
8076
  * {
@@ -7037,8 +8321,15 @@ export interface operations {
7037
8321
  * @example {
7038
8322
  * "id": "8b9c0d1e-2f3a-4b4c-8d5e-6f708192a3b4",
7039
8323
  * "calculation_id": "7a8b9c0d-1e2f-4a3b-9c4d-5e6f708192a3",
8324
+ * "client_id": "6f1c2d3e-4b5a-4c6d-8e7f-90a1b2c3d4e5",
7040
8325
  * "client_name": "Acme Logistics",
7041
- * "workspace_name": "Northwind AI",
8326
+ * "period": {
8327
+ * "from": "2026-08-01T00:00:00Z",
8328
+ * "to": "2026-09-01T00:00:00Z"
8329
+ * },
8330
+ * "state": "draft",
8331
+ * "letterhead_client_name": "Acme Logistics",
8332
+ * "letterhead_workspace_name": "Northwind AI",
7042
8333
  * "note": "August was the first full month on the new routing rules.",
7043
8334
  * "disclosures": [
7044
8335
  * {
@@ -7134,8 +8425,15 @@ export interface operations {
7134
8425
  * @example {
7135
8426
  * "id": "8b9c0d1e-2f3a-4b4c-8d5e-6f708192a3b4",
7136
8427
  * "calculation_id": "7a8b9c0d-1e2f-4a3b-9c4d-5e6f708192a3",
8428
+ * "client_id": "6f1c2d3e-4b5a-4c6d-8e7f-90a1b2c3d4e5",
7137
8429
  * "client_name": "Acme Logistics",
7138
- * "workspace_name": "Northwind AI",
8430
+ * "period": {
8431
+ * "from": "2026-08-01T00:00:00Z",
8432
+ * "to": "2026-09-01T00:00:00Z"
8433
+ * },
8434
+ * "state": "shared",
8435
+ * "letterhead_client_name": "Acme Logistics",
8436
+ * "letterhead_workspace_name": "Northwind AI",
7139
8437
  * "note": "August was the first full month on the new routing rules.",
7140
8438
  * "disclosures": [
7141
8439
  * {
@@ -7227,8 +8525,15 @@ export interface operations {
7227
8525
  * @example {
7228
8526
  * "id": "8b9c0d1e-2f3a-4b4c-8d5e-6f708192a3b4",
7229
8527
  * "calculation_id": "7a8b9c0d-1e2f-4a3b-9c4d-5e6f708192a3",
8528
+ * "client_id": "6f1c2d3e-4b5a-4c6d-8e7f-90a1b2c3d4e5",
7230
8529
  * "client_name": "Acme Logistics",
7231
- * "workspace_name": "Northwind AI",
8530
+ * "period": {
8531
+ * "from": "2026-08-01T00:00:00Z",
8532
+ * "to": "2026-09-01T00:00:00Z"
8533
+ * },
8534
+ * "state": "revoked",
8535
+ * "letterhead_client_name": "Acme Logistics",
8536
+ * "letterhead_workspace_name": "Northwind AI",
7232
8537
  * "note": "August was the first full month on the new routing rules.",
7233
8538
  * "disclosures": [
7234
8539
  * {
@@ -7345,7 +8650,7 @@ export interface operations {
7345
8650
  * "client_id": "6f1c2d3e-4b5a-4c6d-8e7f-90a1b2c3d4e5",
7346
8651
  * "name": "Acme Logistics",
7347
8652
  * "status": "active",
7348
- * "renewal_date": "2026-12-31",
8653
+ * "renewal_date": "2030-12-31",
7349
8654
  * "value_total": 408000,
7350
8655
  * "cost_total": 85100,
7351
8656
  * "roi": 3.7943595769682728,
@@ -7368,7 +8673,7 @@ export interface operations {
7368
8673
  * "client_id": "6f1c2d3e-4b5a-4c6d-8e7f-90a1b2c3d4e5",
7369
8674
  * "name": "Acme Logistics",
7370
8675
  * "status": "active",
7371
- * "renewal_date": "2026-12-31",
8676
+ * "renewal_date": "2030-12-31",
7372
8677
  * "value_total": 408000,
7373
8678
  * "cost_total": 85100,
7374
8679
  * "roi": 3.7943595769682728,
@@ -7434,10 +8739,21 @@ export interface operations {
7434
8739
  listRenewals: {
7435
8740
  parameters: {
7436
8741
  query?: {
8742
+ /**
8743
+ * @description The caller's current date, which every renewal date is rolled against and `window` is measured from. From the current UTC date less one day to the current UTC date plus one, so that any time zone's date is accepted; any other date is refused with `out_of_range`. Absent means the current UTC date. The response's `today` says which date applied, and a cursor is valid only under that date, so send it on later pages. A later page that leaves `today` out and is read after midnight UTC is refused with `invalid_value` on `cursor`.
8744
+ * @example 2026-11-10
8745
+ */
8746
+ today?: components["schemas"]["DateInput"];
8747
+ /** @description Only clients whose renewal date falls in this window. Absent lists every date. Any other value is refused with `invalid_value`. */
8748
+ window?: components["schemas"]["RenewalWindow"];
8749
+ /** @description Only clients with one of these terms, `none` naming a client with no term. Repeat the parameter for several terms, as in `renewal_term=annual&renewal_term=none`; their order does not matter. Absent lists every term. A value sent twice is refused with `duplicate`, and any other value with `invalid_value`. */
8750
+ renewal_term?: components["schemas"]["RenewalTermFilter"][];
7437
8751
  /** @description Page size, 1 to 200. A value outside the range is refused with `out_of_range`, never clamped. */
7438
8752
  limit?: components["parameters"]["Limit"];
7439
8753
  /** @description `next_cursor` from the previous page. Valid only with the filters and sort it was issued under; otherwise refused with `invalid_value`. An empty value is refused with `invalid_format`, like any empty query parameter. `limit` may change between pages. */
7440
8754
  cursor?: components["parameters"]["Cursor"];
8755
+ /** @description Page number, from 1. Reads the list in its documented order at offset `(page − 1) × limit`, and fills `total` with the count of every row matching the filters and search. Without `page` nothing is counted, and `page` and `total` are `null`. Not with `cursor`: both together are refused with `mutually_exclusive` on `cursor`. The offset must not exceed 10,000,000; a larger one is refused with `out_of_range` on `page`. A page past the last returns no rows and the true `total`. The response's `next_cursor` continues the list after the page's last row, so a cursor walk can start from any page. */
8756
+ page?: components["parameters"]["NumberedPage"];
7441
8757
  };
7442
8758
  header?: never;
7443
8759
  path?: never;
@@ -7456,16 +8772,21 @@ export interface operations {
7456
8772
  content: {
7457
8773
  /**
7458
8774
  * @example {
8775
+ * "page": 1,
8776
+ * "total": 1,
8777
+ * "today": "2026-11-10",
7459
8778
  * "data": [
7460
8779
  * {
7461
8780
  * "client_id": "6f1c2d3e-4b5a-4c6d-8e7f-90a1b2c3d4e5",
7462
8781
  * "name": "Acme Logistics",
7463
- * "renewal_date": "2026-12-31",
8782
+ * "renewal_date": "2030-12-31",
8783
+ * "renewal_term": "annual",
7464
8784
  * "roi": 3.7943595769682728,
7465
8785
  * "period": {
7466
8786
  * "from": "2026-08-01T00:00:00Z",
7467
8787
  * "to": "2026-09-01T00:00:00Z"
7468
8788
  * },
8789
+ * "calculation_id": "7a8b9c0d-1e2f-4a3b-9c4d-5e6f708192a3",
7469
8790
  * "health": {
7470
8791
  * "direction": "improving",
7471
8792
  * "delta_points": 41.9,
@@ -7721,4 +9042,456 @@ export interface operations {
7721
9042
  500: components["responses"]["InternalError"];
7722
9043
  };
7723
9044
  };
9045
+ getInvite: {
9046
+ parameters: {
9047
+ query?: never;
9048
+ header?: never;
9049
+ path?: never;
9050
+ cookie?: never;
9051
+ };
9052
+ requestBody?: never;
9053
+ responses: {
9054
+ /** @description OK. The invite is open, and its address has signed in. */
9055
+ 200: {
9056
+ headers: {
9057
+ "X-Request-Id": components["headers"]["X-Request-Id"];
9058
+ [name: string]: unknown;
9059
+ };
9060
+ content: {
9061
+ /**
9062
+ * @example {
9063
+ * "email": "owner@acme.example"
9064
+ * }
9065
+ */
9066
+ "application/json": components["schemas"]["OpenInvite"];
9067
+ };
9068
+ };
9069
+ 400: components["responses"]["BadRequest"];
9070
+ 401: components["responses"]["Unauthenticated"];
9071
+ /** @description `session_required`: any API key, whatever its scopes. */
9072
+ 403: {
9073
+ headers: {
9074
+ "X-Request-Id": components["headers"]["X-Request-Id"];
9075
+ [name: string]: unknown;
9076
+ };
9077
+ content: {
9078
+ /**
9079
+ * @example {
9080
+ * "type": "https://api.allisai.ai/errors/session_required",
9081
+ * "title": "This action requires a signed-in session",
9082
+ * "status": 403,
9083
+ * "detail": "This action requires a signed-in session; API keys cannot perform it.",
9084
+ * "code": "session_required",
9085
+ * "request_id": "3a9f6c1e2b7d4e5f8a0b1c2d3e4f5a6b"
9086
+ * }
9087
+ */
9088
+ "application/problem+json": components["schemas"]["Problem"] & {
9089
+ /** @enum {unknown} */
9090
+ code?: "session_required";
9091
+ };
9092
+ };
9093
+ };
9094
+ /** @description No open invite to the session's email address, or the session has no email address. */
9095
+ 404: {
9096
+ headers: {
9097
+ "X-Request-Id": components["headers"]["X-Request-Id"];
9098
+ [name: string]: unknown;
9099
+ };
9100
+ content: {
9101
+ /**
9102
+ * @example {
9103
+ * "type": "https://api.allisai.ai/errors/not_found",
9104
+ * "title": "The resource was not found",
9105
+ * "status": 404,
9106
+ * "detail": "no open invite for this account",
9107
+ * "code": "not_found",
9108
+ * "request_id": "3a9f6c1e2b7d4e5f8a0b1c2d3e4f5a6b"
9109
+ * }
9110
+ */
9111
+ "application/problem+json": components["schemas"]["Problem"] & {
9112
+ /** @enum {unknown} */
9113
+ code?: "not_found";
9114
+ };
9115
+ };
9116
+ };
9117
+ /** @description `invite_expired`: the invite's address did not sign in within the 24 hours after it was sent. `email_has_workspace`: the session's account or the invited address already belongs to a workspace. Checked in that order. */
9118
+ 409: {
9119
+ headers: {
9120
+ "X-Request-Id": components["headers"]["X-Request-Id"];
9121
+ [name: string]: unknown;
9122
+ };
9123
+ content: {
9124
+ /**
9125
+ * @example {
9126
+ * "type": "https://api.allisai.ai/errors/invite_expired",
9127
+ * "title": "The invite has expired",
9128
+ * "status": 409,
9129
+ * "detail": "This invite has expired. Reply to the invite email to ask for a new one.",
9130
+ * "code": "invite_expired",
9131
+ * "request_id": "3a9f6c1e2b7d4e5f8a0b1c2d3e4f5a6b"
9132
+ * }
9133
+ */
9134
+ "application/problem+json": components["schemas"]["Problem"] & {
9135
+ /** @enum {unknown} */
9136
+ code?: "invite_expired" | "email_has_workspace";
9137
+ };
9138
+ };
9139
+ };
9140
+ 413: components["responses"]["PayloadTooLarge"];
9141
+ 414: components["responses"]["UriTooLong"];
9142
+ 500: components["responses"]["InternalError"];
9143
+ };
9144
+ };
9145
+ redeemInvite: {
9146
+ parameters: {
9147
+ query?: never;
9148
+ header?: never;
9149
+ path?: never;
9150
+ cookie?: never;
9151
+ };
9152
+ requestBody?: never;
9153
+ responses: {
9154
+ /** @description OK. The invited address can now sign in. */
9155
+ 200: {
9156
+ headers: {
9157
+ "X-Request-Id": components["headers"]["X-Request-Id"];
9158
+ "Cache-Control": components["headers"]["Cache-Control"];
9159
+ [name: string]: unknown;
9160
+ };
9161
+ content: {
9162
+ /**
9163
+ * @example {
9164
+ * "email": "owner@acme.example",
9165
+ * "expires_at": "2026-11-03T09:14:00Z"
9166
+ * }
9167
+ */
9168
+ "application/json": components["schemas"]["InviteRedemption"];
9169
+ };
9170
+ };
9171
+ 400: components["responses"]["BadRequest"];
9172
+ /** @description The token is missing, malformed or unknown. */
9173
+ 404: {
9174
+ headers: {
9175
+ "X-Request-Id": components["headers"]["X-Request-Id"];
9176
+ "Cache-Control": components["headers"]["Cache-Control"];
9177
+ [name: string]: unknown;
9178
+ };
9179
+ content: {
9180
+ /**
9181
+ * @example {
9182
+ * "type": "https://api.allisai.ai/errors/not_found",
9183
+ * "title": "The resource was not found",
9184
+ * "status": 404,
9185
+ * "detail": "invite not found",
9186
+ * "code": "not_found",
9187
+ * "request_id": "3a9f6c1e2b7d4e5f8a0b1c2d3e4f5a6b"
9188
+ * }
9189
+ */
9190
+ "application/problem+json": components["schemas"]["Problem"] & {
9191
+ /** @enum {unknown} */
9192
+ code?: "not_found";
9193
+ };
9194
+ };
9195
+ };
9196
+ /** @description `invite_revoked`, `invite_used` or `invite_expired`: the invite is not open, checked in that order. `email_has_workspace`: the invited address already belongs to a workspace. */
9197
+ 409: {
9198
+ headers: {
9199
+ "X-Request-Id": components["headers"]["X-Request-Id"];
9200
+ "Cache-Control": components["headers"]["Cache-Control"];
9201
+ [name: string]: unknown;
9202
+ };
9203
+ content: {
9204
+ /**
9205
+ * @example {
9206
+ * "type": "https://api.allisai.ai/errors/invite_expired",
9207
+ * "title": "The invite has expired",
9208
+ * "status": 409,
9209
+ * "detail": "This invite has expired. Reply to the invite email to ask for a new one.",
9210
+ * "code": "invite_expired",
9211
+ * "request_id": "3a9f6c1e2b7d4e5f8a0b1c2d3e4f5a6b"
9212
+ * }
9213
+ */
9214
+ "application/problem+json": components["schemas"]["Problem"] & {
9215
+ /** @enum {unknown} */
9216
+ code?: "invite_revoked" | "invite_used" | "invite_expired" | "email_has_workspace";
9217
+ };
9218
+ };
9219
+ };
9220
+ 413: components["responses"]["PayloadTooLarge"];
9221
+ 414: components["responses"]["UriTooLong"];
9222
+ 500: components["responses"]["InternalError"];
9223
+ 502: components["responses"]["UpstreamFailed"];
9224
+ };
9225
+ };
9226
+ getWorkspace: {
9227
+ parameters: {
9228
+ query?: never;
9229
+ header?: never;
9230
+ path?: never;
9231
+ cookie?: never;
9232
+ };
9233
+ requestBody?: never;
9234
+ responses: {
9235
+ /** @description OK. */
9236
+ 200: {
9237
+ headers: {
9238
+ "X-Request-Id": components["headers"]["X-Request-Id"];
9239
+ RateLimit: components["headers"]["RateLimit"];
9240
+ "RateLimit-Policy": components["headers"]["RateLimit-Policy"];
9241
+ [name: string]: unknown;
9242
+ };
9243
+ content: {
9244
+ /**
9245
+ * @example {
9246
+ * "id": "0f8e2c1a-5b3d-4e6f-8a7b-9c0d1e2f3a4b",
9247
+ * "name": "Acme AI",
9248
+ * "currency": "JPY",
9249
+ * "minor_units": 0,
9250
+ * "created_at": "2026-11-02T10:01:12Z"
9251
+ * }
9252
+ */
9253
+ "application/json": components["schemas"]["Workspace"];
9254
+ };
9255
+ };
9256
+ 400: components["responses"]["BadRequest"];
9257
+ 401: components["responses"]["Unauthenticated"];
9258
+ 403: components["responses"]["ForbiddenKeyOrSession"];
9259
+ 413: components["responses"]["PayloadTooLarge"];
9260
+ 414: components["responses"]["UriTooLong"];
9261
+ 429: components["responses"]["RateLimited"];
9262
+ 500: components["responses"]["InternalError"];
9263
+ };
9264
+ };
9265
+ createWorkspace: {
9266
+ parameters: {
9267
+ query?: never;
9268
+ header?: never;
9269
+ path?: never;
9270
+ cookie?: never;
9271
+ };
9272
+ requestBody: {
9273
+ content: {
9274
+ /**
9275
+ * @example {
9276
+ * "invite_token": "<token from the invite link>",
9277
+ * "name": "Acme AI",
9278
+ * "currency": "JPY"
9279
+ * }
9280
+ */
9281
+ "application/json": components["schemas"]["WorkspaceCreate"];
9282
+ };
9283
+ };
9284
+ responses: {
9285
+ /** @description Created. */
9286
+ 201: {
9287
+ headers: {
9288
+ "X-Request-Id": components["headers"]["X-Request-Id"];
9289
+ Location: components["headers"]["Location"];
9290
+ [name: string]: unknown;
9291
+ };
9292
+ content: {
9293
+ /**
9294
+ * @example {
9295
+ * "id": "0f8e2c1a-5b3d-4e6f-8a7b-9c0d1e2f3a4b",
9296
+ * "name": "Acme AI",
9297
+ * "currency": "JPY",
9298
+ * "minor_units": 0,
9299
+ * "created_at": "2026-11-02T10:01:12Z"
9300
+ * }
9301
+ */
9302
+ "application/json": components["schemas"]["Workspace"];
9303
+ };
9304
+ };
9305
+ 400: components["responses"]["BadRequest"];
9306
+ 401: components["responses"]["Unauthenticated"];
9307
+ /** @description `session_required`: any API key, whatever its scopes. `invite_email_mismatch`: the session's email address is not the one the invite was sent to. It is checked before the invite's state. `account_not_provisioned`: a request without `invite_token` from a session with no open invite to its address and no workspace. */
9308
+ 403: {
9309
+ headers: {
9310
+ "X-Request-Id": components["headers"]["X-Request-Id"];
9311
+ [name: string]: unknown;
9312
+ };
9313
+ content: {
9314
+ /**
9315
+ * @example {
9316
+ * "type": "https://api.allisai.ai/errors/invite_email_mismatch",
9317
+ * "title": "The invite was sent to another email address",
9318
+ * "status": 403,
9319
+ * "detail": "This invite was sent to another email address. Sign in with the address the invite was sent to.",
9320
+ * "code": "invite_email_mismatch",
9321
+ * "request_id": "3a9f6c1e2b7d4e5f8a0b1c2d3e4f5a6b"
9322
+ * }
9323
+ */
9324
+ "application/problem+json": components["schemas"]["Problem"] & {
9325
+ /** @enum {unknown} */
9326
+ code?: "session_required" | "invite_email_mismatch" | "account_not_provisioned";
9327
+ };
9328
+ };
9329
+ };
9330
+ /** @description `invite_revoked`, `invite_used` or `invite_expired`: the invite is not open, checked in that order. `email_has_workspace`: the session's account or the invited address already belongs to a workspace. */
9331
+ 409: {
9332
+ headers: {
9333
+ "X-Request-Id": components["headers"]["X-Request-Id"];
9334
+ [name: string]: unknown;
9335
+ };
9336
+ content: {
9337
+ /**
9338
+ * @example {
9339
+ * "type": "https://api.allisai.ai/errors/invite_used",
9340
+ * "title": "The invite has been used",
9341
+ * "status": 409,
9342
+ * "detail": "This invite has already been used to create a workspace. Sign in instead.",
9343
+ * "code": "invite_used",
9344
+ * "request_id": "3a9f6c1e2b7d4e5f8a0b1c2d3e4f5a6b"
9345
+ * }
9346
+ */
9347
+ "application/problem+json": components["schemas"]["Problem"] & {
9348
+ /** @enum {unknown} */
9349
+ code?: "invite_revoked" | "invite_used" | "invite_expired" | "email_has_workspace";
9350
+ };
9351
+ };
9352
+ };
9353
+ 413: components["responses"]["PayloadTooLarge"];
9354
+ 414: components["responses"]["UriTooLong"];
9355
+ 415: components["responses"]["UnsupportedMediaType"];
9356
+ 500: components["responses"]["InternalError"];
9357
+ };
9358
+ };
9359
+ getOnboarding: {
9360
+ parameters: {
9361
+ query?: never;
9362
+ header?: never;
9363
+ path?: never;
9364
+ cookie?: never;
9365
+ };
9366
+ requestBody?: never;
9367
+ responses: {
9368
+ /** @description OK. */
9369
+ 200: {
9370
+ headers: {
9371
+ "X-Request-Id": components["headers"]["X-Request-Id"];
9372
+ RateLimit: components["headers"]["RateLimit"];
9373
+ "RateLimit-Policy": components["headers"]["RateLimit-Policy"];
9374
+ [name: string]: unknown;
9375
+ };
9376
+ content: {
9377
+ /**
9378
+ * @example {
9379
+ * "steps": [
9380
+ * {
9381
+ * "step": "add_client",
9382
+ * "completed": true,
9383
+ * "skipped_at": null
9384
+ * },
9385
+ * {
9386
+ * "step": "add_agent",
9387
+ * "completed": false,
9388
+ * "skipped_at": "2026-11-02T10:05:00Z"
9389
+ * },
9390
+ * {
9391
+ * "step": "price_outcomes",
9392
+ * "completed": false,
9393
+ * "skipped_at": null
9394
+ * },
9395
+ * {
9396
+ * "step": "bring_in_data",
9397
+ * "completed": false,
9398
+ * "skipped_at": null
9399
+ * },
9400
+ * {
9401
+ * "step": "create_draft_calculation",
9402
+ * "completed": false,
9403
+ * "skipped_at": null
9404
+ * }
9405
+ * ],
9406
+ * "current_step": "price_outcomes",
9407
+ * "has_published": false
9408
+ * }
9409
+ */
9410
+ "application/json": components["schemas"]["Onboarding"];
9411
+ };
9412
+ };
9413
+ 400: components["responses"]["BadRequest"];
9414
+ 401: components["responses"]["Unauthenticated"];
9415
+ 403: components["responses"]["ForbiddenKeyOrSession"];
9416
+ 413: components["responses"]["PayloadTooLarge"];
9417
+ 414: components["responses"]["UriTooLong"];
9418
+ 429: components["responses"]["RateLimited"];
9419
+ 500: components["responses"]["InternalError"];
9420
+ };
9421
+ };
9422
+ setOnboardingSkippedSteps: {
9423
+ parameters: {
9424
+ query?: never;
9425
+ header?: never;
9426
+ path?: never;
9427
+ cookie?: never;
9428
+ };
9429
+ requestBody: {
9430
+ content: {
9431
+ /**
9432
+ * @example {
9433
+ * "steps": [
9434
+ * "add_agent"
9435
+ * ]
9436
+ * }
9437
+ */
9438
+ "application/json": components["schemas"]["OnboardingSkippedStepsSet"];
9439
+ };
9440
+ };
9441
+ responses: {
9442
+ /** @description OK. */
9443
+ 200: {
9444
+ headers: {
9445
+ "X-Request-Id": components["headers"]["X-Request-Id"];
9446
+ RateLimit: components["headers"]["RateLimit"];
9447
+ "RateLimit-Policy": components["headers"]["RateLimit-Policy"];
9448
+ [name: string]: unknown;
9449
+ };
9450
+ content: {
9451
+ /**
9452
+ * @example {
9453
+ * "steps": [
9454
+ * {
9455
+ * "step": "add_client",
9456
+ * "completed": true,
9457
+ * "skipped_at": null
9458
+ * },
9459
+ * {
9460
+ * "step": "add_agent",
9461
+ * "completed": false,
9462
+ * "skipped_at": "2026-11-02T10:05:00Z"
9463
+ * },
9464
+ * {
9465
+ * "step": "price_outcomes",
9466
+ * "completed": false,
9467
+ * "skipped_at": null
9468
+ * },
9469
+ * {
9470
+ * "step": "bring_in_data",
9471
+ * "completed": false,
9472
+ * "skipped_at": null
9473
+ * },
9474
+ * {
9475
+ * "step": "create_draft_calculation",
9476
+ * "completed": false,
9477
+ * "skipped_at": null
9478
+ * }
9479
+ * ],
9480
+ * "current_step": "price_outcomes",
9481
+ * "has_published": false
9482
+ * }
9483
+ */
9484
+ "application/json": components["schemas"]["Onboarding"];
9485
+ };
9486
+ };
9487
+ 400: components["responses"]["BadRequest"];
9488
+ 401: components["responses"]["Unauthenticated"];
9489
+ 403: components["responses"]["ForbiddenKeyOrSession"];
9490
+ 413: components["responses"]["PayloadTooLarge"];
9491
+ 414: components["responses"]["UriTooLong"];
9492
+ 415: components["responses"]["UnsupportedMediaType"];
9493
+ 429: components["responses"]["RateLimited"];
9494
+ 500: components["responses"]["InternalError"];
9495
+ };
9496
+ };
7724
9497
  }