@myapihq/sdk 2.4.0 → 2.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/crm.ts DELETED
@@ -1,239 +0,0 @@
1
- import { request, requestPage } from './client';
2
- import { CRM_BASE as BASE_URL } from './config';
3
- import type { Exposes } from './exposes';
4
-
5
- export const EXPOSES: Exposes = [
6
- 'POST /crm/orgs/{org_id}/contacts',
7
- 'POST /crm/orgs/{org_id}/contacts/promote',
8
- 'POST /crm/orgs/{org_id}/contacts/search',
9
- 'GET /crm/orgs/{org_id}/contacts/{id}',
10
- 'PATCH /crm/orgs/{org_id}/contacts/{id}',
11
- 'DELETE /crm/orgs/{org_id}/contacts/{id}',
12
- 'GET /crm/orgs/{org_id}/contacts/{id}/events',
13
- 'POST /crm/orgs/{org_id}/companies',
14
- 'POST /crm/orgs/{org_id}/companies/promote',
15
- 'POST /crm/orgs/{org_id}/companies/search',
16
- 'GET /crm/orgs/{org_id}/companies/{id}',
17
- 'PATCH /crm/orgs/{org_id}/companies/{id}',
18
- 'DELETE /crm/orgs/{org_id}/companies/{id}',
19
- ];
20
-
21
- // Shared enums — fixed sets. Lifecycle stage is the same enum for contacts
22
- // and companies (Simon's call: keep it simple, easier for agents).
23
- export type LifecycleStage =
24
- | 'cold'
25
- | 'warm'
26
- | 'qualified'
27
- | 'customer'
28
- | 'churned';
29
-
30
- export type ContactSource =
31
- | 'goldfox'
32
- | 'email'
33
- | 'pixel'
34
- | 'webhook'
35
- | 'manual';
36
-
37
- // Reserved set of event kinds. Agents cannot write these directly — they
38
- // are emitted by the platform when state changes (stage_changed) or the
39
- // underlying service completes (email_sent, webhook_received, etc.).
40
- export type EventKind =
41
- | 'created'
42
- | 'promoted'
43
- | 'stage_changed'
44
- | 'email_sent'
45
- | 'email_opened'
46
- | 'email_clicked'
47
- | 'email_replied'
48
- | 'pixel_visit'
49
- | 'webhook_received'
50
- | 'payment';
51
-
52
- // Goldfox enrichment is a live join — the response embeds the current
53
- // Goldfox row when goldfox_person_id is set. v1: returns null until the
54
- // BQ get-by-id helper lands backend-side. The field shape will become
55
- // the existing Person from people.ts once enabled.
56
- export interface Contact {
57
- id: string;
58
- org_id: string;
59
- email: string | null;
60
- first_name: string | null;
61
- last_name: string | null;
62
- company_id: string | null;
63
- lifecycle_stage: LifecycleStage;
64
- custom: Record<string, unknown>;
65
- source: ContactSource;
66
- goldfox_person_id: string | null;
67
- goldfox_person?: unknown | null; // deferred until BQ helper lands
68
- created_at: string;
69
- updated_at: string;
70
- last_engagement_at?: string | null; // only set after engagement events (email/pixel/webhook)
71
- deleted_at?: string | null; // soft-delete marker
72
- }
73
-
74
- export interface Company {
75
- id: string;
76
- org_id: string;
77
- domain: string | null;
78
- name: string | null;
79
- lifecycle_stage: LifecycleStage;
80
- custom: Record<string, unknown>;
81
- source: ContactSource;
82
- goldfox_company_id: string | null; // for Goldfox-sourced rows this equals the domain
83
- goldfox_company?: unknown | null;
84
- created_at: string;
85
- updated_at: string;
86
- deleted_at?: string | null;
87
- }
88
-
89
- export interface ContactEvent {
90
- id: string;
91
- contact_id: string;
92
- kind: EventKind;
93
- payload: Record<string, unknown>;
94
- at: string;
95
- }
96
-
97
- // ── Inputs ────────────────────────────────────────────────────────────────
98
-
99
- export interface CreateContactInput {
100
- email?: string | null;
101
- first_name?: string;
102
- last_name?: string;
103
- company_id?: string; // override the auto-link by domain
104
- lifecycle_stage?: LifecycleStage;
105
- custom?: Record<string, unknown>;
106
- source?: ContactSource; // defaults to 'manual' server-side
107
- }
108
-
109
- export interface UpdateContactInput {
110
- first_name?: string | null;
111
- last_name?: string | null;
112
- company_id?: string | null;
113
- lifecycle_stage?: LifecycleStage;
114
- custom?: Record<string, unknown>;
115
- deleted_at?: null; // pass explicit null to restore a soft-deleted contact
116
- }
117
-
118
- export interface ContactSearchFilter {
119
- lifecycle_stage?: LifecycleStage[];
120
- source?: ContactSource[];
121
- email?: string;
122
- company_id?: string;
123
- min_last_engagement_days?: number; // engaged within N days
124
- max_last_engagement_days?: number; // last engaged > N days ago — re-engagement filter
125
- include_deleted?: boolean; // default false
126
- limit?: number;
127
- offset?: number;
128
- }
129
-
130
- export interface ContactSearchResult {
131
- contacts: Contact[];
132
- total: number;
133
- }
134
-
135
- export interface CreateCompanyInput {
136
- domain?: string | null;
137
- name?: string;
138
- lifecycle_stage?: LifecycleStage;
139
- custom?: Record<string, unknown>;
140
- source?: ContactSource;
141
- }
142
-
143
- export interface UpdateCompanyInput {
144
- name?: string | null;
145
- lifecycle_stage?: LifecycleStage;
146
- custom?: Record<string, unknown>;
147
- deleted_at?: null;
148
- }
149
-
150
- export interface CompanySearchFilter {
151
- lifecycle_stage?: LifecycleStage[];
152
- source?: ContactSource[];
153
- domain?: string;
154
- include_deleted?: boolean;
155
- limit?: number;
156
- offset?: number;
157
- }
158
-
159
- export interface CompanySearchResult {
160
- companies: Company[];
161
- total: number;
162
- }
163
-
164
- export interface EventsResponse {
165
- events: ContactEvent[];
166
- next_cursor?: string;
167
- }
168
-
169
- export interface ListEventsOptions {
170
- limit?: number; // 1-200, default 50
171
- cursor?: string;
172
- kind?: EventKind;
173
- }
174
-
175
- // ── Contacts ──────────────────────────────────────────────────────────────
176
-
177
- export async function createContact(apiKey: string, orgId: string, input: CreateContactInput): Promise<Contact> {
178
- return request('POST', `${BASE_URL}/crm/orgs/${encodeURIComponent(orgId)}/contacts`, apiKey, input);
179
- }
180
-
181
- export async function getContact(apiKey: string, orgId: string, id: string): Promise<Contact> {
182
- return request('GET', `${BASE_URL}/crm/orgs/${encodeURIComponent(orgId)}/contacts/${encodeURIComponent(id)}`, apiKey);
183
- }
184
-
185
- export async function updateContact(apiKey: string, orgId: string, id: string, patch: UpdateContactInput): Promise<Contact> {
186
- return request('PATCH', `${BASE_URL}/crm/orgs/${encodeURIComponent(orgId)}/contacts/${encodeURIComponent(id)}`, apiKey, patch);
187
- }
188
-
189
- export async function deleteContact(apiKey: string, orgId: string, id: string): Promise<void> {
190
- return request('DELETE', `${BASE_URL}/crm/orgs/${encodeURIComponent(orgId)}/contacts/${encodeURIComponent(id)}`, apiKey);
191
- }
192
-
193
- export async function searchContacts(apiKey: string, orgId: string, filter: ContactSearchFilter = {}): Promise<ContactSearchResult> {
194
- return request('POST', `${BASE_URL}/crm/orgs/${encodeURIComponent(orgId)}/contacts/search`, apiKey, filter);
195
- }
196
-
197
- export async function promoteContact(apiKey: string, orgId: string, goldfoxPersonId: string): Promise<Contact> {
198
- return request('POST', `${BASE_URL}/crm/orgs/${encodeURIComponent(orgId)}/contacts/promote`, apiKey, { goldfox_person_id: goldfoxPersonId });
199
- }
200
-
201
- export async function getContactEvents(apiKey: string, orgId: string, id: string, opts: ListEventsOptions = {}): Promise<EventsResponse> {
202
- const qs = new URLSearchParams();
203
- if (opts.limit != null) qs.append('limit', String(opts.limit));
204
- if (opts.cursor != null) qs.append('cursor', opts.cursor);
205
- if (opts.kind != null) qs.append('kind', opts.kind);
206
- const q = qs.toString();
207
- const url = `${BASE_URL}/crm/orgs/${encodeURIComponent(orgId)}/contacts/${encodeURIComponent(id)}/events${q ? `?${q}` : ''}`;
208
- // Paginated (WrapPage): events are the bare `data` array with the cursor
209
- // under `meta` — use requestPage so `next_cursor` survives.
210
- const page = await requestPage<ContactEvent>('GET', url, apiKey);
211
- return { events: page.data, next_cursor: page.next_cursor };
212
- }
213
-
214
- // ── Companies ─────────────────────────────────────────────────────────────
215
-
216
- export async function createCompany(apiKey: string, orgId: string, input: CreateCompanyInput): Promise<Company> {
217
- return request('POST', `${BASE_URL}/crm/orgs/${encodeURIComponent(orgId)}/companies`, apiKey, input);
218
- }
219
-
220
- export async function getCompany(apiKey: string, orgId: string, id: string): Promise<Company> {
221
- return request('GET', `${BASE_URL}/crm/orgs/${encodeURIComponent(orgId)}/companies/${encodeURIComponent(id)}`, apiKey);
222
- }
223
-
224
- export async function updateCompany(apiKey: string, orgId: string, id: string, patch: UpdateCompanyInput): Promise<Company> {
225
- return request('PATCH', `${BASE_URL}/crm/orgs/${encodeURIComponent(orgId)}/companies/${encodeURIComponent(id)}`, apiKey, patch);
226
- }
227
-
228
- export async function deleteCompany(apiKey: string, orgId: string, id: string): Promise<void> {
229
- return request('DELETE', `${BASE_URL}/crm/orgs/${encodeURIComponent(orgId)}/companies/${encodeURIComponent(id)}`, apiKey);
230
- }
231
-
232
- export async function searchCompanies(apiKey: string, orgId: string, filter: CompanySearchFilter = {}): Promise<CompanySearchResult> {
233
- return request('POST', `${BASE_URL}/crm/orgs/${encodeURIComponent(orgId)}/companies/search`, apiKey, filter);
234
- }
235
-
236
- // Goldfox company id IS its domain (Simon's note in routes.md).
237
- export async function promoteCompany(apiKey: string, orgId: string, domain: string): Promise<Company> {
238
- return request('POST', `${BASE_URL}/crm/orgs/${encodeURIComponent(orgId)}/companies/promote`, apiKey, { goldfox_company_id: domain });
239
- }
package/src/database.ts DELETED
@@ -1,106 +0,0 @@
1
- import { request, requestPage } from './client';
2
- import { DATABASE_BASE as BASE_URL } from './config';
3
- import type { Exposes } from './exposes';
4
-
5
- export const EXPOSES: Exposes = [
6
- 'GET /database/orgs/{org_id}/namespaces',
7
- 'POST /database/orgs/{org_id}/namespaces',
8
- 'GET /database/orgs/{org_id}/namespaces/{ns}',
9
- 'DELETE /database/orgs/{org_id}/namespaces/{ns}',
10
- 'GET /database/orgs/{org_id}/namespaces/{ns}/keys',
11
- 'GET /database/orgs/{org_id}/namespaces/{ns}/keys/{key}',
12
- 'PUT /database/orgs/{org_id}/namespaces/{ns}/keys/{key}',
13
- 'DELETE /database/orgs/{org_id}/namespaces/{ns}/keys/{key}',
14
- ];
15
-
16
- // Per-value JSON size cap. Mirrored server-side. Surfaced here so the CLI
17
- // can fail fast before round-trip.
18
- export const MAX_VALUE_BYTES = 256 * 1024;
19
-
20
- export interface Namespace {
21
- name: string;
22
- org_id: string;
23
- key_count: number; // approximate; eventually consistent
24
- created_at: string;
25
- }
26
-
27
- export interface KeyEntry {
28
- key: string;
29
- value?: unknown; // present when values=true was requested or on get
30
- etag: string;
31
- updated_at: string;
32
- }
33
-
34
- export interface ListKeysOptions {
35
- prefix?: string;
36
- limit?: number; // 1-1000, default 50
37
- cursor?: string; // opaque from previous response
38
- values?: boolean; // default false
39
- }
40
-
41
- export interface ListKeysResponse {
42
- keys: KeyEntry[];
43
- next_cursor?: string; // present when more results exist
44
- }
45
-
46
- export interface ListNamespacesResponse {
47
- namespaces: Namespace[];
48
- }
49
-
50
- export async function listNamespaces(apiKey: string, orgId: string): Promise<ListNamespacesResponse> {
51
- return request('GET', `${BASE_URL}/database/orgs/${encodeURIComponent(orgId)}/namespaces`, apiKey);
52
- }
53
-
54
- export async function createNamespace(apiKey: string, orgId: string, name: string): Promise<Namespace> {
55
- return request('POST', `${BASE_URL}/database/orgs/${encodeURIComponent(orgId)}/namespaces`, apiKey, { name });
56
- }
57
-
58
- export async function getNamespace(apiKey: string, orgId: string, name: string): Promise<Namespace> {
59
- return request('GET', `${BASE_URL}/database/orgs/${encodeURIComponent(orgId)}/namespaces/${encodeURIComponent(name)}`, apiKey);
60
- }
61
-
62
- export async function deleteNamespace(apiKey: string, orgId: string, name: string): Promise<void> {
63
- return request('DELETE', `${BASE_URL}/database/orgs/${encodeURIComponent(orgId)}/namespaces/${encodeURIComponent(name)}`, apiKey);
64
- }
65
-
66
- export async function listKeys(apiKey: string, orgId: string, ns: string, opts: ListKeysOptions = {}): Promise<ListKeysResponse> {
67
- const qs = new URLSearchParams();
68
- if (opts.prefix != null) qs.append('prefix', opts.prefix);
69
- if (opts.limit != null) qs.append('limit', String(opts.limit));
70
- if (opts.cursor != null) qs.append('cursor', opts.cursor);
71
- if (opts.values) qs.append('values', 'true');
72
- const q = qs.toString();
73
- const url = `${BASE_URL}/database/orgs/${encodeURIComponent(orgId)}/namespaces/${encodeURIComponent(ns)}/keys${q ? `?${q}` : ''}`;
74
- // Paginated (WrapPage): keys come back as the bare `data` array with the
75
- // cursor under `meta` — must use requestPage or the cursor is lost.
76
- const page = await requestPage<KeyEntry>('GET', url, apiKey);
77
- return { keys: page.data, next_cursor: page.next_cursor };
78
- }
79
-
80
- export async function getKey(apiKey: string, orgId: string, ns: string, key: string): Promise<KeyEntry> {
81
- return request('GET', `${BASE_URL}/database/orgs/${encodeURIComponent(orgId)}/namespaces/${encodeURIComponent(ns)}/keys/${encodeURIComponent(key)}`, apiKey);
82
- }
83
-
84
- // `ifMatch` enables compare-and-swap: server returns 412 ETAG_MISMATCH when
85
- // the stored etag differs. Omit for last-write-wins.
86
- export async function putKey(apiKey: string, orgId: string, ns: string, key: string, value: unknown, ifMatch?: string): Promise<KeyEntry> {
87
- const headers = ifMatch ? { 'If-Match': ifMatch } : undefined;
88
- return request(
89
- 'PUT',
90
- `${BASE_URL}/database/orgs/${encodeURIComponent(orgId)}/namespaces/${encodeURIComponent(ns)}/keys/${encodeURIComponent(key)}`,
91
- apiKey,
92
- { value },
93
- headers,
94
- );
95
- }
96
-
97
- export async function deleteKey(apiKey: string, orgId: string, ns: string, key: string, ifMatch?: string): Promise<void> {
98
- const headers = ifMatch ? { 'If-Match': ifMatch } : undefined;
99
- return request(
100
- 'DELETE',
101
- `${BASE_URL}/database/orgs/${encodeURIComponent(orgId)}/namespaces/${encodeURIComponent(ns)}/keys/${encodeURIComponent(key)}`,
102
- apiKey,
103
- undefined,
104
- headers,
105
- );
106
- }
package/src/domain.ts DELETED
@@ -1,246 +0,0 @@
1
- import { request } from './client';
2
- import { DOMAIN_BASE as BASE_URL } from './config';
3
- import type { Exposes } from './exposes';
4
-
5
- export const EXPOSES: Exposes = [
6
- 'GET /domain/orgs/{org_id}/list',
7
- 'GET /domain/orgs/{org_id}/check/available/{name}',
8
- 'POST /domain/orgs/{org_id}/register',
9
- 'POST /domain/orgs/{org_id}/import',
10
- 'POST /domain/orgs/{org_id}/{domain}/assign',
11
- 'POST /domain/orgs/{org_id}/{domain}/renew',
12
- 'GET /domain/orgs/{org_id}/{domain}/settings',
13
- 'POST /domain/orgs/{org_id}/{domain}/settings',
14
- 'GET /domain/orgs/{org_id}/{domain}/status',
15
- 'GET /domain/orgs/{org_id}/{domain}/records',
16
- 'GET /domain/orgs/{org_id}/{domain}/records/{record_id}',
17
- 'POST /domain/orgs/{org_id}/{domain}/records',
18
- 'PATCH /domain/orgs/{org_id}/{domain}/records/{record_id}',
19
- 'DELETE /domain/orgs/{org_id}/{domain}/records/{record_id}',
20
- 'POST /domain/orgs/{org_id}/{domain}/email-infra',
21
- 'POST /domain/orgs/{org_id}/{domain}/retry-provisioning',
22
- ];
23
-
24
-
25
-
26
- export interface DomainRecord {
27
- domain: string;
28
- status: string;
29
- expires_at?: string;
30
- days_until_expiry?: number;
31
- email_infra_ready?: boolean;
32
- // New status surface (post-2026-05-14 backend). Email infra is opt-in and
33
- // always lives on a subdomain — apex is never touched.
34
- email_infra?: 'skipped' | 'pending' | 'ready' | 'error';
35
- email_subdomain?: string; // Only set when email_infra ∈ {pending, ready, error}.
36
- dns_active?: boolean;
37
- steps_completed?: string[];
38
- error_detail?: {
39
- failed_step: string;
40
- message: string;
41
- retryable: boolean;
42
- attempt_count?: number;
43
- last_attempt_at?: string;
44
- };
45
- org_id?: string | null;
46
- created_at: string;
47
- }
48
-
49
- export interface DomainSettings {
50
- domain: string;
51
- security_level: string;
52
- browser_check: string;
53
- ai_bots_protection: string;
54
- is_robots_txt_managed: boolean;
55
- }
56
-
57
- // ICANN-required WHOIS contact info for domain registration. Sent in the
58
- // register-domain request body when REGISTRAR_PROVIDER=cloudflare is set
59
- // server-side; ignored (but accepted) under the legacy OpenProvider path.
60
- // The CF account holds the zone; this is the WHOIS registrant.
61
- export interface Registrant {
62
- name: string;
63
- email: string;
64
- phone: string; // E.164 format recommended (e.g. "+33612345678")
65
- street: string;
66
- city: string;
67
- state?: string; // Required for US / CA registrants; optional elsewhere.
68
- postal_code: string;
69
- country_code: string; // ISO 3166-1 alpha-2 (e.g. "US", "DE", "FR")
70
- organization?: string; // Optional organization name (WHOIS "Registrant Organization" field).
71
- }
72
-
73
- export interface RegisterDomainInput {
74
- years?: number;
75
- // Required only when the server runs REGISTRAR_PROVIDER=cloudflare (the CF
76
- // account holds the zone; this is the WHOIS registrant). Under the legacy
77
- // OpenProvider path it is ignored-but-accepted, so it's optional here and the
78
- // backend enforces its presence when it actually needs it.
79
- registrant?: Registrant;
80
- }
81
-
82
- export async function checkDomain(apiKey: string, orgId: string, domain: string): Promise<{ available: boolean; price_cents: number }> {
83
- return request('GET', `${BASE_URL}/domain/orgs/${encodeURIComponent(orgId)}/check/available/${encodeURIComponent(domain)}`, apiKey);
84
- }
85
-
86
- export async function registerDomain(apiKey: string, orgId: string, domain: string, input: RegisterDomainInput): Promise<DomainRecord> {
87
- return request('POST', `${BASE_URL}/domain/orgs/${encodeURIComponent(orgId)}/register`, apiKey, {
88
- domain,
89
- years: input.years,
90
- registrant: input.registrant,
91
- });
92
- }
93
-
94
- export async function renewDomain(apiKey: string, orgId: string, domain: string): Promise<DomainRecord> {
95
- return request('POST', `${BASE_URL}/domain/orgs/${encodeURIComponent(orgId)}/${encodeURIComponent(domain)}/renew`, apiKey);
96
- }
97
-
98
- // BYOD import — registrar-agnostic. Backend uses CF zone creation + best-effort
99
- // public DNS probe to snapshot existing records before the NS swap. Customer's
100
- // next action is changing NS at their current registrar to the returned values.
101
- export interface PreservedRecord {
102
- type: string;
103
- name: string;
104
- content: string;
105
- ttl: number;
106
- }
107
-
108
- export interface ImportDomainResponse {
109
- domain: string;
110
- domain_id: string;
111
- status: string; // 'pending_ns_change' initially
112
- nameservers: string[];
113
- preserved_records: PreservedRecord[];
114
- preserved_count: number;
115
- probe_warning: string;
116
- next_step: string;
117
- }
118
-
119
- export async function importDomain(apiKey: string, orgId: string, domain: string): Promise<ImportDomainResponse> {
120
- return request('POST', `${BASE_URL}/domain/orgs/${encodeURIComponent(orgId)}/import`, apiKey, { domain });
121
- }
122
-
123
- export async function listDomains(apiKey: string, orgId: string, filter?: string): Promise<DomainRecord[]> {
124
- const query = filter ? `?filter=${encodeURIComponent(filter)}` : '';
125
- return request('GET', `${BASE_URL}/domain/orgs/${encodeURIComponent(orgId)}/list${query}`, apiKey);
126
- }
127
-
128
- export async function getDomainStatus(apiKey: string, orgId: string, domain: string): Promise<DomainRecord> {
129
- return request('GET', `${BASE_URL}/domain/orgs/${encodeURIComponent(orgId)}/${encodeURIComponent(domain)}/status`, apiKey);
130
- }
131
-
132
- // Assign returns the bound Worker routes so the CLI can show users what's
133
- // live without hardcoding "apex + www" (which would skew if backend changes
134
- // the default convention). `include_www` defaults to true at the backend.
135
- export interface AssignDomainResponse {
136
- domain: string;
137
- org_id: string | null;
138
- include_www: boolean;
139
- routes_bound: string[];
140
- }
141
-
142
- export async function assignDomain(apiKey: string, orgId: string, domain: string, opts?: { includeWww?: boolean; funnelId?: string }): Promise<AssignDomainResponse> {
143
- const body: Record<string, unknown> = { org_id: orgId };
144
- if (opts?.includeWww === false) body.include_www = false;
145
- // Backend (2026-05-15): optional funnel_id picks which funnel the domain
146
- // is bound to. Defaults server-side to the org's only funnel (or first
147
- // when ambiguous, today; will become required once N-funnels-per-org lands
148
- // for real). Pre-emptively threading it through gives agents a way to be
149
- // explicit when the migration completes without an SDK shape change.
150
- if (opts?.funnelId) body.funnel_id = opts.funnelId;
151
- return request('POST', `${BASE_URL}/domain/orgs/${encodeURIComponent(orgId)}/${encodeURIComponent(domain)}/assign`, apiKey, body);
152
- }
153
-
154
- export async function unassignDomain(apiKey: string, orgId: string, domain: string): Promise<AssignDomainResponse> {
155
- return request('POST', `${BASE_URL}/domain/orgs/${encodeURIComponent(orgId)}/${encodeURIComponent(domain)}/assign`, apiKey, { org_id: null });
156
- }
157
-
158
- export async function getDomainSettings(apiKey: string, orgId: string, domain: string): Promise<DomainSettings> {
159
- return request('GET', `${BASE_URL}/domain/orgs/${encodeURIComponent(orgId)}/${encodeURIComponent(domain)}/settings`, apiKey);
160
- }
161
-
162
- // ── DNS records ──────────────────────────────────────────────────────────────
163
- // Per-zone CRUD on the Cloudflare zone the backend manages for this domain.
164
- // v1 supports A / AAAA / CNAME / MX / TXT. `priority` is non-null only for MX,
165
- // `proxied` is non-null only for A/AAAA/CNAME. `ttl: 1` is CF's "automatic"
166
- // sentinel.
167
-
168
- export type DnsRecordType = 'A' | 'AAAA' | 'CNAME' | 'MX' | 'TXT';
169
-
170
- export interface DnsRecord {
171
- id: string;
172
- type: DnsRecordType;
173
- name: string; // FQDN as stored by CF
174
- content: string;
175
- ttl: number;
176
- priority: number | null;
177
- proxied: boolean | null;
178
- created_on: string;
179
- modified_on: string;
180
- }
181
-
182
- export interface DnsRecordInput {
183
- type: DnsRecordType;
184
- name: string; // Accepts FQDN, host-only, or apex tokens (`@`, `""`).
185
- content: string;
186
- ttl?: number; // Default 1 (CF auto). Range [60, 86400] otherwise.
187
- priority?: number; // Required for MX.
188
- proxied?: boolean; // A/AAAA/CNAME only. Defaults false.
189
- }
190
-
191
- export async function listDnsRecords(apiKey: string, orgId: string, domain: string, type?: DnsRecordType): Promise<DnsRecord[]> {
192
- const query = type ? `?type=${encodeURIComponent(type)}` : '';
193
- return request('GET', `${BASE_URL}/domain/orgs/${encodeURIComponent(orgId)}/${encodeURIComponent(domain)}/records${query}`, apiKey);
194
- }
195
-
196
- export async function getDnsRecord(apiKey: string, orgId: string, domain: string, recordId: string): Promise<DnsRecord> {
197
- return request('GET', `${BASE_URL}/domain/orgs/${encodeURIComponent(orgId)}/${encodeURIComponent(domain)}/records/${encodeURIComponent(recordId)}`, apiKey);
198
- }
199
-
200
- export async function createDnsRecord(apiKey: string, orgId: string, domain: string, input: DnsRecordInput): Promise<DnsRecord> {
201
- return request('POST', `${BASE_URL}/domain/orgs/${encodeURIComponent(orgId)}/${encodeURIComponent(domain)}/records`, apiKey, input);
202
- }
203
-
204
- export async function updateDnsRecord(apiKey: string, orgId: string, domain: string, recordId: string, input: Partial<Omit<DnsRecordInput, 'type'>>): Promise<DnsRecord> {
205
- return request('PATCH', `${BASE_URL}/domain/orgs/${encodeURIComponent(orgId)}/${encodeURIComponent(domain)}/records/${encodeURIComponent(recordId)}`, apiKey, input);
206
- }
207
-
208
- export async function deleteDnsRecord(apiKey: string, orgId: string, domain: string, recordId: string): Promise<void> {
209
- return request('DELETE', `${BASE_URL}/domain/orgs/${encodeURIComponent(orgId)}/${encodeURIComponent(domain)}/records/${encodeURIComponent(recordId)}`, apiKey);
210
- }
211
-
212
- // Opt in to MyAPI-managed email on a subdomain. Apex is never touched; the
213
- // backend provisions an SES identity on <subdomain>.<domain> and writes
214
- // DKIM/SPF/DMARC records there. Default subdomain is `mail`.
215
- export interface EmailInfraResponse {
216
- domain: string;
217
- email_infra: 'pending' | 'ready' | 'error';
218
- subdomain: string;
219
- next_step?: string;
220
- }
221
-
222
- export async function setupEmailInfra(apiKey: string, orgId: string, domain: string, subdomain?: string): Promise<EmailInfraResponse> {
223
- const body = subdomain ? { subdomain } : {};
224
- return request('POST', `${BASE_URL}/domain/orgs/${encodeURIComponent(orgId)}/${encodeURIComponent(domain)}/email-infra`, apiKey, body);
225
- }
226
-
227
- // Re-run provisioning from the failed step when status=infra_error and the
228
- // error is retryable. Returns a transient `{ email_infra: 'pending', next_step }`
229
- // shape; caller polls `getDomainStatus` until status flips off `infra_error`.
230
- export interface RetryProvisioningResponse {
231
- domain: string;
232
- email_infra?: string;
233
- next_step?: string;
234
- }
235
-
236
- export async function retryProvisioning(apiKey: string, orgId: string, domain: string): Promise<RetryProvisioningResponse> {
237
- return request('POST', `${BASE_URL}/domain/orgs/${encodeURIComponent(orgId)}/${encodeURIComponent(domain)}/retry-provisioning`, apiKey);
238
- }
239
-
240
- export async function updateDomainSettings(apiKey: string, orgId: string, domain: string, payload: {
241
- security_level?: 'essentially_off' | 'medium' | 'high' | 'under_attack';
242
- browser_check?: 'on' | 'off';
243
- purge_cache?: boolean;
244
- }): Promise<DomainSettings> {
245
- return request('POST', `${BASE_URL}/domain/orgs/${encodeURIComponent(orgId)}/${encodeURIComponent(domain)}/settings`, apiKey, payload);
246
- }