uarp_sdk/generated/api/admin_config.rs
1// Code generated by @uarp/codegen from spec/openapi.json. DO NOT EDIT.
2//!
3//! Platform configuration: pricing, plans, feature flags, rate limits, runtime
4
5#![allow(unused_imports, clippy::too_many_arguments)]
6
7use reqwest::Method;
8use serde::{Deserialize, Serialize};
9
10use crate::client::{Client, Request, NO_BODY, NO_QUERY};
11use crate::error::Result;
12use crate::generated::models;
13use crate::multipart::{field_text, FilePart};
14use crate::util::encode_path;
15
16/// Query and header parameters for `deleteCustomPlan`.
17#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
18pub struct DeleteCustomPlanParams {
19 /// Exactly `1`. Deletes despite assigned tenants.
20 #[serde(default, skip_serializing_if = "Option::is_none")]
21 pub force: Option<models::DeleteCustomPlanForce>,
22}
23
24/// Query and header parameters for `updateAdminSpecPackages`.
25#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
26pub struct UpdateAdminSpecPackagesParams {
27 /// Comma-separated package ids the caller intends to delete despite a wired Stripe price. Ids
28 /// not listed still refuse.
29 #[serde(default, skip_serializing_if = "Option::is_none")]
30 pub confirm_drop: Option<String>,
31}
32
33/// Platform configuration: pricing, plans, feature flags, rate limits, runtime
34#[derive(Debug, Clone)]
35pub struct AdminConfigApi {
36 pub(crate) client: Client,
37}
38
39impl Client {
40 /// Platform configuration: pricing, plans, feature flags, rate limits, runtime
41 pub fn admin_config(&self) -> AdminConfigApi {
42 AdminConfigApi { client: self.clone() }
43 }
44}
45
46impl AdminConfigApi {
47 /// Create the Stripe product and price for a package
48 ///
49 /// Creates the product and price in Stripe and persists the resulting price id onto the
50 /// package. Until this has run, the package cannot be bought: `POST
51 /// /api/v1/billing/spec-packages/{packageId}/checkout-session` answers 400 and says so.
52 ///
53 /// `POST /api/v1/admin/config/spec-packages/{packageId}/stripe-price`
54 ///
55 /// Required scopes: `admin`.
56 pub async fn create_admin_spec_package_stripe_price(&self, package_id: &str) -> Result<serde_json::Map<String, serde_json::Value>> {
57 self.client
58 .request_json(Request {
59 method: Method::POST,
60 path: format!("/api/v1/admin/config/spec-packages/{}/stripe-price", encode_path(package_id)),
61 query: NO_QUERY,
62 body: NO_BODY,
63 headers: Vec::new(),
64 idempotent: true,
65 })
66 .await
67 }
68
69 /// Create Stripe Product+Price for plan
70 ///
71 /// `POST /api/v1/admin/config/plans/{planId}/stripe-price`
72 ///
73 /// Required scopes: `admin`.
74 pub async fn create_plan_stripe_price(&self, plan_id: &models::PlanLLMLimitsTierAccessItem, body: &models::CreatePlanStripePriceRequest) -> Result<models::CreatePlanStripePriceResponse> {
75 self.client
76 .request_json(Request {
77 method: Method::POST,
78 path: format!("/api/v1/admin/config/plans/{}/stripe-price", encode_path(&plan_id.to_string())),
79 query: NO_QUERY,
80 body: Some(body),
81 headers: Vec::new(),
82 idempotent: true,
83 })
84 .await
85 }
86
87 /// Remove a custom plan
88 ///
89 /// **Refuses while tenants are assigned to the plan.** The answer is 409 naming how many, and
90 /// the caller opts in with `?force=1` — an exact string match, so `?force=true` does NOT force.
91 /// Deleting a plan out from under its tenants leaves them on an id that no longer resolves,
92 /// which is why the guard is there.
93 ///
94 /// The count in the message is a floor, not a census: it is what the tenant scan saw at that
95 /// moment.
96 ///
97 /// `DELETE /api/v1/admin/config/custom-plans/{planId}`
98 ///
99 /// Required scopes: `admin`.
100 pub async fn delete_custom_plan(&self, plan_id: &str, params: &DeleteCustomPlanParams) -> Result<models::DeleteCustomPlanResponse> {
101 self.client
102 .request_json(Request {
103 method: Method::DELETE,
104 path: format!("/api/v1/admin/config/custom-plans/{}", encode_path(plan_id)),
105 query: Some(params),
106 body: NO_BODY,
107 headers: Vec::new(),
108 idempotent: true,
109 })
110 .await
111 }
112
113 /// Drop the price override for one model
114 ///
115 /// Removes the override so the model bills at its catalogue rate again. The 404 is keyed on the
116 /// OVERRIDE map, not the model catalogue: deleting an override that was never set is 404 even
117 /// for a model that exists.
118 ///
119 /// `DELETE /api/v1/admin/config/model-pricing/{modelRef}`
120 ///
121 /// Required scopes: `admin`.
122 pub async fn delete_model_pricing_override(&self, model_ref: &str) -> Result<models::DeleteModelPricingOverrideResponse> {
123 self.client
124 .request_json(Request {
125 method: Method::DELETE,
126 path: format!("/api/v1/admin/config/model-pricing/{}", encode_path(model_ref)),
127 query: NO_QUERY,
128 body: NO_BODY,
129 headers: Vec::new(),
130 idempotent: true,
131 })
132 .await
133 }
134
135 /// Remove a promo code
136 ///
137 /// Removes the code only. Redemption and reward records already written against it are NOT
138 /// cascaded — they remain, keyed by the code string, so a code deleted and later re-created
139 /// inherits the history of its name.
140 ///
141 /// `DELETE /api/v1/admin/config/promo-codes/{code}`
142 ///
143 /// Required scopes: `admin`.
144 pub async fn delete_promo_code(&self, code: &str) -> Result<models::DeletePromoCodeResponse> {
145 self.client
146 .request_json(Request {
147 method: Method::DELETE,
148 path: format!("/api/v1/admin/config/promo-codes/{}", encode_path(code)),
149 query: NO_QUERY,
150 body: NO_BODY,
151 headers: Vec::new(),
152 idempotent: true,
153 })
154 .await
155 }
156
157 /// Bulk download of every admin-config KV override
158 ///
159 /// `GET /api/v1/admin/config/export`
160 ///
161 /// Required scopes: `admin`.
162 pub async fn export(&self) -> Result<models::ExportAdminConfigResponse> {
163 self.client
164 .request_json(Request {
165 method: Method::GET,
166 path: "/api/v1/admin/config/export".to_string(),
167 query: NO_QUERY,
168 body: NO_BODY,
169 headers: Vec::new(),
170 idempotent: false,
171 })
172 .await
173 }
174
175 /// Get agent memory overrides (decay, models, embedding dims)
176 ///
177 /// `GET /api/v1/admin/config/agent-memory`
178 ///
179 /// Required scopes: `admin`.
180 pub async fn get_admin_agent_memory_config(&self) -> Result<serde_json::Map<String, serde_json::Value>> {
181 self.client
182 .request_json(Request {
183 method: Method::GET,
184 path: "/api/v1/admin/config/agent-memory".to_string(),
185 query: NO_QUERY,
186 body: NO_BODY,
187 headers: Vec::new(),
188 idempotent: false,
189 })
190 .await
191 }
192
193 /// Get auth runtime overrides (super-admin email, OTP/JWKS TTLs)
194 ///
195 /// `GET /api/v1/admin/config/auth`
196 ///
197 /// Required scopes: `admin`.
198 pub async fn get_admin_auth_config(&self) -> Result<serde_json::Map<String, serde_json::Value>> {
199 self.client
200 .request_json(Request {
201 method: Method::GET,
202 path: "/api/v1/admin/config/auth".to_string(),
203 query: NO_QUERY,
204 body: NO_BODY,
205 headers: Vec::new(),
206 idempotent: false,
207 })
208 .await
209 }
210
211 /// Get backpressure overrides (SSE buffers + tool queue watermarks)
212 ///
213 /// `GET /api/v1/admin/config/backpressure`
214 ///
215 /// Required scopes: `admin`.
216 pub async fn get_admin_backpressure_config(&self) -> Result<serde_json::Map<String, serde_json::Value>> {
217 self.client
218 .request_json(Request {
219 method: Method::GET,
220 path: "/api/v1/admin/config/backpressure".to_string(),
221 query: NO_QUERY,
222 body: NO_BODY,
223 headers: Vec::new(),
224 idempotent: false,
225 })
226 .await
227 }
228
229 /// Get code-interpreter overrides (isolation, timeout, memory)
230 ///
231 /// `GET /api/v1/admin/config/code-interpreter`
232 ///
233 /// Required scopes: `admin`.
234 pub async fn get_admin_code_interpreter_config(&self) -> Result<serde_json::Map<String, serde_json::Value>> {
235 self.client
236 .request_json(Request {
237 method: Method::GET,
238 path: "/api/v1/admin/config/code-interpreter".to_string(),
239 query: NO_QUERY,
240 body: NO_BODY,
241 headers: Vec::new(),
242 idempotent: false,
243 })
244 .await
245 }
246
247 /// Tool ids disabled platform-wide
248 ///
249 /// `GET /api/v1/admin/config/disabled-tools`
250 ///
251 /// Required scopes: `admin`.
252 pub async fn get_admin_disabled_tools(&self) -> Result<models::GetAdminDisabledToolsResponse> {
253 self.client
254 .request_json(Request {
255 method: Method::GET,
256 path: "/api/v1/admin/config/disabled-tools".to_string(),
257 query: NO_QUERY,
258 body: NO_BODY,
259 headers: Vec::new(),
260 idempotent: false,
261 })
262 .await
263 }
264
265 /// Get evaluation overrides (timeouts, regression threshold, auto-rollback)
266 ///
267 /// `GET /api/v1/admin/config/evaluation`
268 ///
269 /// Required scopes: `admin`.
270 pub async fn get_admin_evaluation_config(&self) -> Result<serde_json::Map<String, serde_json::Value>> {
271 self.client
272 .request_json(Request {
273 method: Method::GET,
274 path: "/api/v1/admin/config/evaluation".to_string(),
275 query: NO_QUERY,
276 body: NO_BODY,
277 headers: Vec::new(),
278 idempotent: false,
279 })
280 .await
281 }
282
283 /// Founder identity, stored and from the environment
284 ///
285 /// Same three-layer read as SMTP, except the third key is `effective` rather than `source`: the
286 /// resolved values themselves, not a label saying where they came from. Resolution is per
287 /// FIELD, so a founder id from storage can sit beside a public key from the environment.
288 ///
289 /// `GET /api/v1/admin/config/founder`
290 ///
291 /// Required scopes: `admin`.
292 pub async fn get_admin_founder_config(&self) -> Result<models::GetAdminFounderConfigResponse> {
293 self.client
294 .request_json(Request {
295 method: Method::GET,
296 path: "/api/v1/admin/config/founder".to_string(),
297 query: NO_QUERY,
298 body: NO_BODY,
299 headers: Vec::new(),
300 idempotent: false,
301 })
302 .await
303 }
304
305 /// Get guardrail config
306 ///
307 /// `GET /api/v1/admin/config/guardrails`
308 ///
309 /// Required scopes: `admin`.
310 pub async fn get_admin_guardrails(&self) -> Result<models::GetAdminGuardrailsResponse> {
311 self.client
312 .request_json(Request {
313 method: Method::GET,
314 path: "/api/v1/admin/config/guardrails".to_string(),
315 query: NO_QUERY,
316 body: NO_BODY,
317 headers: Vec::new(),
318 idempotent: false,
319 })
320 .await
321 }
322
323 /// Get idempotency overrides (enabled, TTL hours, max cache bytes)
324 ///
325 /// `GET /api/v1/admin/config/idempotency`
326 ///
327 /// Required scopes: `admin`.
328 pub async fn get_admin_idempotency_config(&self) -> Result<serde_json::Map<String, serde_json::Value>> {
329 self.client
330 .request_json(Request {
331 method: Method::GET,
332 path: "/api/v1/admin/config/idempotency".to_string(),
333 query: NO_QUERY,
334 body: NO_BODY,
335 headers: Vec::new(),
336 idempotent: false,
337 })
338 .await
339 }
340
341 /// Get integration toggles
342 ///
343 /// `GET /api/v1/admin/config/integrations`
344 ///
345 /// Required scopes: `admin`.
346 pub async fn get_admin_integrations(&self) -> Result<models::GetAdminIntegrationsResponse> {
347 self.client
348 .request_json(Request {
349 method: Method::GET,
350 path: "/api/v1/admin/config/integrations".to_string(),
351 query: NO_QUERY,
352 body: NO_BODY,
353 headers: Vec::new(),
354 idempotent: false,
355 })
356 .await
357 }
358
359 /// Get LLM adapter overrides (retries, circuit breaker, per-provider RPM)
360 ///
361 /// `GET /api/v1/admin/config/llm-adapters`
362 ///
363 /// Required scopes: `admin`.
364 pub async fn get_admin_llm_adapters_config(&self) -> Result<serde_json::Map<String, serde_json::Value>> {
365 self.client
366 .request_json(Request {
367 method: Method::GET,
368 path: "/api/v1/admin/config/llm-adapters".to_string(),
369 query: NO_QUERY,
370 body: NO_BODY,
371 headers: Vec::new(),
372 idempotent: false,
373 })
374 .await
375 }
376
377 /// Get logging overrides (PII mode, file level, activity verbosity)
378 ///
379 /// `GET /api/v1/admin/config/logging`
380 ///
381 /// Required scopes: `admin`.
382 pub async fn get_admin_logging_config(&self) -> Result<serde_json::Map<String, serde_json::Value>> {
383 self.client
384 .request_json(Request {
385 method: Method::GET,
386 path: "/api/v1/admin/config/logging".to_string(),
387 query: NO_QUERY,
388 body: NO_BODY,
389 headers: Vec::new(),
390 idempotent: false,
391 })
392 .await
393 }
394
395 /// Get long-running run overrides
396 ///
397 /// `GET /api/v1/admin/config/long-running`
398 ///
399 /// Required scopes: `admin`.
400 pub async fn get_admin_long_running_config(&self) -> Result<serde_json::Map<String, serde_json::Value>> {
401 self.client
402 .request_json(Request {
403 method: Method::GET,
404 path: "/api/v1/admin/config/long-running".to_string(),
405 query: NO_QUERY,
406 body: NO_BODY,
407 headers: Vec::new(),
408 idempotent: false,
409 })
410 .await
411 }
412
413 /// Get MCP overrides (session limits, idle timeout)
414 ///
415 /// `GET /api/v1/admin/config/mcp`
416 ///
417 /// Required scopes: `admin`.
418 pub async fn get_admin_mcp_config(&self) -> Result<serde_json::Map<String, serde_json::Value>> {
419 self.client
420 .request_json(Request {
421 method: Method::GET,
422 path: "/api/v1/admin/config/mcp".to_string(),
423 query: NO_QUERY,
424 body: NO_BODY,
425 headers: Vec::new(),
426 idempotent: false,
427 })
428 .await
429 }
430
431 /// Get multimodal overrides (size + duration caps + format allowlists)
432 ///
433 /// `GET /api/v1/admin/config/multimodal`
434 ///
435 /// Required scopes: `admin`.
436 pub async fn get_admin_multimodal_config(&self) -> Result<serde_json::Map<String, serde_json::Value>> {
437 self.client
438 .request_json(Request {
439 method: Method::GET,
440 path: "/api/v1/admin/config/multimodal".to_string(),
441 query: NO_QUERY,
442 body: NO_BODY,
443 headers: Vec::new(),
444 idempotent: false,
445 })
446 .await
447 }
448
449 /// Apple native sign-in identifiers and the OAuth return-to allowlist
450 ///
451 /// Three-layer read with `effective`, as with founder identity. The environment's
452 /// `oauth_return_to_hosts` is a comma-separated variable, split, trimmed and lower-cased before
453 /// it appears here.
454 ///
455 /// `GET /api/v1/admin/config/oauth-identity`
456 ///
457 /// Required scopes: `admin`.
458 pub async fn get_admin_o_auth_identity_config(&self) -> Result<models::GetAdminOAuthIdentityConfigResponse> {
459 self.client
460 .request_json(Request {
461 method: Method::GET,
462 path: "/api/v1/admin/config/oauth-identity".to_string(),
463 query: NO_QUERY,
464 body: NO_BODY,
465 headers: Vec::new(),
466 idempotent: false,
467 })
468 .await
469 }
470
471 /// Get persistence overrides (snapshot interval, KV auto-cap)
472 ///
473 /// `GET /api/v1/admin/config/persistence`
474 ///
475 /// Required scopes: `admin`.
476 pub async fn get_admin_persistence_config(&self) -> Result<serde_json::Map<String, serde_json::Value>> {
477 self.client
478 .request_json(Request {
479 method: Method::GET,
480 path: "/api/v1/admin/config/persistence".to_string(),
481 query: NO_QUERY,
482 body: NO_BODY,
483 headers: Vec::new(),
484 idempotent: false,
485 })
486 .await
487 }
488
489 /// Get plan overrides
490 ///
491 /// `GET /api/v1/admin/config/plans`
492 ///
493 /// Required scopes: `admin`.
494 pub async fn get_admin_plans(&self) -> Result<models::GetAdminPlansResponse> {
495 self.client
496 .request_json(Request {
497 method: Method::GET,
498 path: "/api/v1/admin/config/plans".to_string(),
499 query: NO_QUERY,
500 body: NO_BODY,
501 headers: Vec::new(),
502 idempotent: false,
503 })
504 .await
505 }
506
507 /// Registration state, setup progress, and the waitlist
508 ///
509 /// Answers three things at once because the admin screen needs all three to decide whether the
510 /// doors CAN open: the effective registration config, how far platform setup has got, and who
511 /// signed up while it was shut.
512 ///
513 /// The waitlist is real registered tenants in status `waitlisted`, not leads — they activate
514 /// lazily on their first login after the doors open.
515 ///
516 /// `GET /api/v1/admin/config/registration`
517 ///
518 /// Required scopes: `admin`.
519 pub async fn get_admin_registration_config(&self) -> Result<models::GetAdminRegistrationConfigResponse> {
520 self.client
521 .request_json(Request {
522 method: Method::GET,
523 path: "/api/v1/admin/config/registration".to_string(),
524 query: NO_QUERY,
525 body: NO_BODY,
526 headers: Vec::new(),
527 idempotent: false,
528 })
529 .await
530 }
531
532 /// Get retention overrides (run / event / audit / feed / artifact TTLs)
533 ///
534 /// `GET /api/v1/admin/config/retention`
535 ///
536 /// Required scopes: `admin`.
537 pub async fn get_admin_retention_config(&self) -> Result<serde_json::Map<String, serde_json::Value>> {
538 self.client
539 .request_json(Request {
540 method: Method::GET,
541 path: "/api/v1/admin/config/retention".to_string(),
542 query: NO_QUERY,
543 body: NO_BODY,
544 headers: Vec::new(),
545 idempotent: false,
546 })
547 .await
548 }
549
550 /// Get run_command overrides (enabled, allowed commands, deno_allow)
551 ///
552 /// `GET /api/v1/admin/config/run-command`
553 ///
554 /// Required scopes: `admin`.
555 pub async fn get_admin_run_command_config(&self) -> Result<serde_json::Map<String, serde_json::Value>> {
556 self.client
557 .request_json(Request {
558 method: Method::GET,
559 path: "/api/v1/admin/config/run-command".to_string(),
560 query: NO_QUERY,
561 body: NO_BODY,
562 headers: Vec::new(),
563 idempotent: false,
564 })
565 .await
566 }
567
568 /// Get HTTP server overrides (trust_proxy, body cap, shutdown timeout)
569 ///
570 /// `GET /api/v1/admin/config/server`
571 ///
572 /// Required scopes: `admin`.
573 pub async fn get_admin_server_config(&self) -> Result<serde_json::Map<String, serde_json::Value>> {
574 self.client
575 .request_json(Request {
576 method: Method::GET,
577 path: "/api/v1/admin/config/server".to_string(),
578 query: NO_QUERY,
579 body: NO_BODY,
580 headers: Vec::new(),
581 idempotent: false,
582 })
583 .await
584 }
585
586 /// Platform setup progress
587 ///
588 /// Answers the state plus the two vocabularies needed to read it — which steps exist and which
589 /// are required — so a client does not hard-code either and drift when the list changes.
590 ///
591 /// `GET /api/v1/admin/config/setup-state`
592 ///
593 /// Required scopes: `admin`.
594 pub async fn get_admin_setup_state(&self) -> Result<models::SetupStateResponse> {
595 self.client
596 .request_json(Request {
597 method: Method::GET,
598 path: "/api/v1/admin/config/setup-state".to_string(),
599 query: NO_QUERY,
600 body: NO_BODY,
601 headers: Vec::new(),
602 idempotent: false,
603 })
604 .await
605 }
606
607 /// Get SMTP config, stored and from the environment
608 ///
609 /// Three-layer read, the shape this whole config family uses: `kv` is what an operator saved,
610 /// `env` is what the process environment supplies, and `source` says which of them is actually
611 /// in force. The password is never in either — only `has_password`, so a UI can show that a
612 /// credential exists without ever holding it.
613 ///
614 /// `GET /api/v1/admin/config/smtp`
615 ///
616 /// Required scopes: `admin`.
617 pub async fn get_admin_smtp_config(&self) -> Result<models::GetAdminSmtpConfigResponse> {
618 self.client
619 .request_json(Request {
620 method: Method::GET,
621 path: "/api/v1/admin/config/smtp".to_string(),
622 query: NO_QUERY,
623 body: NO_BODY,
624 headers: Vec::new(),
625 idempotent: false,
626 })
627 .await
628 }
629
630 /// Every SPEC package, archived ones included
631 ///
632 /// The operator's view: unlike the tenant-facing `/api/v1/billing/spec-packages`, archived
633 /// packages are present and the Stripe price id is NOT redacted. Sorted by `display_order`,
634 /// then by name.
635 ///
636 /// `GET /api/v1/admin/config/spec-packages`
637 ///
638 /// Required scopes: `admin`.
639 pub async fn get_admin_spec_packages(&self) -> Result<models::GetAdminSpecPackagesResponse> {
640 self.client
641 .request_json(Request {
642 method: Method::GET,
643 path: "/api/v1/admin/config/spec-packages".to_string(),
644 query: NO_QUERY,
645 body: NO_BODY,
646 headers: Vec::new(),
647 idempotent: false,
648 })
649 .await
650 }
651
652 /// Get SSE overrides (heartbeat, polling, reconnect hint)
653 ///
654 /// `GET /api/v1/admin/config/sse`
655 ///
656 /// Required scopes: `admin`.
657 pub async fn get_admin_sse_config(&self) -> Result<serde_json::Map<String, serde_json::Value>> {
658 self.client
659 .request_json(Request {
660 method: Method::GET,
661 path: "/api/v1/admin/config/sse".to_string(),
662 query: NO_QUERY,
663 body: NO_BODY,
664 headers: Vec::new(),
665 idempotent: false,
666 })
667 .await
668 }
669
670 /// Get Stripe runtime config (keys redacted)
671 ///
672 /// `GET /api/v1/admin/config/stripe`
673 ///
674 /// Required scopes: `admin`.
675 pub async fn get_admin_stripe_config(&self) -> Result<serde_json::Map<String, serde_json::Value>> {
676 self.client
677 .request_json(Request {
678 method: Method::GET,
679 path: "/api/v1/admin/config/stripe".to_string(),
680 query: NO_QUERY,
681 body: NO_BODY,
682 headers: Vec::new(),
683 idempotent: false,
684 })
685 .await
686 }
687
688 /// Per-tool presentation overrides
689 ///
690 /// A map keyed by tool id. Empty object when nothing is stored — never null.
691 ///
692 /// `GET /api/v1/admin/config/tool-overrides`
693 ///
694 /// Required scopes: `admin`.
695 pub async fn get_admin_tool_overrides(&self) -> Result<models::GetAdminToolOverridesResponse> {
696 self.client
697 .request_json(Request {
698 method: Method::GET,
699 path: "/api/v1/admin/config/tool-overrides".to_string(),
700 query: NO_QUERY,
701 body: NO_BODY,
702 headers: Vec::new(),
703 idempotent: false,
704 })
705 .await
706 }
707
708 /// Get tool security overrides (egress, SSRF, payload caps, concurrency)
709 ///
710 /// `GET /api/v1/admin/config/tool-security`
711 ///
712 /// Required scopes: `admin`.
713 pub async fn get_admin_tool_security_config(&self) -> Result<serde_json::Map<String, serde_json::Value>> {
714 self.client
715 .request_json(Request {
716 method: Method::GET,
717 path: "/api/v1/admin/config/tool-security".to_string(),
718 query: NO_QUERY,
719 body: NO_BODY,
720 headers: Vec::new(),
721 idempotent: false,
722 })
723 .await
724 }
725
726 /// Get webhook delivery overrides (separate from webhooks-policy)
727 ///
728 /// `GET /api/v1/admin/config/webhooks`
729 ///
730 /// Required scopes: `admin`.
731 pub async fn get_admin_webhooks_config(&self) -> Result<serde_json::Map<String, serde_json::Value>> {
732 self.client
733 .request_json(Request {
734 method: Method::GET,
735 path: "/api/v1/admin/config/webhooks".to_string(),
736 query: NO_QUERY,
737 body: NO_BODY,
738 headers: Vec::new(),
739 idempotent: false,
740 })
741 .await
742 }
743
744 /// Get worker pool overrides (max workers, mode, queue size)
745 ///
746 /// `GET /api/v1/admin/config/worker-pool`
747 ///
748 /// Required scopes: `admin`.
749 pub async fn get_admin_worker_pool_config(&self) -> Result<serde_json::Map<String, serde_json::Value>> {
750 self.client
751 .request_json(Request {
752 method: Method::GET,
753 path: "/api/v1/admin/config/worker-pool".to_string(),
754 query: NO_QUERY,
755 body: NO_BODY,
756 headers: Vec::new(),
757 idempotent: false,
758 })
759 .await
760 }
761
762 /// Get feature flags
763 ///
764 /// `GET /api/v1/admin/config/feature-flags`
765 ///
766 /// Required scopes: `admin`.
767 pub async fn get_feature_flags(&self) -> Result<models::GetFeatureFlagsResponse> {
768 self.client
769 .request_json(Request {
770 method: Method::GET,
771 path: "/api/v1/admin/config/feature-flags".to_string(),
772 query: NO_QUERY,
773 body: NO_BODY,
774 headers: Vec::new(),
775 idempotent: false,
776 })
777 .await
778 }
779
780 /// Get markup config
781 ///
782 /// `GET /api/v1/admin/config/markup`
783 ///
784 /// Required scopes: `admin`.
785 pub async fn get_markup_config(&self) -> Result<models::GetMarkupConfigResponse> {
786 self.client
787 .request_json(Request {
788 method: Method::GET,
789 path: "/api/v1/admin/config/markup".to_string(),
790 query: NO_QUERY,
791 body: NO_BODY,
792 headers: Vec::new(),
793 idempotent: false,
794 })
795 .await
796 }
797
798 /// Get platform base URLs (public_base_url, webhook_base_url)
799 ///
800 /// `GET /api/v1/admin/config/platform-urls`
801 ///
802 /// Required scopes: `admin`.
803 pub async fn get_platform_urls(&self) -> Result<models::GetPlatformURLSResponse> {
804 self.client
805 .request_json(Request {
806 method: Method::GET,
807 path: "/api/v1/admin/config/platform-urls".to_string(),
808 query: NO_QUERY,
809 body: NO_BODY,
810 headers: Vec::new(),
811 idempotent: false,
812 })
813 .await
814 }
815
816 /// Get rate limit config
817 ///
818 /// `GET /api/v1/admin/config/rate-limits`
819 ///
820 /// Required scopes: `admin`.
821 pub async fn get_rate_limits(&self) -> Result<models::GetRateLimitsResponse> {
822 self.client
823 .request_json(Request {
824 method: Method::GET,
825 path: "/api/v1/admin/config/rate-limits".to_string(),
826 query: NO_QUERY,
827 body: NO_BODY,
828 headers: Vec::new(),
829 idempotent: false,
830 })
831 .await
832 }
833
834 /// Get last reconciliation result
835 ///
836 /// `GET /api/v1/admin/config/reconciliation`
837 ///
838 /// Required scopes: `admin`.
839 pub async fn get_reconciliation(&self) -> Result<serde_json::Map<String, serde_json::Value>> {
840 self.client
841 .request_json(Request {
842 method: Method::GET,
843 path: "/api/v1/admin/config/reconciliation".to_string(),
844 query: NO_QUERY,
845 body: NO_BODY,
846 headers: Vec::new(),
847 idempotent: false,
848 })
849 .await
850 }
851
852 /// Get runtime config
853 ///
854 /// `GET /api/v1/admin/config/runtime`
855 ///
856 /// Required scopes: `admin`.
857 pub async fn get_runtime_config(&self) -> Result<models::GetRuntimeConfigResponse> {
858 self.client
859 .request_json(Request {
860 method: Method::GET,
861 path: "/api/v1/admin/config/runtime".to_string(),
862 query: NO_QUERY,
863 body: NO_BODY,
864 headers: Vec::new(),
865 idempotent: false,
866 })
867 .await
868 }
869
870 /// Get CORS / SSRF / upload / admin-RBAC policies
871 ///
872 /// `GET /api/v1/admin/config/security-policies`
873 ///
874 /// Required scopes: `admin`.
875 pub async fn get_security_policies(&self) -> Result<serde_json::Map<String, serde_json::Value>> {
876 self.client
877 .request_json(Request {
878 method: Method::GET,
879 path: "/api/v1/admin/config/security-policies".to_string(),
880 query: NO_QUERY,
881 body: NO_BODY,
882 headers: Vec::new(),
883 idempotent: false,
884 })
885 .await
886 }
887
888 /// Get webhook delivery + Stripe verification policy
889 ///
890 /// `GET /api/v1/admin/config/webhooks-policy`
891 ///
892 /// Required scopes: `admin`.
893 pub async fn get_webhooks_policy(&self) -> Result<serde_json::Map<String, serde_json::Value>> {
894 self.client
895 .request_json(Request {
896 method: Method::GET,
897 path: "/api/v1/admin/config/webhooks-policy".to_string(),
898 query: NO_QUERY,
899 body: NO_BODY,
900 headers: Vec::new(),
901 idempotent: false,
902 })
903 .await
904 }
905
906 /// Bulk-apply a previously exported snapshot
907 ///
908 /// `POST /api/v1/admin/config/import`
909 ///
910 /// Required scopes: `admin`.
911 pub async fn import(&self, body: &models::ImportAdminConfigRequest) -> Result<serde_json::Map<String, serde_json::Value>> {
912 self.client
913 .request_json(Request {
914 method: Method::POST,
915 path: "/api/v1/admin/config/import".to_string(),
916 query: NO_QUERY,
917 body: Some(body),
918 headers: Vec::new(),
919 idempotent: true,
920 })
921 .await
922 }
923
924 /// The admin-authored plan catalogue
925 ///
926 /// Custom plans layer over the four built-in tiers. Ordered by `program` ascending — rows with
927 /// no program sort FIRST, because an absent program compares as the empty string — then by
928 /// `id`. `count` is `plans.length`, not a total across pages: there is no paging, the catalogue
929 /// is one stored record.
930 ///
931 /// Optional fields are ABSENT rather than null throughout, so a client must test presence and
932 /// not compare against null.
933 ///
934 /// `GET /api/v1/admin/config/custom-plans`
935 ///
936 /// Required scopes: `admin`.
937 pub async fn list_custom_plans(&self) -> Result<models::ListCustomPlansResponse> {
938 self.client
939 .request_json(Request {
940 method: Method::GET,
941 path: "/api/v1/admin/config/custom-plans".to_string(),
942 query: NO_QUERY,
943 body: NO_BODY,
944 headers: Vec::new(),
945 idempotent: false,
946 })
947 .await
948 }
949
950 /// Referral and promo codes
951 ///
952 /// A promo code pays its owner tenant bonus tokens for every paid subscription redeemed with
953 /// it, and grants the subscriber a welcome balance. `count` is the array length; there is no
954 /// paging.
955 ///
956 /// `GET /api/v1/admin/config/promo-codes`
957 ///
958 /// Required scopes: `admin`.
959 pub async fn list_promo_codes(&self) -> Result<models::ListPromoCodesResponse> {
960 self.client
961 .request_json(Request {
962 method: Method::GET,
963 path: "/api/v1/admin/config/promo-codes".to_string(),
964 query: NO_QUERY,
965 body: NO_BODY,
966 headers: Vec::new(),
967 idempotent: false,
968 })
969 .await
970 }
971
972 /// What one promo code has paid out
973 ///
974 /// One entry per reward actually granted — the audit trail behind a code's `uses`. Matched
975 /// before the `{code}` route, so a code literally named `rewards` cannot shadow it.
976 ///
977 /// `GET /api/v1/admin/config/promo-codes/{code}/rewards`
978 ///
979 /// Required scopes: `admin`.
980 pub async fn list_promo_rewards(&self, code: &str) -> Result<models::ListPromoRewardsResponse> {
981 self.client
982 .request_json(Request {
983 method: Method::GET,
984 path: format!("/api/v1/admin/config/promo-codes/{}/rewards", encode_path(code)),
985 query: NO_QUERY,
986 body: NO_BODY,
987 headers: Vec::new(),
988 idempotent: false,
989 })
990 .await
991 }
992
993 /// Run reconciliation
994 ///
995 /// `POST /api/v1/admin/config/reconciliation`
996 ///
997 /// Required scopes: `admin`.
998 pub async fn run_reconciliation(&self) -> Result<serde_json::Map<String, serde_json::Value>> {
999 self.client
1000 .request_json(Request {
1001 method: Method::POST,
1002 path: "/api/v1/admin/config/reconciliation".to_string(),
1003 query: NO_QUERY,
1004 body: NO_BODY,
1005 headers: Vec::new(),
1006 idempotent: true,
1007 })
1008 .await
1009 }
1010
1011 /// Set feature flags
1012 ///
1013 /// `PUT /api/v1/admin/config/feature-flags`
1014 ///
1015 /// Required scopes: `admin`.
1016 pub async fn set_feature_flags(&self, body: &serde_json::Map<String, serde_json::Value>) -> Result<serde_json::Map<String, serde_json::Value>> {
1017 self.client
1018 .request_json(Request {
1019 method: Method::PUT,
1020 path: "/api/v1/admin/config/feature-flags".to_string(),
1021 query: NO_QUERY,
1022 body: Some(body),
1023 headers: Vec::new(),
1024 idempotent: true,
1025 })
1026 .await
1027 }
1028
1029 /// Override the billed price of one model
1030 ///
1031 /// Sets what the platform charges for a model, independent of the catalogue. Validated by hand
1032 /// rather than by a schema, so the failures are worth stating: a body that is not JSON is 400;
1033 /// `input_per_million` or `output_per_million` missing, negative, or not coercible to a finite
1034 /// number is 400; `cached_input_per_million`, when present, must be a non-negative number or
1035 /// 400.
1036 ///
1037 /// WRITE SEMANTICS: the entry replaces, the map merges. This overwrites the override for this
1038 /// model only and leaves every other model's override untouched. Omitting
1039 /// `cached_input_per_million` removes it, and cached tokens then bill at the full input rate.
1040 ///
1041 /// Note the response key is `modelRef` — camelCase, an outlier in a snake_case API, and
1042 /// documented as sent.
1043 ///
1044 /// `PUT /api/v1/admin/config/model-pricing/{modelRef}`
1045 ///
1046 /// Required scopes: `admin`.
1047 pub async fn set_model_pricing_override(&self, model_ref: &str, body: &models::SetModelPricingOverrideRequest) -> Result<models::SetModelPricingOverrideResponse> {
1048 self.client
1049 .request_json(Request {
1050 method: Method::PUT,
1051 path: format!("/api/v1/admin/config/model-pricing/{}", encode_path(model_ref)),
1052 query: NO_QUERY,
1053 body: Some(body),
1054 headers: Vec::new(),
1055 idempotent: true,
1056 })
1057 .await
1058 }
1059
1060 /// Set rate limits
1061 ///
1062 /// `PUT /api/v1/admin/config/rate-limits`
1063 ///
1064 /// Required scopes: `admin`.
1065 pub async fn set_rate_limits(&self, body: &serde_json::Map<String, serde_json::Value>) -> Result<serde_json::Map<String, serde_json::Value>> {
1066 self.client
1067 .request_json(Request {
1068 method: Method::PUT,
1069 path: "/api/v1/admin/config/rate-limits".to_string(),
1070 query: NO_QUERY,
1071 body: Some(body),
1072 headers: Vec::new(),
1073 idempotent: true,
1074 })
1075 .await
1076 }
1077
1078 /// Send a test email through the effective SMTP config
1079 ///
1080 /// Sends for real, using whichever layer `source` reports — this is not a dry run. A delivery
1081 /// failure is **500** carrying the SMTP error text, not a 200 with `ok: false`, so a client
1082 /// must read the status rather than a field.
1083 ///
1084 /// `POST /api/v1/admin/config/smtp/test`
1085 ///
1086 /// Required scopes: `admin`.
1087 pub async fn test_admin_smtp_config(&self, body: &models::TestAdminSmtpConfigRequest) -> Result<models::TestAdminSmtpConfigResponse> {
1088 self.client
1089 .request_json(Request {
1090 method: Method::POST,
1091 path: "/api/v1/admin/config/smtp/test".to_string(),
1092 query: NO_QUERY,
1093 body: Some(body),
1094 headers: Vec::new(),
1095 idempotent: true,
1096 })
1097 .await
1098 }
1099
1100 /// Verify stored secret_key authenticates against Stripe (read-only)
1101 ///
1102 /// `POST /api/v1/admin/config/stripe/test`
1103 ///
1104 /// Required scopes: `admin`.
1105 pub async fn test_admin_stripe_config(&self) -> Result<serde_json::Map<String, serde_json::Value>> {
1106 self.client
1107 .request_json(Request {
1108 method: Method::POST,
1109 path: "/api/v1/admin/config/stripe/test".to_string(),
1110 query: NO_QUERY,
1111 body: NO_BODY,
1112 headers: Vec::new(),
1113 idempotent: true,
1114 })
1115 .await
1116 }
1117
1118 /// Update agent memory overrides
1119 ///
1120 /// `PUT /api/v1/admin/config/agent-memory`
1121 ///
1122 /// Required scopes: `admin`.
1123 pub async fn update_admin_agent_memory_config(&self, body: &serde_json::Map<String, serde_json::Value>) -> Result<serde_json::Map<String, serde_json::Value>> {
1124 self.client
1125 .request_json(Request {
1126 method: Method::PUT,
1127 path: "/api/v1/admin/config/agent-memory".to_string(),
1128 query: NO_QUERY,
1129 body: Some(body),
1130 headers: Vec::new(),
1131 idempotent: true,
1132 })
1133 .await
1134 }
1135
1136 /// Update auth runtime overrides
1137 ///
1138 /// `PUT /api/v1/admin/config/auth`
1139 ///
1140 /// Required scopes: `admin`.
1141 pub async fn update_admin_auth_config(&self, body: &serde_json::Map<String, serde_json::Value>) -> Result<serde_json::Map<String, serde_json::Value>> {
1142 self.client
1143 .request_json(Request {
1144 method: Method::PUT,
1145 path: "/api/v1/admin/config/auth".to_string(),
1146 query: NO_QUERY,
1147 body: Some(body),
1148 headers: Vec::new(),
1149 idempotent: true,
1150 })
1151 .await
1152 }
1153
1154 /// Update backpressure overrides
1155 ///
1156 /// `PUT /api/v1/admin/config/backpressure`
1157 ///
1158 /// Required scopes: `admin`.
1159 pub async fn update_admin_backpressure_config(&self, body: &serde_json::Map<String, serde_json::Value>) -> Result<serde_json::Map<String, serde_json::Value>> {
1160 self.client
1161 .request_json(Request {
1162 method: Method::PUT,
1163 path: "/api/v1/admin/config/backpressure".to_string(),
1164 query: NO_QUERY,
1165 body: Some(body),
1166 headers: Vec::new(),
1167 idempotent: true,
1168 })
1169 .await
1170 }
1171
1172 /// Update code-interpreter overrides
1173 ///
1174 /// `PUT /api/v1/admin/config/code-interpreter`
1175 ///
1176 /// Required scopes: `admin`.
1177 pub async fn update_admin_code_interpreter_config(&self, body: &serde_json::Map<String, serde_json::Value>) -> Result<serde_json::Map<String, serde_json::Value>> {
1178 self.client
1179 .request_json(Request {
1180 method: Method::PUT,
1181 path: "/api/v1/admin/config/code-interpreter".to_string(),
1182 query: NO_QUERY,
1183 body: Some(body),
1184 headers: Vec::new(),
1185 idempotent: true,
1186 })
1187 .await
1188 }
1189
1190 /// Replace the platform-wide disabled tool list
1191 ///
1192 /// **The body is a bare JSON ARRAY, not an object** — an outlier on a surface where every other
1193 /// write takes an object, and a client that wraps it in `{disabled_tools: \[…\]}` gets 400.
1194 ///
1195 /// Gated on a FRESH MFA challenge.
1196 ///
1197 /// WRITE SEMANTICS: replaces. The array given becomes the list. It must be NON-EMPTY and every
1198 /// element a non-empty string, so there is no way to disable nothing through this route —
1199 /// clearing the list is not expressible here.
1200 ///
1201 /// `PUT /api/v1/admin/config/disabled-tools`
1202 ///
1203 /// Required scopes: `admin`.
1204 pub async fn update_admin_disabled_tools(&self, body: &Vec<String>) -> Result<models::UpdateAdminDisabledToolsResponse> {
1205 self.client
1206 .request_json(Request {
1207 method: Method::PUT,
1208 path: "/api/v1/admin/config/disabled-tools".to_string(),
1209 query: NO_QUERY,
1210 body: Some(body),
1211 headers: Vec::new(),
1212 idempotent: true,
1213 })
1214 .await
1215 }
1216
1217 /// Update evaluation overrides
1218 ///
1219 /// `PUT /api/v1/admin/config/evaluation`
1220 ///
1221 /// Required scopes: `admin`.
1222 pub async fn update_admin_evaluation_config(&self, body: &serde_json::Map<String, serde_json::Value>) -> Result<serde_json::Map<String, serde_json::Value>> {
1223 self.client
1224 .request_json(Request {
1225 method: Method::PUT,
1226 path: "/api/v1/admin/config/evaluation".to_string(),
1227 query: NO_QUERY,
1228 body: Some(body),
1229 headers: Vec::new(),
1230 idempotent: true,
1231 })
1232 .await
1233 }
1234
1235 /// Set the stored founder identity
1236 ///
1237 /// Answers the same body the GET does.
1238 ///
1239 /// WRITE SEMANTICS: merges. Omitted fields keep their stored values. Unlike SMTP, an empty
1240 /// string IS accepted on every field here and means "leave unset" — deliberately, because the
1241 /// admin UI echoes current values back and a no-op save of an unset identity must not 422.
1242 ///
1243 /// `PUT /api/v1/admin/config/founder`
1244 ///
1245 /// Required scopes: `admin`.
1246 pub async fn update_admin_founder_config(&self, body: &models::UpdateAdminFounderConfigRequest) -> Result<serde_json::Map<String, serde_json::Value>> {
1247 self.client
1248 .request_json(Request {
1249 method: Method::PUT,
1250 path: "/api/v1/admin/config/founder".to_string(),
1251 query: NO_QUERY,
1252 body: Some(body),
1253 headers: Vec::new(),
1254 idempotent: true,
1255 })
1256 .await
1257 }
1258
1259 /// Update guardrail config
1260 ///
1261 /// `PUT /api/v1/admin/config/guardrails`
1262 ///
1263 /// Required scopes: `admin`.
1264 pub async fn update_admin_guardrails(&self, body: &serde_json::Map<String, serde_json::Value>) -> Result<serde_json::Map<String, serde_json::Value>> {
1265 self.client
1266 .request_json(Request {
1267 method: Method::PUT,
1268 path: "/api/v1/admin/config/guardrails".to_string(),
1269 query: NO_QUERY,
1270 body: Some(body),
1271 headers: Vec::new(),
1272 idempotent: true,
1273 })
1274 .await
1275 }
1276
1277 /// Update idempotency overrides
1278 ///
1279 /// `PUT /api/v1/admin/config/idempotency`
1280 ///
1281 /// Required scopes: `admin`.
1282 pub async fn update_admin_idempotency_config(&self, body: &serde_json::Map<String, serde_json::Value>) -> Result<serde_json::Map<String, serde_json::Value>> {
1283 self.client
1284 .request_json(Request {
1285 method: Method::PUT,
1286 path: "/api/v1/admin/config/idempotency".to_string(),
1287 query: NO_QUERY,
1288 body: Some(body),
1289 headers: Vec::new(),
1290 idempotent: true,
1291 })
1292 .await
1293 }
1294
1295 /// Update integrations
1296 ///
1297 /// `PUT /api/v1/admin/config/integrations`
1298 ///
1299 /// Required scopes: `admin`.
1300 pub async fn update_admin_integrations(&self, body: &serde_json::Map<String, serde_json::Value>) -> Result<serde_json::Map<String, serde_json::Value>> {
1301 self.client
1302 .request_json(Request {
1303 method: Method::PUT,
1304 path: "/api/v1/admin/config/integrations".to_string(),
1305 query: NO_QUERY,
1306 body: Some(body),
1307 headers: Vec::new(),
1308 idempotent: true,
1309 })
1310 .await
1311 }
1312
1313 /// Update LLM adapter overrides
1314 ///
1315 /// `PUT /api/v1/admin/config/llm-adapters`
1316 ///
1317 /// Required scopes: `admin`.
1318 pub async fn update_admin_llm_adapters_config(&self, body: &serde_json::Map<String, serde_json::Value>) -> Result<serde_json::Map<String, serde_json::Value>> {
1319 self.client
1320 .request_json(Request {
1321 method: Method::PUT,
1322 path: "/api/v1/admin/config/llm-adapters".to_string(),
1323 query: NO_QUERY,
1324 body: Some(body),
1325 headers: Vec::new(),
1326 idempotent: true,
1327 })
1328 .await
1329 }
1330
1331 /// Update logging overrides
1332 ///
1333 /// `PUT /api/v1/admin/config/logging`
1334 ///
1335 /// Required scopes: `admin`.
1336 pub async fn update_admin_logging_config(&self, body: &serde_json::Map<String, serde_json::Value>) -> Result<serde_json::Map<String, serde_json::Value>> {
1337 self.client
1338 .request_json(Request {
1339 method: Method::PUT,
1340 path: "/api/v1/admin/config/logging".to_string(),
1341 query: NO_QUERY,
1342 body: Some(body),
1343 headers: Vec::new(),
1344 idempotent: true,
1345 })
1346 .await
1347 }
1348
1349 /// Update long-running overrides
1350 ///
1351 /// `PUT /api/v1/admin/config/long-running`
1352 ///
1353 /// Required scopes: `admin`.
1354 pub async fn update_admin_long_running_config(&self, body: &serde_json::Map<String, serde_json::Value>) -> Result<serde_json::Map<String, serde_json::Value>> {
1355 self.client
1356 .request_json(Request {
1357 method: Method::PUT,
1358 path: "/api/v1/admin/config/long-running".to_string(),
1359 query: NO_QUERY,
1360 body: Some(body),
1361 headers: Vec::new(),
1362 idempotent: true,
1363 })
1364 .await
1365 }
1366
1367 /// Update MCP overrides
1368 ///
1369 /// `PUT /api/v1/admin/config/mcp`
1370 ///
1371 /// Required scopes: `admin`.
1372 pub async fn update_admin_mcp_config(&self, body: &serde_json::Map<String, serde_json::Value>) -> Result<serde_json::Map<String, serde_json::Value>> {
1373 self.client
1374 .request_json(Request {
1375 method: Method::PUT,
1376 path: "/api/v1/admin/config/mcp".to_string(),
1377 query: NO_QUERY,
1378 body: Some(body),
1379 headers: Vec::new(),
1380 idempotent: true,
1381 })
1382 .await
1383 }
1384
1385 /// Update multimodal overrides
1386 ///
1387 /// `PUT /api/v1/admin/config/multimodal`
1388 ///
1389 /// Required scopes: `admin`.
1390 pub async fn update_admin_multimodal_config(&self, body: &serde_json::Map<String, serde_json::Value>) -> Result<serde_json::Map<String, serde_json::Value>> {
1391 self.client
1392 .request_json(Request {
1393 method: Method::PUT,
1394 path: "/api/v1/admin/config/multimodal".to_string(),
1395 query: NO_QUERY,
1396 body: Some(body),
1397 headers: Vec::new(),
1398 idempotent: true,
1399 })
1400 .await
1401 }
1402
1403 /// Set Apple identifiers and the return-to allowlist
1404 ///
1405 /// Answers the same body the GET does.
1406 ///
1407 /// WRITE SEMANTICS: merges. Omitted fields keep their stored values; a present
1408 /// `oauth_return_to_hosts` REPLACES the stored list rather than adding to it.
1409 ///
1410 /// `PUT /api/v1/admin/config/oauth-identity`
1411 ///
1412 /// Required scopes: `admin`.
1413 pub async fn update_admin_o_auth_identity_config(&self, body: &models::UpdateAdminOAuthIdentityConfigRequest) -> Result<serde_json::Map<String, serde_json::Value>> {
1414 self.client
1415 .request_json(Request {
1416 method: Method::PUT,
1417 path: "/api/v1/admin/config/oauth-identity".to_string(),
1418 query: NO_QUERY,
1419 body: Some(body),
1420 headers: Vec::new(),
1421 idempotent: true,
1422 })
1423 .await
1424 }
1425
1426 /// Update persistence overrides
1427 ///
1428 /// `PUT /api/v1/admin/config/persistence`
1429 ///
1430 /// Required scopes: `admin`.
1431 pub async fn update_admin_persistence_config(&self, body: &serde_json::Map<String, serde_json::Value>) -> Result<serde_json::Map<String, serde_json::Value>> {
1432 self.client
1433 .request_json(Request {
1434 method: Method::PUT,
1435 path: "/api/v1/admin/config/persistence".to_string(),
1436 query: NO_QUERY,
1437 body: Some(body),
1438 headers: Vec::new(),
1439 idempotent: true,
1440 })
1441 .await
1442 }
1443
1444 /// Update plans
1445 ///
1446 /// `PUT /api/v1/admin/config/plans`
1447 ///
1448 /// Required scopes: `admin`.
1449 pub async fn update_admin_plans(&self, body: &models::UpdateAdminPlansRequest) -> Result<models::UpdateAdminPlansResponse> {
1450 self.client
1451 .request_json(Request {
1452 method: Method::PUT,
1453 path: "/api/v1/admin/config/plans".to_string(),
1454 query: NO_QUERY,
1455 body: Some(body),
1456 headers: Vec::new(),
1457 idempotent: true,
1458 })
1459 .await
1460 }
1461
1462 /// Open or close registration, and set signup defaults
1463 ///
1464 /// **Opening registration when it is currently CLOSED requires `confirm_open: true`.** Without
1465 /// it the answer is 400, and the message says so. This is not ceremony: on 2026-06-11 a
1466 /// long-lived admin tab running a stale bundle re-submitted its whole form four times in one
1467 /// day, each time carrying a stale `registration_open: true`, and silently re-opened doors an
1468 /// operator had ordered shut. An explicit confirm is something no stale form can send by
1469 /// accident. Closing, and a no-op re-save while already open, need no confirm.
1470 ///
1471 /// A second 400 refuses opening while required setup steps are outstanding, and names them.
1472 ///
1473 /// Answers the same body the GET does.
1474 ///
1475 /// WRITE SEMANTICS: merges. Omitted fields keep their stored values. `default_signup_plan` and
1476 /// `allowed_email_domains` are stored only when present; an empty `default_signup_plan` clears
1477 /// it back to the `free` default.
1478 ///
1479 /// `PUT /api/v1/admin/config/registration`
1480 ///
1481 /// Required scopes: `admin`.
1482 pub async fn update_admin_registration_config(&self, body: &models::UpdateAdminRegistrationConfigRequest) -> Result<serde_json::Map<String, serde_json::Value>> {
1483 self.client
1484 .request_json(Request {
1485 method: Method::PUT,
1486 path: "/api/v1/admin/config/registration".to_string(),
1487 query: NO_QUERY,
1488 body: Some(body),
1489 headers: Vec::new(),
1490 idempotent: true,
1491 })
1492 .await
1493 }
1494
1495 /// Update retention overrides
1496 ///
1497 /// `PUT /api/v1/admin/config/retention`
1498 ///
1499 /// Required scopes: `admin`.
1500 pub async fn update_admin_retention_config(&self, body: &serde_json::Map<String, serde_json::Value>) -> Result<serde_json::Map<String, serde_json::Value>> {
1501 self.client
1502 .request_json(Request {
1503 method: Method::PUT,
1504 path: "/api/v1/admin/config/retention".to_string(),
1505 query: NO_QUERY,
1506 body: Some(body),
1507 headers: Vec::new(),
1508 idempotent: true,
1509 })
1510 .await
1511 }
1512
1513 /// Update run_command overrides
1514 ///
1515 /// `PUT /api/v1/admin/config/run-command`
1516 ///
1517 /// Required scopes: `admin`.
1518 pub async fn update_admin_run_command_config(&self, body: &serde_json::Map<String, serde_json::Value>) -> Result<serde_json::Map<String, serde_json::Value>> {
1519 self.client
1520 .request_json(Request {
1521 method: Method::PUT,
1522 path: "/api/v1/admin/config/run-command".to_string(),
1523 query: NO_QUERY,
1524 body: Some(body),
1525 headers: Vec::new(),
1526 idempotent: true,
1527 })
1528 .await
1529 }
1530
1531 /// Update server overrides
1532 ///
1533 /// `PUT /api/v1/admin/config/server`
1534 ///
1535 /// Required scopes: `admin`.
1536 pub async fn update_admin_server_config(&self, body: &serde_json::Map<String, serde_json::Value>) -> Result<serde_json::Map<String, serde_json::Value>> {
1537 self.client
1538 .request_json(Request {
1539 method: Method::PUT,
1540 path: "/api/v1/admin/config/server".to_string(),
1541 query: NO_QUERY,
1542 body: Some(body),
1543 headers: Vec::new(),
1544 idempotent: true,
1545 })
1546 .await
1547 }
1548
1549 /// Mark setup steps complete, or flip the registration gate
1550 ///
1551 /// WRITE SEMANTICS: mixed, and the mixed half is the point. `completed_steps` is a UNION — the
1552 /// steps given are ADDED to the stored list and never removed — so re-sending the same PATCH is
1553 /// idempotent and there is no way to un-complete a step through this route. `registration_open`
1554 /// is a plain overwrite.
1555 ///
1556 /// **Opening registration requires `confirm_open: true`** when it is currently closed, exactly
1557 /// as `PUT /api/v1/admin/config/registration` does. The guard lives in both places on purpose:
1558 /// without it here, the lower-level endpoint was a way around the confirm that the launch-day
1559 /// incident of 2026-06-11 put there.
1560 ///
1561 /// Opening also refuses with 400 while any required step is outstanding, naming them.
1562 ///
1563 /// `status` reaching `live` is a ONE-WAY latch. Once setup has completed, CLOSING registration
1564 /// is an operational mode — a pre-registration wave — and does NOT return the platform to
1565 /// `in_progress`. Before that was fixed, closing sent the super admin back into the setup
1566 /// wizard on every page, and the wizard's only exit was the very switch they had just turned
1567 /// off.
1568 ///
1569 /// The write is a compare-and-set retried up to six times; a persistently contended record
1570 /// answers **503** rather than overwriting a concurrent change.
1571 ///
1572 /// `PATCH /api/v1/admin/config/setup-state`
1573 ///
1574 /// Required scopes: `admin`.
1575 pub async fn update_admin_setup_state(&self, body: &models::UpdateAdminSetupStateRequest) -> Result<models::SetupStateResponse> {
1576 self.client
1577 .request_json(Request {
1578 method: Method::PATCH,
1579 path: "/api/v1/admin/config/setup-state".to_string(),
1580 query: NO_QUERY,
1581 body: Some(body),
1582 headers: Vec::new(),
1583 idempotent: true,
1584 })
1585 .await
1586 }
1587
1588 /// Update stored SMTP config
1589 ///
1590 /// Answers the same body the GET does, so a client does not re-read to see what took effect.
1591 ///
1592 /// WRITE SEMANTICS: merges. A field the body omits keeps its stored value. An empty string
1593 /// CLEARS, but only where the validator admits one: `password` and `from_name` accept `""`,
1594 /// while `host`, `user` and `from` are rejected with 422 before the merge is reached — `host`
1595 /// and `user` require at least one character and `from` must parse as an email. So a stored
1596 /// host cannot be blanked through this route, only overwritten.
1597 ///
1598 /// `password: ""` is the operator-initiated clear: it drops both the encrypted and plaintext
1599 /// fields so the next read falls back to the environment. A password is stored
1600 /// AES-GCM-encrypted when an encryption key is configured; without one it is stored in
1601 /// plaintext and the server logs a warning rather than refusing.
1602 ///
1603 /// `PUT /api/v1/admin/config/smtp`
1604 ///
1605 /// Required scopes: `admin`.
1606 pub async fn update_admin_smtp_config(&self, body: &models::UpdateAdminSmtpConfigRequest) -> Result<serde_json::Map<String, serde_json::Value>> {
1607 self.client
1608 .request_json(Request {
1609 method: Method::PUT,
1610 path: "/api/v1/admin/config/smtp".to_string(),
1611 query: NO_QUERY,
1612 body: Some(body),
1613 headers: Vec::new(),
1614 idempotent: true,
1615 })
1616 .await
1617 }
1618
1619 /// Replace the SPEC-package map
1620 ///
1621 /// WRITE SEMANTICS: replaces. The map given becomes the whole map, so a package omitted from
1622 /// the body is DELETED. Two guards exist because of that.
1623 ///
1624 /// **A drop that would remove a package with a wired `stripe_price_id` is refused with 422**
1625 /// unless the caller opts in per id: `?confirm_drop=\<id\>\[,\<id\>\]`. Tenants may be
1626 /// subscribed against that price, so losing it silently is not a save, it is a billing
1627 /// incident. The refusal names every id it is protecting.
1628 ///
1629 /// **Each map KEY must equal its record's `package_id`**, or 422. The map is keyed by id
1630 /// everywhere downstream, so a key that disagrees with its record orphans the package at the
1631 /// next read.
1632 ///
1633 /// `updated_at` is stamped by the server on every record in the payload and is not read from
1634 /// the body.
1635 ///
1636 /// `PUT /api/v1/admin/config/spec-packages`
1637 ///
1638 /// Required scopes: `admin`.
1639 pub async fn update_admin_spec_packages(&self, body: &models::UpdateAdminSpecPackagesRequest, params: &UpdateAdminSpecPackagesParams) -> Result<serde_json::Map<String, serde_json::Value>> {
1640 self.client
1641 .request_json(Request {
1642 method: Method::PUT,
1643 path: "/api/v1/admin/config/spec-packages".to_string(),
1644 query: Some(params),
1645 body: Some(body),
1646 headers: Vec::new(),
1647 idempotent: true,
1648 })
1649 .await
1650 }
1651
1652 /// Update SSE overrides
1653 ///
1654 /// `PUT /api/v1/admin/config/sse`
1655 ///
1656 /// Required scopes: `admin`.
1657 pub async fn update_admin_sse_config(&self, body: &serde_json::Map<String, serde_json::Value>) -> Result<serde_json::Map<String, serde_json::Value>> {
1658 self.client
1659 .request_json(Request {
1660 method: Method::PUT,
1661 path: "/api/v1/admin/config/sse".to_string(),
1662 query: NO_QUERY,
1663 body: Some(body),
1664 headers: Vec::new(),
1665 idempotent: true,
1666 })
1667 .await
1668 }
1669
1670 /// Update Stripe keys/mode/price IDs; rebuilds BillingManager
1671 ///
1672 /// `PUT /api/v1/admin/config/stripe`
1673 ///
1674 /// Required scopes: `admin`.
1675 pub async fn update_admin_stripe_config(&self, body: &models::UpdateAdminStripeConfigRequest) -> Result<serde_json::Map<String, serde_json::Value>> {
1676 self.client
1677 .request_json(Request {
1678 method: Method::PUT,
1679 path: "/api/v1/admin/config/stripe".to_string(),
1680 query: NO_QUERY,
1681 body: Some(body),
1682 headers: Vec::new(),
1683 idempotent: true,
1684 })
1685 .await
1686 }
1687
1688 /// Replace the per-tool presentation overrides
1689 ///
1690 /// These affect PRESENTATION only. The runtime tool catalogue is code-defined, so an override
1691 /// changes what the catalogue page shows and nothing about what an agent can call — including
1692 /// `hidden`, which hides the row by default while the runtime still serves the tool. An
1693 /// operator reaching for `hidden` to switch a tool OFF wants `disabled-tools` instead.
1694 ///
1695 /// Gated on a FRESH MFA challenge.
1696 ///
1697 /// WRITE SEMANTICS: replaces. The map given becomes the whole map, so an id omitted from the
1698 /// body is deleted. Two further rules follow from that: an entry whose fields are all empty is
1699 /// DROPPED rather than stored — sending `{}` for an id is how the client deletes just that one
1700 /// — and `hidden` is stored only when literally `true`, so `hidden: false` deletes the flag
1701 /// rather than recording it.
1702 ///
1703 /// Every key is checked against the runtime's built-in tool ids: an unknown id is **422**,
1704 /// distinct from the 400 a malformed body gets. The outer object is strict — an unexpected
1705 /// top-level key is rejected, not stripped.
1706 ///
1707 /// `PUT /api/v1/admin/config/tool-overrides`
1708 ///
1709 /// Required scopes: `admin`.
1710 pub async fn update_admin_tool_overrides(&self, body: &models::UpdateAdminToolOverridesRequest) -> Result<models::UpdateAdminToolOverridesResponse> {
1711 self.client
1712 .request_json(Request {
1713 method: Method::PUT,
1714 path: "/api/v1/admin/config/tool-overrides".to_string(),
1715 query: NO_QUERY,
1716 body: Some(body),
1717 headers: Vec::new(),
1718 idempotent: true,
1719 })
1720 .await
1721 }
1722
1723 /// Update tool security overrides
1724 ///
1725 /// `PUT /api/v1/admin/config/tool-security`
1726 ///
1727 /// Required scopes: `admin`.
1728 pub async fn update_admin_tool_security_config(&self, body: &serde_json::Map<String, serde_json::Value>) -> Result<serde_json::Map<String, serde_json::Value>> {
1729 self.client
1730 .request_json(Request {
1731 method: Method::PUT,
1732 path: "/api/v1/admin/config/tool-security".to_string(),
1733 query: NO_QUERY,
1734 body: Some(body),
1735 headers: Vec::new(),
1736 idempotent: true,
1737 })
1738 .await
1739 }
1740
1741 /// Update webhook delivery overrides
1742 ///
1743 /// `PUT /api/v1/admin/config/webhooks`
1744 ///
1745 /// Required scopes: `admin`.
1746 pub async fn update_admin_webhooks_config(&self, body: &serde_json::Map<String, serde_json::Value>) -> Result<serde_json::Map<String, serde_json::Value>> {
1747 self.client
1748 .request_json(Request {
1749 method: Method::PUT,
1750 path: "/api/v1/admin/config/webhooks".to_string(),
1751 query: NO_QUERY,
1752 body: Some(body),
1753 headers: Vec::new(),
1754 idempotent: true,
1755 })
1756 .await
1757 }
1758
1759 /// Update worker pool overrides
1760 ///
1761 /// `PUT /api/v1/admin/config/worker-pool`
1762 ///
1763 /// Required scopes: `admin`.
1764 pub async fn update_admin_worker_pool_config(&self, body: &serde_json::Map<String, serde_json::Value>) -> Result<serde_json::Map<String, serde_json::Value>> {
1765 self.client
1766 .request_json(Request {
1767 method: Method::PUT,
1768 path: "/api/v1/admin/config/worker-pool".to_string(),
1769 query: NO_QUERY,
1770 body: Some(body),
1771 headers: Vec::new(),
1772 idempotent: true,
1773 })
1774 .await
1775 }
1776
1777 /// Update markup
1778 ///
1779 /// `PUT /api/v1/admin/config/markup`
1780 ///
1781 /// Required scopes: `admin`.
1782 pub async fn update_markup_config(&self, body: &serde_json::Map<String, serde_json::Value>) -> Result<serde_json::Map<String, serde_json::Value>> {
1783 self.client
1784 .request_json(Request {
1785 method: Method::PUT,
1786 path: "/api/v1/admin/config/markup".to_string(),
1787 query: NO_QUERY,
1788 body: Some(body),
1789 headers: Vec::new(),
1790 idempotent: true,
1791 })
1792 .await
1793 }
1794
1795 /// Update public_base_url and webhook_base_url
1796 ///
1797 /// `PUT /api/v1/admin/config/platform-urls`
1798 ///
1799 /// Required scopes: `admin`.
1800 pub async fn update_platform_urls(&self, body: &models::UpdatePlatformURLSRequest) -> Result<serde_json::Map<String, serde_json::Value>> {
1801 self.client
1802 .request_json(Request {
1803 method: Method::PUT,
1804 path: "/api/v1/admin/config/platform-urls".to_string(),
1805 query: NO_QUERY,
1806 body: Some(body),
1807 headers: Vec::new(),
1808 idempotent: true,
1809 })
1810 .await
1811 }
1812
1813 /// Update runtime
1814 ///
1815 /// `PUT /api/v1/admin/config/runtime`
1816 ///
1817 /// Required scopes: `admin`.
1818 pub async fn update_runtime_config(&self, body: &serde_json::Map<String, serde_json::Value>) -> Result<serde_json::Map<String, serde_json::Value>> {
1819 self.client
1820 .request_json(Request {
1821 method: Method::PUT,
1822 path: "/api/v1/admin/config/runtime".to_string(),
1823 query: NO_QUERY,
1824 body: Some(body),
1825 headers: Vec::new(),
1826 idempotent: true,
1827 })
1828 .await
1829 }
1830
1831 /// Update security policies
1832 ///
1833 /// `PUT /api/v1/admin/config/security-policies`
1834 ///
1835 /// Required scopes: `admin`.
1836 pub async fn update_security_policies(&self, body: &models::UpdateSecurityPoliciesRequest) -> Result<serde_json::Map<String, serde_json::Value>> {
1837 self.client
1838 .request_json(Request {
1839 method: Method::PUT,
1840 path: "/api/v1/admin/config/security-policies".to_string(),
1841 query: NO_QUERY,
1842 body: Some(body),
1843 headers: Vec::new(),
1844 idempotent: true,
1845 })
1846 .await
1847 }
1848
1849 /// Update webhooks policy
1850 ///
1851 /// `PUT /api/v1/admin/config/webhooks-policy`
1852 ///
1853 /// Required scopes: `admin`.
1854 pub async fn update_webhooks_policy(&self, body: &models::UpdateWebhooksPolicyRequest) -> Result<serde_json::Map<String, serde_json::Value>> {
1855 self.client
1856 .request_json(Request {
1857 method: Method::PUT,
1858 path: "/api/v1/admin/config/webhooks-policy".to_string(),
1859 query: NO_QUERY,
1860 body: Some(body),
1861 headers: Vec::new(),
1862 idempotent: true,
1863 })
1864 .await
1865 }
1866
1867 /// Create or replace one custom plan
1868 ///
1869 /// WRITE SEMANTICS: replaces. The stored record is rebuilt from this body; only `created_at`
1870 /// survives from the previous version. An omitted field does NOT keep its stored value — it
1871 /// takes the schema's default or disappears.
1872 ///
1873 /// **Two defaults make an omission destructive, and the dangerous one is `active`.** It is
1874 /// `default(true)`, so re-saving a DEACTIVATED plan without sending `active` silently
1875 /// reactivates it. `visibility` is `default("hidden")`, so re-saving a public plan without
1876 /// sending it hides the plan from every tenant. Neither reports anything: the answer is 200 and
1877 /// the record looks freshly written.
1878 ///
1879 /// Unknown keys are stripped rather than rejected, so a typo'd field name is accepted and
1880 /// dropped with a 200.
1881 ///
1882 /// A built-in plan id (`free`, `starter`, `pro`, `enterprise`) is **409**, pointing at `PUT
1883 /// /api/v1/admin/config/plans` — the route that does own those.
1884 ///
1885 /// `PUT /api/v1/admin/config/custom-plans/{planId}`
1886 ///
1887 /// Required scopes: `admin`.
1888 pub async fn upsert_custom_plan(&self, plan_id: &str, body: &models::CustomPlanInput) -> Result<models::UpsertCustomPlanResponse> {
1889 self.client
1890 .request_json(Request {
1891 method: Method::PUT,
1892 path: format!("/api/v1/admin/config/custom-plans/{}", encode_path(plan_id)),
1893 query: NO_QUERY,
1894 body: Some(body),
1895 headers: Vec::new(),
1896 idempotent: true,
1897 })
1898 .await
1899 }
1900
1901 /// Create or replace one promo code
1902 ///
1903 /// WRITE SEMANTICS: replaces. Only `uses` and `created_at` survive from the previous version;
1904 /// every other field comes from this body, and an omitted field is dropped.
1905 ///
1906 /// **`target_plan_id` is the omission that costs money.** It scopes the code to one plan, and
1907 /// the reward path returns early when it is set and does not match the plan being paid for.
1908 /// Replace a scoped code without resending it and the code becomes redeemable on EVERY plan —
1909 /// 200, no warning, and the stored row looks the same size as before. `active` behaves the same
1910 /// way as on custom plans: `default(true)`, so omitting it reactivates a deactivated code.
1911 ///
1912 /// `PUT /api/v1/admin/config/promo-codes/{code}`
1913 ///
1914 /// Required scopes: `admin`.
1915 pub async fn upsert_promo_code(&self, code: &str, body: &models::PromoCodeInput) -> Result<models::UpsertPromoCodeResponse> {
1916 self.client
1917 .request_json(Request {
1918 method: Method::PUT,
1919 path: format!("/api/v1/admin/config/promo-codes/{}", encode_path(code)),
1920 query: NO_QUERY,
1921 body: Some(body),
1922 headers: Vec::new(),
1923 idempotent: true,
1924 })
1925 .await
1926 }
1927}