@extrovert.dev/mcp 0.1.0-pre.3

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 (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +313 -0
  3. package/dist/bin.d.ts +13 -0
  4. package/dist/bin.d.ts.map +1 -0
  5. package/dist/bin.js +89 -0
  6. package/dist/bin.js.map +1 -0
  7. package/dist/client.d.ts +956 -0
  8. package/dist/client.d.ts.map +1 -0
  9. package/dist/client.js +1354 -0
  10. package/dist/client.js.map +1 -0
  11. package/dist/config.d.ts +51 -0
  12. package/dist/config.d.ts.map +1 -0
  13. package/dist/config.js +53 -0
  14. package/dist/config.js.map +1 -0
  15. package/dist/contract.d.ts +62 -0
  16. package/dist/contract.d.ts.map +1 -0
  17. package/dist/contract.js +78 -0
  18. package/dist/contract.js.map +1 -0
  19. package/dist/extract.d.ts +25 -0
  20. package/dist/extract.d.ts.map +1 -0
  21. package/dist/extract.js +131 -0
  22. package/dist/extract.js.map +1 -0
  23. package/dist/fixtures.d.ts +676 -0
  24. package/dist/fixtures.d.ts.map +1 -0
  25. package/dist/fixtures.js +2685 -0
  26. package/dist/fixtures.js.map +1 -0
  27. package/dist/http.d.ts +18 -0
  28. package/dist/http.d.ts.map +1 -0
  29. package/dist/http.js +124 -0
  30. package/dist/http.js.map +1 -0
  31. package/dist/index.d.ts +17 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +18 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/server.d.ts +20 -0
  36. package/dist/server.d.ts.map +1 -0
  37. package/dist/server.js +36 -0
  38. package/dist/server.js.map +1 -0
  39. package/dist/stdio.d.ts +8 -0
  40. package/dist/stdio.d.ts.map +1 -0
  41. package/dist/stdio.js +22 -0
  42. package/dist/stdio.js.map +1 -0
  43. package/dist/tools.d.ts +27 -0
  44. package/dist/tools.d.ts.map +1 -0
  45. package/dist/tools.js +2752 -0
  46. package/dist/tools.js.map +1 -0
  47. package/dist/types.d.ts +1037 -0
  48. package/dist/types.d.ts.map +1 -0
  49. package/dist/types.js +83 -0
  50. package/dist/types.js.map +1 -0
  51. package/package.json +72 -0
@@ -0,0 +1,956 @@
1
+ /**
2
+ * Thin, typed Extrovert API client.
3
+ *
4
+ * One method per REST endpoint in spec §8 (`/v1`). The base URL and scoped
5
+ * agent key come from config (env `EXTROVERT_API_BASE_URL` / `EXTROVERT_API_KEY`).
6
+ * This module is the single seam between the MCP tools and the network — the
7
+ * tools never touch `fetch` directly.
8
+ *
9
+ * While `config.mock` is true, each method returns deterministic fixture data
10
+ * via `FixtureStore` instead of issuing HTTP.
11
+ */
12
+ import type { ExtrovertConfig } from "./config.js";
13
+ import { NotFoundError } from "./fixtures.js";
14
+ import type { Attachment, AttachmentDownload, AttachmentInput, BatchUpdateResult, Category, ContactListDirection, ContactListEntry, ContactListKind, DeleteResult, Domain, DomainOffboard, EnrollmentResult, GraduationStatus, Inbox, Job, KeyTier, MailboxCredentials, Message, Page, Review, RiskDial, ReviewDecisionContext, ReviewerAction, ReviewerDecisionResult, ReviewEventsResult, ReviewFeedback, ReviewIntent, ReviewMode, ReviewState, CategoryPacingState, ReviewTurn, Rule, RuleAuditEntry, ProblemField, ReplyEmailResult, ScanBacklogStatus, SendEmailResult, SignUpResult, SubmitForReviewResult, SuppressionEntry, SuppressionPrecheck, ReputationRollup, ReputationFinding, ListDeliverabilityFindingsInput, Thread, ThreadDetail, VerifyResult, WaitForEmailResult, Webhook, WebhookEvent, WhoAmI } from "./types.js";
15
+ /** Normalized error surfaced from any client call. */
16
+ export declare class ExtrovertApiError extends Error {
17
+ readonly status: number;
18
+ readonly code?: string | undefined;
19
+ readonly details?: unknown | undefined;
20
+ /**
21
+ * The problem's machine-readable field hints (`problem.errors[]`), verbatim.
22
+ *
23
+ * These are NOT decoration. A 422 `intent_required` carries the exact JSON to
24
+ * add under `retry_with`, and a 409 carries `state` / `revision` / `version` /
25
+ * one `allowed_action` per legal verb — the facts that let an agent recover in
26
+ * one turn instead of guessing. They reach the model only because
27
+ * `toErrorResult` renders them: anything left in `structuredContent` is
28
+ * invisible to a text-only agent.
29
+ */
30
+ readonly problemErrors?: ProblemField[] | undefined;
31
+ constructor(message: string, status: number, code?: string | undefined, details?: unknown | undefined,
32
+ /**
33
+ * The problem's machine-readable field hints (`problem.errors[]`), verbatim.
34
+ *
35
+ * These are NOT decoration. A 422 `intent_required` carries the exact JSON to
36
+ * add under `retry_with`, and a 409 carries `state` / `revision` / `version` /
37
+ * one `allowed_action` per legal verb — the facts that let an agent recover in
38
+ * one turn instead of guessing. They reach the model only because
39
+ * `toErrorResult` renders them: anything left in `structuredContent` is
40
+ * invisible to a text-only agent.
41
+ */
42
+ problemErrors?: ProblemField[] | undefined);
43
+ }
44
+ export interface RedeemEnrollmentInput {
45
+ enrollment_token: string;
46
+ /** Idempotency handle (à la AgentMail `client_id`); rebinds the same agent. */
47
+ agent_handle?: string;
48
+ /**
49
+ * Optional client-supplied idempotency key sent as the `Idempotency-Key`
50
+ * header: a retry with the same key replays the original enrollment response.
51
+ */
52
+ client_id?: string;
53
+ }
54
+ /**
55
+ * A metadata patch on create/update. Each value is string | number | boolean to
56
+ * SET a key, or `null` to DELETE that key (merge-null-clear semantics). A
57
+ * top-level `null` on update clears ALL metadata (see {@link UpdateInboxInput}).
58
+ */
59
+ export type InboxMetadataPatch = Record<string, string | number | boolean | null>;
60
+ export interface CreateInboxInput {
61
+ username?: string;
62
+ domain?: string;
63
+ display_name?: string;
64
+ inbound_webhook_url?: string;
65
+ /**
66
+ * Optional arbitrary key-value metadata to store on the inbox (AgentMail
67
+ * parity). Values may be string, number, or boolean; a key with a `null` value
68
+ * is dropped. Caps: ≤256 keys, ≤256 chars per key, ≤256 chars per string value;
69
+ * nested objects/arrays are rejected. Echoed back (and replayed on idempotent
70
+ * retries) on the create response.
71
+ */
72
+ metadata?: InboxMetadataPatch;
73
+ /**
74
+ * Optional assertion that must match the key's bound project — NEVER a
75
+ * selector. A mismatch is rejected server-side; the inbox is always created in
76
+ * the key's stored project.
77
+ */
78
+ project_id?: string;
79
+ /**
80
+ * Optional client-supplied idempotency key sent as the `Idempotency-Key`
81
+ * header: re-creating with the same key returns the existing inbox rather than
82
+ * a duplicate (the same key with a different request is a 409).
83
+ */
84
+ client_id?: string;
85
+ }
86
+ export interface RegisterWebhookInput {
87
+ url: string;
88
+ events?: WebhookEvent[];
89
+ inbox?: string;
90
+ /**
91
+ * Optional client-supplied idempotency key sent as the `Idempotency-Key`
92
+ * header: a retry with the same key replays the original registration.
93
+ */
94
+ client_id?: string;
95
+ }
96
+ /** Mutable inbox settings for `PATCH /v1/inboxes/{inbox_id}`. Omitted fields are left unchanged. */
97
+ export interface UpdateInboxInput {
98
+ /** New sender display / "From" name. Empty string falls back to the local-part. */
99
+ display_name?: string;
100
+ /** Replace the inbound webhook target (empty string clears it). */
101
+ inbound_webhook_url?: string;
102
+ /**
103
+ * Set the effective rolling-24-hour recipient cap (integer 1–10,000).
104
+ * Requires the opt-in `mailbox:quota` scope.
105
+ */
106
+ daily_send_limit?: number;
107
+ /**
108
+ * Patch the inbox's arbitrary metadata (AgentMail parity) with a shallow merge:
109
+ * an object merges into the existing metadata; a key whose value is `null`
110
+ * deletes that key; a top-level `null` clears ALL metadata (the response then
111
+ * carries `{}`). Omit the field entirely to leave metadata unchanged. Values
112
+ * may be string, number, or boolean; nested objects/arrays are rejected; the
113
+ * same ≤256 key/length caps as create apply.
114
+ */
115
+ metadata?: InboxMetadataPatch | null;
116
+ /**
117
+ * Optional assertion that must match the key's bound project — NEVER a
118
+ * selector. A mismatch is rejected server-side.
119
+ */
120
+ project_id?: string;
121
+ }
122
+ export interface SendEmailInput {
123
+ inbox: string;
124
+ to: string[];
125
+ subject: string;
126
+ text: string;
127
+ html?: string;
128
+ cc?: string[];
129
+ bcc?: string[];
130
+ /** Override the Reply-To header. */
131
+ reply_to?: string;
132
+ /** Custom headers to attach (reserved/unsafe names are dropped server-side). */
133
+ headers?: Record<string, string>;
134
+ /** Files to attach (base64). */
135
+ attachments?: AttachmentInput[];
136
+ /** Stable retry key, sent as Idempotency-Key and never in the JSON body. */
137
+ client_id?: string;
138
+ }
139
+ export interface ReplyEmailInput {
140
+ inbox: string;
141
+ /** Exactly one of thread_id / message_id selects the parent. */
142
+ thread_id?: string;
143
+ message_id?: string;
144
+ text?: string;
145
+ html?: string;
146
+ cc?: string[];
147
+ bcc?: string[];
148
+ reply_to?: string;
149
+ headers?: Record<string, string>;
150
+ /** Reply to every thread recipient, not just the original sender. */
151
+ reply_all?: boolean;
152
+ /** Files to attach (base64). */
153
+ attachments?: AttachmentInput[];
154
+ /** Stable retry key, sent as Idempotency-Key and never in the JSON body. */
155
+ client_id?: string;
156
+ }
157
+ export interface ForwardEmailInput {
158
+ inbox: string;
159
+ message_id: string;
160
+ to: string[];
161
+ cc?: string[];
162
+ bcc?: string[];
163
+ text?: string;
164
+ /** Accepted for wire compatibility but ignored; the materialized forward is plain text. */
165
+ html?: string;
166
+ /** Stable retry key, sent as Idempotency-Key and never in the JSON body. */
167
+ client_id?: string;
168
+ }
169
+ /**
170
+ * Submit a forward for human review (Review Loop). A forward is an outbound
171
+ * message to arbitrary NEW recipients that quotes an entire received thread, so it
172
+ * is policy-enforced exactly like send and reply — otherwise it would be the
173
+ * documented bypass, and a worse one, because it exfiltrates a conversation.
174
+ *
175
+ * The subject and the quoted body are materialized server-side at SUBMIT time, so
176
+ * the human reviews the exact bytes that go out and an approved forward delivers
177
+ * the reviewer's edit rather than a body re-derived from the live parent.
178
+ */
179
+ export interface SubmitForwardForReviewInput {
180
+ inbox: string;
181
+ message_id: string;
182
+ to: string[];
183
+ cc?: string[];
184
+ bcc?: string[];
185
+ /** Optional note to prepend; the parent quote is appended server-side. */
186
+ text?: string;
187
+ /** Accepted for wire compatibility but ignored; the materialized forward is plain text. */
188
+ html?: string;
189
+ mode?: ReviewMode;
190
+ /** Required when the resolved mode is review (D3). */
191
+ intent?: ReviewIntent;
192
+ category_id?: string;
193
+ /** See SubmitForReviewInput.category_confidence. */
194
+ category_confidence?: number;
195
+ /** Stable retry key, sent as Idempotency-Key and never in the JSON body. */
196
+ client_id?: string;
197
+ }
198
+ /** Submit a new message for human review (Review Loop, spec §5.1). */
199
+ export interface SubmitForReviewInput {
200
+ inbox: string;
201
+ to: string[];
202
+ subject?: string;
203
+ text: string;
204
+ html?: string;
205
+ cc?: string[];
206
+ bcc?: string[];
207
+ reply_to?: string;
208
+ headers?: Record<string, string>;
209
+ /**
210
+ * Files to attach (base64). Attachments now survive submit -> review row ->
211
+ * approval dispatch, so the human reviews the message WITH its files and the
212
+ * recipient receives the same ones.
213
+ */
214
+ attachments?: AttachmentInput[];
215
+ /** "review" (default) routes to the human queue; "direct" requests an immediate send. */
216
+ mode?: ReviewMode;
217
+ /** Required when the resolved mode is review (D3). */
218
+ intent?: ReviewIntent;
219
+ /** Opaque category id (cat_…) matched from the registry; never a name. */
220
+ category_id?: string;
221
+ /**
222
+ * Agent-supplied confidence (0..1) in the category match. Feeds the submit-time
223
+ * min_confidence auto-send gate ONLY; the server never scores ($0 LLM). Below the
224
+ * effective threshold (or omitted when a threshold is set) the would-be auto-send
225
+ * routes to needs_review with gate_outcome held:low_confidence.
226
+ */
227
+ category_confidence?: number;
228
+ /** Stable retry key, sent as Idempotency-Key and never in the JSON body. */
229
+ client_id?: string;
230
+ }
231
+ /** Submit an in-thread reply for human review (Review Loop). */
232
+ export interface SubmitReplyForReviewInput {
233
+ inbox: string;
234
+ thread_id?: string;
235
+ message_id?: string;
236
+ text: string;
237
+ html?: string;
238
+ cc?: string[];
239
+ bcc?: string[];
240
+ reply_to?: string;
241
+ headers?: Record<string, string>;
242
+ /** Reply to every thread recipient, not just the original sender. */
243
+ reply_all?: boolean;
244
+ /** Files to attach (base64); they survive submit -> review row -> dispatch. */
245
+ attachments?: AttachmentInput[];
246
+ mode?: ReviewMode;
247
+ intent?: ReviewIntent;
248
+ category_id?: string;
249
+ /** See SubmitForReviewInput.category_confidence. */
250
+ category_confidence?: number;
251
+ /** Stable retry key, sent as Idempotency-Key and never in the JSON body. */
252
+ client_id?: string;
253
+ }
254
+ /** Filters for listing review requests (Review Loop, spec §5.2). */
255
+ export interface ListReviewsInput {
256
+ state?: ReviewState | ReviewState[];
257
+ category_id?: string;
258
+ inbox?: string;
259
+ limit?: number;
260
+ page?: string;
261
+ }
262
+ /** Post a chat turn on a review's thread (Review Loop M5, spec §5.2). */
263
+ export interface PostReviewChatInput {
264
+ /** Review id (rr_…). */
265
+ id: string;
266
+ /** The agent's question/comment for the human reviewer. */
267
+ text: string;
268
+ /** Optional idempotency key (sent as the `Idempotency-Key` header). */
269
+ client_id?: string;
270
+ }
271
+ /** Post a new agent draft under a parent_revision CAS (Review Loop M5, spec §5.2). */
272
+ export interface SubmitRevisionInput {
273
+ /** Review id (rr_…). */
274
+ id: string;
275
+ /** The revision the agent composed against (PRIMARY CAS; 409 STALE on mismatch). */
276
+ parent_revision: number;
277
+ /** Optional row-version CAS (defense in depth). */
278
+ version?: number;
279
+ subject?: string;
280
+ /** The canonical new plain-text body (matches `text` on send/reply/forward). */
281
+ text?: string;
282
+ /**
283
+ * DEPRECATED alias for {@link text}, accepted indefinitely so already-shipped
284
+ * callers keep working. Sending BOTH with different content is rejected 400
285
+ * `conflicting_alias` — the server never guesses which bytes you meant.
286
+ */
287
+ body?: string;
288
+ html?: string;
289
+ /**
290
+ * REPLACES the draft's attachments when present; omit to leave them untouched,
291
+ * pass `[]` to clear them. Without this a redraft after reviewer feedback could
292
+ * never restore a file the human reviewed the message WITH.
293
+ */
294
+ attachments?: AttachmentInput[];
295
+ /** When the agent built this draft (informational). */
296
+ built_at?: string;
297
+ /** Rule high-water this draft was composed against (born-stale basis). */
298
+ rules_version_seen?: number;
299
+ /** Stable retry key, sent as Idempotency-Key and never in the JSON body. */
300
+ client_id?: string;
301
+ }
302
+ /**
303
+ * The D19/§8 re-stamp-without-redraft escape valve ($0). The agent asserts it reviewed
304
+ * the draft against rules `against_version` and no change is needed; the server advances
305
+ * the draft's composed_* rules-versions WITHOUT a new draft.
306
+ */
307
+ export interface RestampReviewInput {
308
+ /** Review id (rr_…). */
309
+ id: string;
310
+ /** The category rules-version the agent reviewed against (≤ the current version). */
311
+ against_version: number;
312
+ /** Optional: re-stamp the house-style axis to this version (≤ the current version). */
313
+ house_style_version?: number;
314
+ /** Stable retry key, sent as Idempotency-Key and never in the JSON body. */
315
+ client_id?: string;
316
+ }
317
+ /**
318
+ * A reviewer decision (BYO review-agent plane; D5/§9). `action` is approve|edit|reject|
319
+ * escalate. `revision`/`version` are the optimistic CAS — a mismatch is a 409 STALE with
320
+ * NO mutation (the human always wins, D17). `subject`/`body` carry the edited content for
321
+ * the edit action; `feedback` is the reviewer's note.
322
+ */
323
+ export interface ReviewerDecideInput {
324
+ /** Review id (rr_…). */
325
+ id: string;
326
+ /** approve | edit | reject | escalate. */
327
+ action: ReviewerAction;
328
+ /** The revision you decided against (PRIMARY CAS; 409 STALE on mismatch). */
329
+ revision: number;
330
+ /** Optional row-version CAS (defense in depth). */
331
+ version?: number;
332
+ /** Edited subject (edit action). */
333
+ subject?: string;
334
+ /** Edited body text (edit action). */
335
+ body?: string;
336
+ /** Reviewer note (reject: the rule-birth signal; escalate: the human-facing reason). */
337
+ feedback?: string;
338
+ }
339
+ /** Filters for draining/waiting on review events (Review Loop, spec §5.9). */
340
+ export interface ListReviewEventsInput {
341
+ /** Restrict the drain to one review's events (rr_…). */
342
+ review_id?: string;
343
+ /** Max events to return in one drain. */
344
+ limit?: number;
345
+ }
346
+ /** Long-poll input: like {@link ListReviewEventsInput} plus a wait budget. */
347
+ export interface WaitForReviewEventInput extends ListReviewEventsInput {
348
+ /** Long-poll budget in seconds (default ~30, capped ~55). */
349
+ wait_seconds?: number;
350
+ }
351
+ /** One per-(agent, review) cursor advance for ack_review_event. */
352
+ export interface AckReviewEventEntry {
353
+ review_id: string;
354
+ through_seq: number;
355
+ }
356
+ /** Propose a new category (Review Loop registry, D9). */
357
+ export interface ProposeCategoryInput {
358
+ name: string;
359
+ description?: string;
360
+ /** Defaults to org_shared server-side. */
361
+ scope?: "org_shared" | "agent_private";
362
+ }
363
+ /** Rename / re-describe a category — metadata only (D10). */
364
+ export interface UpdateCategoryInput {
365
+ id: string;
366
+ name?: string;
367
+ description?: string;
368
+ }
369
+ /** Get the ordered writing-rule set (Review Loop, §7). */
370
+ export interface GetRulesInput {
371
+ /** Category id (cat_…). Empty returns ONLY the house-style/general layer. */
372
+ category_id?: string;
373
+ /** Narrow to one layer (general | category). Default returns both. */
374
+ scope?: "general" | "category";
375
+ }
376
+ /** Save / edit a writing rule (append-only by supersession, D11). */
377
+ export interface SaveRuleInput {
378
+ /** Defaults from category_id (general iff empty). */
379
+ scope?: "general" | "category";
380
+ /** Category id (cat_…); empty = house-style/general (D2). */
381
+ category_id?: string;
382
+ rule_text: string;
383
+ /** Defaults soft. hard = non-overridable. */
384
+ kind?: "soft" | "hard";
385
+ priority?: number;
386
+ source_review_id?: string;
387
+ source_turn_id?: string;
388
+ /** Set to EDIT the prior version (rule_…). */
389
+ supersedes_id?: string;
390
+ /** Set for a per-agent override; empty = all org agents. */
391
+ scope_agent_id?: string;
392
+ /** D8 retro-propagation HUMAN OPT-IN (default false): propagate a NEW category rule to pending siblings. */
393
+ propagate_to_pending?: boolean;
394
+ /** Override the propagate batch (0 = base 3, bounded by rework_batch_max). */
395
+ suggested_batch?: number;
396
+ }
397
+ /** Read the rule/category change audit log (D11). */
398
+ export interface GetRuleAuditInput {
399
+ entity_kind?: "rule" | "category";
400
+ entity_id?: string;
401
+ }
402
+ /** Ack input: advance per-review cursor(s) and/or mark broadcast nudges done. */
403
+ export interface AckReviewEventInput {
404
+ acks?: AckReviewEventEntry[];
405
+ broadcast_ids?: string[];
406
+ }
407
+ export interface AddContactListInput {
408
+ inbox: string;
409
+ kind: ContactListKind;
410
+ /** Defaults to "send" server-side. */
411
+ direction?: ContactListDirection;
412
+ /** A bare email address or a bare domain. */
413
+ pattern: string;
414
+ }
415
+ /** Filters for listing the caller's own org suppression rows (`GET /v1/suppressions`). */
416
+ export interface ListSuppressionsInput {
417
+ /** Narrow to one scope; the agent plane only ever returns `org` rows. */
418
+ scope?: "org" | "shared_domain" | "global";
419
+ /** Include revoked rows too (default: active rows only). */
420
+ include_revoked?: boolean;
421
+ limit?: number;
422
+ /** Opaque cursor from a previous page's next_cursor. */
423
+ cursor?: string;
424
+ }
425
+ /** Onboarding modes the agent-facing domains API accepts. */
426
+ export type DomainOnboardMode = "shared" | "ns_delegated" | "manual" | "purchased";
427
+ export interface OnboardDomainInput {
428
+ domain: string;
429
+ /**
430
+ * Onboarding path. Defaults to ns_delegated server-side when omitted. `mode:
431
+ * "purchased"` spends money at the registrar and therefore requires BOTH the
432
+ * `domain:manage` scope (the route gate) AND the explicit, default-off
433
+ * `domain:purchase` scope (it is additionally bounded by the org/project
434
+ * purchased-domain cap). `manual` and `ns_delegated` need `domain:manage` only.
435
+ */
436
+ mode?: DomainOnboardMode;
437
+ /** A-record IP served at a delegated zone's apex (ns_delegated only). */
438
+ mail_host_ip?: string;
439
+ /**
440
+ * Domain visibility. `org` (default) makes it usable by every project in the
441
+ * org; `project` binds it to the key's OWN bound project (never client-selected)
442
+ * so it is only visible/mintable from that project. A legacy/unscoped key falls
443
+ * back to `org`.
444
+ */
445
+ scope?: "org" | "project";
446
+ /**
447
+ * Optional assertion that must match the key's bound project — NEVER a
448
+ * selector. A mismatch is rejected server-side; the binding is always derived
449
+ * from the key.
450
+ */
451
+ project_id?: string;
452
+ }
453
+ export interface WaitForEmailInput {
454
+ inbox: string;
455
+ from?: string;
456
+ subject?: string;
457
+ /** Case-sensitive Go RE2 expression over subject+body (maps to the API `match` field); use a leading `(?i)` for case-insensitive matching. */
458
+ regex?: string;
459
+ /** Prefer an extracted link containing this substring. */
460
+ link_hint?: string;
461
+ /** Only match arrivals after the wait begins (default true). */
462
+ since_now?: boolean;
463
+ timeout_ms: number;
464
+ }
465
+ export declare class ExtrovertClient {
466
+ private readonly config;
467
+ private readonly store?;
468
+ private apiKey;
469
+ constructor(config: ExtrovertConfig);
470
+ get isMock(): boolean;
471
+ redeemEnrollment(input: RedeemEnrollmentInput): Promise<EnrollmentResult>;
472
+ /** Grab a free account: `POST /v1/agent/sign-up` (unauthenticated). */
473
+ signUp(input: {
474
+ human_email: string;
475
+ username?: string;
476
+ }): Promise<SignUpResult>;
477
+ /** Confirm the signup OTP and elevate scope: `POST /v1/agent/verify`. */
478
+ verify(input: {
479
+ otp: string;
480
+ }): Promise<VerifyResult>;
481
+ /** Introspect the principal behind the current key: `GET /v1/auth/me`. */
482
+ whoami(): Promise<WhoAmI>;
483
+ createInbox(input: CreateInboxInput): Promise<Inbox>;
484
+ /**
485
+ * List the agent's inboxes (redesign §4.1 bare-vs-wildcard semantics).
486
+ *
487
+ * Scope is in the KEY. By tier:
488
+ * - project/inbox key → that project's inboxes. Addressed via the canonical
489
+ * project-prefixed envelope `GET /v1/projects/{project_id}/inboxes` (the §5.2
490
+ * `{object:"list", data, has_more, next_cursor}` shape) when a project is
491
+ * resolved; otherwise the bare `/v1/inboxes` curl-sugar form (which resolves
492
+ * to the key's default project and returns the legacy `{inboxes, next_page}`).
493
+ * - org key → MUST pick a breadth: pass `project` (a concrete id) or
494
+ * `wildcard:true` (`/v1/projects/-/inboxes`, the org subtree). A bare org-key
495
+ * list is a 400 `breadth_required` (mirrors the server choke-point) — we fail
496
+ * fast client-side with the same code so the agent sees the next call to make.
497
+ *
498
+ * Either wire shape is normalized into the internal {@link Page}.
499
+ */
500
+ listInboxes(opts?: {
501
+ limit?: number;
502
+ project?: string;
503
+ wildcard?: boolean;
504
+ cursor?: string;
505
+ } | number): Promise<Page<Inbox>>;
506
+ /** The ceiling tier encoded in the current session's agent key (redesign §3.1). */
507
+ keyTier(): KeyTier;
508
+ getInbox(idOrAddress: string): Promise<Inbox>;
509
+ /**
510
+ * Update an inbox's settings in place: `PATCH /v1/inboxes/{inbox_id}` with
511
+ * `{display_name?, webhook_url?, daily_send_limit?, metadata?, project_id?}`. The agent-facing
512
+ * `inbound_webhook_url` maps to the API's `webhook_url`. `metadata` is a shallow
513
+ * merge: omit it to leave metadata unchanged; an object merges (a `null` value
514
+ * deletes that key); a top-level `null` clears ALL metadata. Owner-scoped
515
+ * server-side. Changing `daily_send_limit` requires the opt-in `mailbox:quota`
516
+ * scope. Returns the updated inbox with the effective enforced cap.
517
+ */
518
+ updateInbox(idOrAddress: string, input: UpdateInboxInput): Promise<Inbox>;
519
+ getCredentials(idOrAddress: string): Promise<MailboxCredentials>;
520
+ /**
521
+ * Permanently delete an inbox and its messages/sender identity. Requires
522
+ * `mailbox:delete`; this cannot be undone.
523
+ */
524
+ deleteInbox(idOrAddress: string): Promise<{
525
+ id: string;
526
+ deleted: true;
527
+ }>;
528
+ /**
529
+ * Send a new message WITHOUT the review overload.
530
+ *
531
+ * The return type is a union because the endpoint has two outcomes and the
532
+ * account's policy — not the caller — picks between them. This used to be typed
533
+ * `Promise<Message>` and rendered as a message header, which was garbage against
534
+ * every real response: the server has never returned a Message here. It returns
535
+ * `{status:"sent", message_id, review_id}` on the policy's direct path, and the
536
+ * §5.1 `{kind:"queued_for_review", review}` envelope (HTTP 202) when the policy
537
+ * queues it — which, under the `require_review` default, is the normal outcome.
538
+ *
539
+ * A send with no `intent` under `require_review` never reaches either arm: it is
540
+ * refused with 422 `intent_required` and NOTHING is sent or queued.
541
+ */
542
+ sendEmail(input: SendEmailInput): Promise<SendEmailResult>;
543
+ /**
544
+ * Thread-aware reply. Canonical contract:
545
+ * `POST /v1/inboxes/{inbox_id}/reply` with `{thread_id|message_id, text, html?, cc?,
546
+ * bcc?, reply_to?, reply_all?}`. The server derives To/Subject/In-Reply-To/
547
+ * References and returns `{message_id, thread_id, review_id}`. No `to` is sent.
548
+ *
549
+ * Like {@link sendEmail} the outcome is policy-decided: a bare reply under
550
+ * `require_review` is QUEUED (202 `{kind:"queued_for_review"}`), not sent, and a
551
+ * bare reply with no intent is refused 422 `intent_required`.
552
+ */
553
+ replyEmail(input: ReplyEmailInput): Promise<ReplyEmailResult>;
554
+ /**
555
+ * Forward an existing message to new recipients, preserving the original.
556
+ * `POST /v1/inboxes/{inbox_id}/messages/{id}/forward` `{to[], cc?, bcc?, text?, html?}`.
557
+ * `html` is accepted but ignored: the server materializes one plain-text body
558
+ * containing both the note and quoted parent, so HTML clients cannot hide the quote.
559
+ *
560
+ * Policy-decided like send and reply: a bare forward under `require_review` is
561
+ * QUEUED, and one with no intent is refused 422 `intent_required`.
562
+ */
563
+ forwardEmail(input: ForwardEmailInput): Promise<ReplyEmailResult>;
564
+ /**
565
+ * Submit a forward for human review — the SAME endpoint as {@link forwardEmail}
566
+ * with mode/intent/category_id attached, mirroring how send and reply overload.
567
+ * Returns the discriminated §5.1 envelope (queued OR sent).
568
+ */
569
+ submitForwardForReview(input: SubmitForwardForReviewInput): Promise<SubmitForReviewResult>;
570
+ /**
571
+ * Submit a new message for human review (`POST /v1/inboxes/{inbox_id}/send` with
572
+ * mode/intent/category_id). The server routes per the account/inbox review
573
+ * policy and returns either `{kind:"queued_for_review"}` (202) or
574
+ * `{kind:"sent"}` (200, policy-permitted direct/graduated path).
575
+ */
576
+ submitForReview(input: SubmitForReviewInput): Promise<SubmitForReviewResult>;
577
+ /**
578
+ * Submit an in-thread reply for human review (`POST /v1/inboxes/{inbox_id}/reply`
579
+ * with mode/intent/category_id). Same routing/return contract as submitForReview.
580
+ */
581
+ submitReplyForReview(input: SubmitReplyForReviewInput): Promise<SubmitForReviewResult>;
582
+ /** List review requests (`GET /v1/reviews`). Customer-scoped; agent monitors its submissions. */
583
+ listReviews(input?: ListReviewsInput): Promise<Page<Review>>;
584
+ /** Get one review request (`GET /v1/reviews/{id}`) — current draft + intent + state. */
585
+ getReview(id: string): Promise<Review>;
586
+ /** Get a review's append-only thread turns (`GET /v1/reviews/{id}/turns`). */
587
+ getReviewTurns(id: string): Promise<Page<ReviewTurn>>;
588
+ /**
589
+ * Get the human's assembled feedback for a review (`GET /v1/reviews/{id}/feedback`):
590
+ * the unified + structured diff, the human comments, the decision, and the rules born
591
+ * from this review (rule_ ids). Read-only; $0 LLM (pure assembly).
592
+ */
593
+ getReviewFeedback(id: string): Promise<ReviewFeedback>;
594
+ /**
595
+ * Post a chat turn on a review's thread (`POST /v1/reviews/{id}/chat`): append an
596
+ * agent_question turn, flip in_review -> chatting on the first turn, enqueue a
597
+ * feedback_added nudge to the human reviewer + emit review.chat. Idempotent on the
598
+ * client-supplied key. $0 LLM — YOU compose the question.
599
+ */
600
+ postReviewChat(input: PostReviewChatInput): Promise<Review>;
601
+ /**
602
+ * Post a new agent draft under a parent_revision CAS (`POST /v1/reviews/{id}/
603
+ * revision`). parent_revision must equal the draft's current revision, else 409
604
+ * STALE with NO mutation (D17). On a clean CAS the draft is re-rendered in place
605
+ * (revision++), returned to needs_review, and the reviewer is nudged. $0 LLM — YOU
606
+ * compose the redraft.
607
+ */
608
+ submitRevision(input: SubmitRevisionInput): Promise<Review>;
609
+ /**
610
+ * Withdraw a pending review (`POST /v1/reviews/{id}/cancel`): the composing agent
611
+ * cancels its own review to the terminal cancelled state. A foreign id / another
612
+ * agent's draft 404s; a terminal review 409s.
613
+ */
614
+ cancelReview(input: {
615
+ id: string;
616
+ client_id?: string;
617
+ }): Promise<Review>;
618
+ /**
619
+ * Re-stamp a draft's rules-version WITHOUT redrafting (`POST /v1/reviews/{id}/
620
+ * restamp`; D19/§8 $0 escape valve). Assert "reviewed against vX, no change needed"
621
+ * and the server advances the draft's composed_* versions with no new draft, no
622
+ * revision bump, no nudge. against_version above the category's current rules-version
623
+ * is 400; a terminal/sent draft 409s.
624
+ */
625
+ restampReview(input: RestampReviewInput): Promise<Review>;
626
+ /**
627
+ * Get the REVIEWER's decision context for a review (`GET /v1/reviews/{id}/
628
+ * decision-context`; BYO review-agent plane, D5/§9). The reviewer's read-only view:
629
+ * the intent + current draft + thread + the two-circuit-breaker budget (hop_count vs
630
+ * max_hops, the hard review_deadline). Requires review:act + a matching active link;
631
+ * a cross-tenant id is 404, a non-reviewer is 403. `force_to_human` is true when a
632
+ * reject would be FORCED to the human regardless of intent (D17).
633
+ */
634
+ getReviewDecisionContext(id: string): Promise<ReviewDecisionContext>;
635
+ /**
636
+ * Submit a reviewer decision (`POST /v1/reviews/{id}/decision`; reviewer_decide,
637
+ * D5/§9). approve/edit → the PLATFORM ACS-sends with the COMPOSER's creds (the
638
+ * reviewer NEVER holds mailbox:send — the credential boundary); reject → back to the
639
+ * composer (needs_review, hop_count++); escalate → the human queue. revision/version
640
+ * are the CAS (409 STALE on mismatch, NO mutation — the human always wins, D17). The
641
+ * two circuit breakers (hop_count ≥ max_hops, or the hard review_deadline) FORCE a
642
+ * reject to the human regardless of intent — `forced_by_breaker` names it. $0 LLM —
643
+ * you judged; we route, send, and enforce the breakers.
644
+ */
645
+ reviewerDecide(input: ReviewerDecideInput): Promise<ReviewerDecisionResult>;
646
+ /**
647
+ * Drain the next un-acked review events (`GET /v1/reviews/events`). Non-blocking;
648
+ * returns the FIFO-ordered nudges + per-review cursors. Side-effect free.
649
+ */
650
+ listReviewEvents(input?: ListReviewEventsInput): Promise<ReviewEventsResult>;
651
+ /**
652
+ * Long-poll for a review event (`GET /v1/reviews/events/wait`). Blocks ~25–55s
653
+ * until a nudge is available OR the deadline, then returns like
654
+ * {@link listReviewEvents} (empty on timeout).
655
+ */
656
+ waitForReviewEvent(input?: WaitForReviewEventInput): Promise<ReviewEventsResult>;
657
+ /**
658
+ * Ack review events (`POST /v1/reviews/events/ack`): advance per-(agent, review)
659
+ * cursor(s) and/or mark broadcast nudges done. Idempotent + monotonic.
660
+ */
661
+ ackReviewEvent(input: AckReviewEventInput): Promise<{
662
+ cursors: ReviewEventsResult["cursors"];
663
+ }>;
664
+ /**
665
+ * Browse the category registry (`GET /v1/categories?match=`). Returns id + name +
666
+ * description + scope + state for fuzzy matching. `match` is a pure lexical filter
667
+ * (NO LLM on our side) — the agent does the semantic match. Customer-scoped.
668
+ */
669
+ listCategories(match?: string): Promise<Page<Category>>;
670
+ /** Get one category (`GET /v1/categories/{id}`). A foreign id is 404. */
671
+ getCategory(id: string): Promise<Category>;
672
+ /**
673
+ * Propose a new category (`POST /v1/categories`). It stands immediately
674
+ * (author_kind=agent) and writes a create audit/undo row. Match the registry
675
+ * first so you do not duplicate an existing bucket.
676
+ */
677
+ proposeCategory(input: ProposeCategoryInput): Promise<Category>;
678
+ /**
679
+ * Rename / re-describe a category (`PUT /v1/categories/{id}`) — metadata ONLY
680
+ * (D10). Renaming never breaks a reference; a rename/redescribe undo row is
681
+ * written. Any agent in the customer may edit (the shared-registry exception).
682
+ */
683
+ updateCategory(input: UpdateCategoryInput): Promise<Category>;
684
+ /**
685
+ * Read the effective risk dial (`GET /v1/risk-dial`): the account default + every
686
+ * category's overrides (each with its resolved effective value; null override =
687
+ * inherit). Read-only — agents read but NEVER flip the dial (setting it is a human
688
+ * console action; D16).
689
+ */
690
+ getRiskDial(): Promise<RiskDial>;
691
+ /**
692
+ * Read a category's graduation gate status (`GET /v1/categories/{id}/graduation-
693
+ * status`): the gates passed / still needed toward the next rung (approvals N/needed,
694
+ * age, maturity gate, drift vs K, can_graduate). Read-only.
695
+ */
696
+ getGraduationStatus(categoryId: string): Promise<GraduationStatus>;
697
+ /**
698
+ * Propose graduating a category (`POST /v1/categories/{id}/graduation-request`).
699
+ * RECORDS the request (durable evidence) and returns the current gate status; it
700
+ * does NOT change the category state — flipping the bit is a human (console) action
701
+ * (D16/D6). A never_graduate category stays locked.
702
+ */
703
+ proposeGraduation(categoryId: string, evidence?: Record<string, unknown>): Promise<GraduationStatus>;
704
+ /**
705
+ * Read the D19/§8 backlog-reconciliation status (`GET /v1/categories/{id}/
706
+ * backlog-status`): how many QUEUED drafts are stale vs current-enough against the
707
+ * current rules-version (a pure $0-LLM integer compare). Read-only — agents READ the
708
+ * picture; the human (console scan-backlog) / hooks TRIGGER the actual sweep.
709
+ */
710
+ getBacklogStatus(categoryId: string): Promise<ScanBacklogStatus>;
711
+ /**
712
+ * Read the demand-driven pacing state (`GET /v1/categories/{id}/pacing-state`;
713
+ * M7 Slice B/§8): the human review cursor, the effective window/ceiling/interval, and
714
+ * each queued draft's in-window/redrafting/behind-cursor classification. Read-only;
715
+ * the cursor advances from the human's console approve/reject/edit actions.
716
+ */
717
+ getPacingState(categoryId: string): Promise<CategoryPacingState>;
718
+ /**
719
+ * Get the ORDERED active rule set (`GET /v1/rules?category_id=&scope=`). The §7
720
+ * precedence ladder is applied SERVER-SIDE (NO LLM): hard>soft; per-agent>category>
721
+ * general; human>agent; newest rev/created_at; higher priority; plus a soft cap.
722
+ * Includes the general/house-style layer (D2) IN ADDITION to the category's rules.
723
+ */
724
+ getRules(input?: GetRulesInput): Promise<Page<Rule>>;
725
+ /**
726
+ * Save / edit a writing rule (`PUT /v1/rules`) — append-only by supersession (D11).
727
+ * scope='general' iff category_id is empty (house-style, D2). With supersedes_id
728
+ * the write is an EDIT (rev+1, same lineage). Writes a create/supersede audit row.
729
+ */
730
+ saveRule(input: SaveRuleInput): Promise<Rule>;
731
+ /**
732
+ * Promote a rule between the category and general/house-style layers
733
+ * (`POST /v1/rules/{id}/promote`) via a supersession.
734
+ */
735
+ promoteRule(id: string, toScope: "general" | "category"): Promise<Rule>;
736
+ /** Retire a rule (`POST /v1/rules/{id}/retire`) — soft delete; history survives. */
737
+ retireRule(id: string): Promise<Rule>;
738
+ /**
739
+ * Read the rule/category change audit log (`GET /v1/rules/audit`) — read-only,
740
+ * agent-visible (the audit log is the shared safety net, D11).
741
+ */
742
+ getRuleAudit(input?: GetRuleAuditInput): Promise<Page<RuleAuditEntry>>;
743
+ /**
744
+ * Undo a rule change (`POST /v1/rules/audit/{udo_id}/undo`) — restore the prior
745
+ * version as a forward 'restore' supersession (D11; agents may undo too).
746
+ * Idempotent: a re-undo of an already-undone row is a clean 409.
747
+ */
748
+ undoRuleChange(udoId: string): Promise<Rule>;
749
+ /**
750
+ * List messages in an inbox, newest-first. Canonical contract:
751
+ * `GET /v1/inboxes/{inbox_id}/messages` with optional exact-field filters
752
+ * (from/to/subject), an `unread=true` filter (native IMAP \Seen), and
753
+ * limit/offset paging. Returns the canonical `Page<Message>` ({items,total}).
754
+ */
755
+ listMessages(input: {
756
+ inbox: string;
757
+ limit?: number;
758
+ offset?: number;
759
+ unread_only?: boolean;
760
+ from?: string;
761
+ to?: string;
762
+ subject?: string;
763
+ }): Promise<Page<Message>>;
764
+ /** Fetch a single message by its opaque id (`GET /v1/messages/{id}`). */
765
+ getMessage(id: string): Promise<Message>;
766
+ /**
767
+ * List a message's attachment metadata
768
+ * (`GET /v1/inboxes/{inbox_id}/messages/{id}/attachments` → `Page<Attachment>`).
769
+ */
770
+ listAttachments(input: {
771
+ inbox: string;
772
+ message_id: string;
773
+ }): Promise<Page<Attachment>>;
774
+ /**
775
+ * Download one attachment's bytes (base64) + metadata
776
+ * (`GET /v1/inboxes/{inbox_id}/messages/{id}/attachments/{attId}` → raw bytes with
777
+ * Content-Type + Content-Disposition). The "easy attachment fetch."
778
+ */
779
+ getAttachment(input: {
780
+ inbox: string;
781
+ message_id: string;
782
+ attachment_id: string;
783
+ }): Promise<AttachmentDownload>;
784
+ /**
785
+ * Mark a message read/unread via the native IMAP \Seen flag
786
+ * (`PATCH /v1/inboxes/{inbox_id}/messages/{id}` {read}). The inbox is resolved
787
+ * from the message id. Returns the updated message.
788
+ */
789
+ markRead(input: {
790
+ inbox: string;
791
+ id: string;
792
+ read: boolean;
793
+ }): Promise<Message>;
794
+ listThreads(input: {
795
+ inbox: string;
796
+ limit?: number;
797
+ }): Promise<Page<Thread>>;
798
+ /**
799
+ * Fetch one thread (with its messages, oldest-first) by stable id, scoped to
800
+ * the owning inbox: `GET /v1/inboxes/{inbox_id}/threads/{id}`.
801
+ */
802
+ getThread(input: {
803
+ inbox: string;
804
+ thread_id: string;
805
+ }): Promise<ThreadDetail>;
806
+ /**
807
+ * Delete a message: move it to Trash, or permanently expunge it when
808
+ * `expunge` is set (`DELETE /v1/inboxes/{inbox_id}/messages/{id}?expunge=`). A
809
+ * message already in Trash is always expunged.
810
+ */
811
+ deleteMessage(input: {
812
+ inbox: string;
813
+ id: string;
814
+ expunge?: boolean;
815
+ }): Promise<DeleteResult>;
816
+ /**
817
+ * Delete an entire thread (every message): move to Trash, or expunge when
818
+ * `expunge` is set (`DELETE /v1/inboxes/{inbox_id}/threads/{id}?expunge=`).
819
+ */
820
+ deleteThread(input: {
821
+ inbox: string;
822
+ thread_id: string;
823
+ expunge?: boolean;
824
+ }): Promise<DeleteResult>;
825
+ /**
826
+ * Batch mark read/unread and/or move folder for a list of message ids in one
827
+ * inbox (`PATCH /v1/inboxes/{inbox_id}/messages/batch`). At least one of
828
+ * `read` / `folder` must be set; returns the per-id `{updated, failed}` split.
829
+ */
830
+ batchUpdateMessages(input: {
831
+ inbox: string;
832
+ ids: string[];
833
+ read?: boolean;
834
+ folder?: string;
835
+ }): Promise<BatchUpdateResult>;
836
+ /**
837
+ * Full-text search backed by IMAP SEARCH, scoped to one inbox
838
+ * (`GET /v1/inboxes/{inbox_id}/messages/search?q=...`). When `inbox` is omitted,
839
+ * iterate every inbox the agent owns and merge the results (newest-first).
840
+ */
841
+ search(input: {
842
+ query: string;
843
+ inbox?: string;
844
+ limit?: number;
845
+ }): Promise<Page<Message>>;
846
+ waitForEmail(input: WaitForEmailInput): Promise<WaitForEmailResult>;
847
+ /**
848
+ * Register an inbound webhook (`POST /v1/webhooks`). The signing `secret` is
849
+ * returned ONCE here; deliveries are HMAC-signed in the canonical
850
+ * `X-Extrovert-Signature: t=<unix>,v1=<hex>` format.
851
+ */
852
+ registerWebhook(input: RegisterWebhookInput): Promise<Webhook>;
853
+ /** List registered webhooks (`GET /v1/webhooks`); secrets are redacted. */
854
+ listWebhooks(): Promise<Page<Webhook>>;
855
+ /** Get one webhook by id (`GET /v1/webhooks/{id}`); secret redacted. */
856
+ getWebhook(id: string): Promise<Webhook>;
857
+ /**
858
+ * Update a webhook in place (`PATCH /v1/webhooks/{id}`). Every field is
859
+ * optional; an omitted field is left unchanged (PATCH semantics). The signing
860
+ * secret is immutable and stays redacted in the response.
861
+ */
862
+ updateWebhook(id: string, input: {
863
+ url?: string;
864
+ events?: WebhookEvent[];
865
+ inbox?: string;
866
+ active?: boolean;
867
+ }): Promise<Webhook>;
868
+ /** Delete a webhook by id (`DELETE /v1/webhooks/{id}`). */
869
+ deleteWebhook(id: string): Promise<{
870
+ id: string;
871
+ deleted: true;
872
+ }>;
873
+ /**
874
+ * Add an allow/block entry to an inbox's contact lists
875
+ * (`POST /v1/inboxes/{inbox_id}/lists`). A `block` entry rejects a matching
876
+ * recipient on send; when an `allow` entry exists, sends from this inbox are
877
+ * restricted to recipients that match one (allowlist mode).
878
+ */
879
+ addContactListEntry(input: AddContactListInput): Promise<ContactListEntry>;
880
+ /** List the contact-list entries governing an inbox (`GET /v1/inboxes/{inbox_id}/lists`). */
881
+ listContactListEntries(inbox: string): Promise<Page<ContactListEntry>>;
882
+ /** Delete a contact-list entry by id (`DELETE /v1/inboxes/{inbox_id}/lists/{id}`). */
883
+ deleteContactListEntry(inbox: string, id: string): Promise<{
884
+ id: string;
885
+ deleted: true;
886
+ }>;
887
+ /** List the customer's onboarded domains (`GET /v1/domains`). Canonical page envelope. */
888
+ listDomains(): Promise<Page<Domain>>;
889
+ /** Get one domain's detail + verification status + the DNS records to set (`GET /v1/domains/{domain}`). */
890
+ getDomain(domain: string): Promise<Domain>;
891
+ /** Onboard/add a domain for the customer (`POST /v1/domains`). */
892
+ onboardDomain(input: OnboardDomainInput): Promise<Domain>;
893
+ /** Trigger/refresh verification for a domain (`POST /v1/domains/{domain}/verify`). */
894
+ verifyDomain(domain: string): Promise<Domain>;
895
+ /**
896
+ * Offboard (remove) a domain from the customer (`DELETE /v1/domains/{domain}`).
897
+ * The API accepts the request (HTTP 202) and runs the teardown — reaping the
898
+ * outbound provider sender identities + routing rows, then scrubbing the DNS
899
+ * zone/records and the domain row — as an async job. This returns the job id and
900
+ * a poll URL (`status_url`, i.e. `GET /v1/jobs/{job_id}`); offboarding is
901
+ * ACCEPTED, not yet complete. Poll with `getJob(job_id)` (the `get_job` tool)
902
+ * until the status is terminal.
903
+ */
904
+ offboardDomain(domain: string): Promise<DomainOffboard>;
905
+ /**
906
+ * Poll the status of an async job (`GET /v1/jobs/{job_id}`) — currently only
907
+ * the domain-offboard teardown enqueues one. `status` is terminal on
908
+ * succeeded/failed/cancelled; keep polling otherwise.
909
+ */
910
+ getJob(jobId: string): Promise<Job>;
911
+ /**
912
+ * Pre-check whether the caller's org suppresses a recipient
913
+ * (`GET /v1/suppressions?recipient=…`). Returns `{recipient, suppressed, rows}`
914
+ * over the caller's OWN active org rows — never a global/shared/cross-tenant
915
+ * opt-out. Use it BEFORE composing to skip a would-be-rejected recipient.
916
+ */
917
+ precheckSuppression(recipient: string): Promise<SuppressionPrecheck>;
918
+ /**
919
+ * List the caller's own org suppression rows (`GET /v1/suppressions`). No
920
+ * `recipient` is sent here — that param switches the server to the pre-check.
921
+ */
922
+ listSuppressions(input?: ListSuppressionsInput): Promise<Page<SuppressionEntry>>;
923
+ /**
924
+ * Revoke one org-scope suppression row (`POST /v1/suppressions/{id}/revoke`),
925
+ * re-enabling sending to that recipient. A `reason` is REQUIRED (empty is a 400)
926
+ * and is audit-logged. A foreign/global/shared id is an indistinguishable 404.
927
+ */
928
+ revokeSuppression(id: string, reason: string): Promise<SuppressionEntry>;
929
+ /**
930
+ * The caller's org deliverability rollup (`GET /v1/reputation`): derived status
931
+ * badge, per-provider/tenant sending status, latest Sends/Bounces/Complaints
932
+ * window, and open-finding count. Read-only; strictly org-scoped. Advisor
933
+ * findings show `unavailable_vdm_disabled` when VDM is off.
934
+ */
935
+ getReputation(): Promise<ReputationRollup>;
936
+ /**
937
+ * List the caller's org deliverability findings (`GET /v1/reputation/findings`),
938
+ * newest-first, with optional status/severity/domain/sender filters. Read-only.
939
+ */
940
+ listDeliverabilityFindings(input?: ListDeliverabilityFindingsInput): Promise<Page<ReputationFinding>>;
941
+ private get;
942
+ /**
943
+ * Fetch a binary endpoint (the attachment download) and return its bytes as
944
+ * base64 plus the filename + content type pulled from the response headers.
945
+ * Bypasses the JSON `request` path so arbitrary bytes survive intact.
946
+ */
947
+ private getBinary;
948
+ private post;
949
+ private del;
950
+ private patch;
951
+ private put;
952
+ private request;
953
+ private setSessionKey;
954
+ }
955
+ export { NotFoundError };
956
+ //# sourceMappingURL=client.d.ts.map