@myapihq/cli 2.7.1 → 2.7.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/dist/commands/account.js +15 -0
- package/dist/commands/audience.js +7 -5
- package/dist/commands/crm/companies.js +4 -4
- package/dist/commands/crm/contacts.js +4 -4
- package/dist/commands/crm/index.js +3 -0
- package/dist/commands/crm/origin-flag.test.d.ts +1 -0
- package/dist/commands/crm/origin-flag.test.js +38 -0
- package/dist/commands/crm/pagination.d.ts +2 -0
- package/dist/commands/crm/pagination.js +9 -0
- package/dist/commands/domain.js +11 -0
- package/dist/commands/fn.js +7 -2
- package/dist/commands/task.js +12 -4
- package/dist/skills/my-api-hq/SKILL.md +25 -1
- package/dist/skills/my-audience-api/SKILL.md +5 -5
- package/dist/skills/my-auth-api/SKILL.md +8 -1
- package/dist/skills/my-company-api/SKILL.md +3 -3
- package/dist/skills/my-container-api/SKILL.md +25 -4
- package/dist/skills/my-crm-api/SKILL.md +6 -6
- package/dist/skills/my-database-api/SKILL.md +22 -1
- package/dist/skills/my-domain-api/SKILL.md +18 -1
- package/dist/skills/my-email-api/SKILL.md +36 -1
- package/dist/skills/my-function-api/SKILL.md +29 -1
- package/dist/skills/my-funnel-api/SKILL.md +6 -3
- package/dist/skills/my-git-api/SKILL.md +7 -1
- package/dist/skills/my-people-api/SKILL.md +3 -3
- package/dist/skills/my-pixel-api/SKILL.md +12 -1
- package/dist/skills/my-storage-api/SKILL.md +31 -2
- package/dist/skills/my-task-api/SKILL.md +9 -1
- package/dist/skills/my-webhook-api/SKILL.md +12 -1
- package/package.json +3 -2
package/dist/commands/account.js
CHANGED
|
@@ -25,6 +25,21 @@ export const SCHEMA = {
|
|
|
25
25
|
'no-skills': 'boolean',
|
|
26
26
|
anonymous: 'boolean',
|
|
27
27
|
anon: 'boolean',
|
|
28
|
+
// Flags belonging to SUBCOMMANDS of `account`. They have to be declared here
|
|
29
|
+
// because the foreign-flag check runs against the top-level command's schema
|
|
30
|
+
// and cannot see subcommand parsers. Omitting them made the CLI print
|
|
31
|
+
// "--registrant-json is not a flag of `myapi account` — the value was
|
|
32
|
+
// ignored" and then use the value anyway: a warning that was itself false,
|
|
33
|
+
// which is worse than the missing check it was added to provide.
|
|
34
|
+
'registrant-json': 'string',
|
|
35
|
+
'registrant-name': 'string',
|
|
36
|
+
'registrant-email': 'string',
|
|
37
|
+
'registrant-phone': 'string',
|
|
38
|
+
'registrant-street': 'string',
|
|
39
|
+
'registrant-city': 'string',
|
|
40
|
+
'registrant-state': 'string',
|
|
41
|
+
'registrant-postal-code': 'string',
|
|
42
|
+
'registrant-country-code': 'string',
|
|
28
43
|
};
|
|
29
44
|
export const HELP = `Usage: myapi account <subcommand>
|
|
30
45
|
|
|
@@ -15,6 +15,8 @@ export const SCHEMA = {
|
|
|
15
15
|
org: 'string',
|
|
16
16
|
name: 'string',
|
|
17
17
|
description: 'string',
|
|
18
|
+
from: 'string',
|
|
19
|
+
// Deprecated alias for --from; undocumented, removable next minor.
|
|
18
20
|
source: 'string',
|
|
19
21
|
filter: 'string',
|
|
20
22
|
limit: 'number',
|
|
@@ -47,11 +49,11 @@ function summarizeAudience(a) {
|
|
|
47
49
|
}
|
|
48
50
|
async function create(nameArg, flags) {
|
|
49
51
|
const config = requireConfig();
|
|
50
|
-
const orgId = requireOrg(flags, config, 'myapi audience create <name> --
|
|
52
|
+
const orgId = requireOrg(flags, config, 'myapi audience create <name> --from <people|company> --filter <json>');
|
|
51
53
|
const name = nameArg || flags.name;
|
|
52
54
|
if (!name)
|
|
53
|
-
error('Missing required argument <name>.\nUsage: myapi audience create <name> --
|
|
54
|
-
const source = flags.source;
|
|
55
|
+
error('Missing required argument <name>.\nUsage: myapi audience create <name> --from <people|company> --filter <json>');
|
|
56
|
+
const source = (flags.from ?? flags.source);
|
|
55
57
|
if (source !== 'people' && source !== 'company') {
|
|
56
58
|
error(`--source must be "people" or "company" (got: ${source ?? '<missing>'}).`);
|
|
57
59
|
}
|
|
@@ -76,7 +78,7 @@ async function list(flags) {
|
|
|
76
78
|
}
|
|
77
79
|
printTable(res.map(summarizeAudience), {
|
|
78
80
|
flags,
|
|
79
|
-
empty: 'No audiences yet. Create one with: myapi audience create <name> --
|
|
81
|
+
empty: 'No audiences yet. Create one with: myapi audience create <name> --from <people|company> --filter <json>',
|
|
80
82
|
});
|
|
81
83
|
}
|
|
82
84
|
async function get(id, flags) {
|
|
@@ -168,7 +170,7 @@ async function refresh(id, flags) {
|
|
|
168
170
|
success(`Refreshed. ${res.previous} → ${res.total} (${sign}${res.delta})`);
|
|
169
171
|
}
|
|
170
172
|
const SUBCOMMAND_USAGE = {
|
|
171
|
-
'create': `myapi audience create <name> --
|
|
173
|
+
'create': `myapi audience create <name> --from <people|company> --filter <json> [--description <text>] [--org <id>]
|
|
172
174
|
|
|
173
175
|
The Goldfox filter shape is shared across people/company/audience:
|
|
174
176
|
{
|
|
@@ -3,7 +3,7 @@ import { crm } from '@myapihq/sdk';
|
|
|
3
3
|
import { requireConfig } from '../../config.js';
|
|
4
4
|
import { success, error, info, printTable, printJson } from '../../output.js';
|
|
5
5
|
import { requireOrg, requireArg } from '../../helpers.js';
|
|
6
|
-
import { pageLine } from './pagination.js';
|
|
6
|
+
import { pageLine, originFlag } from './pagination.js';
|
|
7
7
|
export const EXPOSES = [
|
|
8
8
|
'POST /crm/orgs/{org_id}/companies',
|
|
9
9
|
'POST /crm/orgs/{org_id}/companies/promote',
|
|
@@ -32,7 +32,7 @@ function parseCustom(v) {
|
|
|
32
32
|
function buildSearchFilter(flags) {
|
|
33
33
|
return {
|
|
34
34
|
lifecycle_stage: csv(flags.stage),
|
|
35
|
-
source: csv(flags
|
|
35
|
+
source: csv(originFlag(flags)),
|
|
36
36
|
domain: typeof flags.domain === 'string' ? flags.domain : undefined,
|
|
37
37
|
include_deleted: flags['include-deleted'] === true || undefined,
|
|
38
38
|
limit: typeof flags.limit === 'number' ? flags.limit : undefined,
|
|
@@ -144,11 +144,11 @@ async function promote(domain, flags) {
|
|
|
144
144
|
// ── Dispatcher ──────────────────────────────────────────────────────────
|
|
145
145
|
const SUBCOMMAND_USAGE = {
|
|
146
146
|
list: 'myapi crm companies list [--limit N] [--offset N] [--org <id>] [--json]',
|
|
147
|
-
search: `myapi crm companies search [--stage <csv>] [--
|
|
147
|
+
search: `myapi crm companies search [--stage <csv>] [--origin <csv>] [--domain <d>]
|
|
148
148
|
[--include-deleted] [--limit N] [--offset N] [--org <id>] [--json]
|
|
149
149
|
|
|
150
150
|
--stage cold, warm, qualified, customer, churned
|
|
151
|
-
--
|
|
151
|
+
--origin goldfox, email, pixel, webhook, manual`,
|
|
152
152
|
create: 'myapi crm companies create <domain> [--name <n>] [--stage <s>] [--custom-json <json>] [--org <id>]',
|
|
153
153
|
get: 'myapi crm companies get <id> [--org <id>]',
|
|
154
154
|
update: 'myapi crm companies update <id> [--stage <s>] [--name <n>] [--custom-json <json>] [--org <id>]',
|
|
@@ -3,7 +3,7 @@ import { crm } from '@myapihq/sdk';
|
|
|
3
3
|
import { requireConfig } from '../../config.js';
|
|
4
4
|
import { success, error, info, printTable, printJson } from '../../output.js';
|
|
5
5
|
import { requireOrg, requireArg } from '../../helpers.js';
|
|
6
|
-
import { pageLine } from './pagination.js';
|
|
6
|
+
import { pageLine, originFlag } from './pagination.js';
|
|
7
7
|
export const EXPOSES = [
|
|
8
8
|
'POST /crm/orgs/{org_id}/contacts',
|
|
9
9
|
'POST /crm/orgs/{org_id}/contacts/promote',
|
|
@@ -35,7 +35,7 @@ function parseCustom(v) {
|
|
|
35
35
|
function buildSearchFilter(flags) {
|
|
36
36
|
return {
|
|
37
37
|
lifecycle_stage: csv(flags.stage),
|
|
38
|
-
source: csv(flags
|
|
38
|
+
source: csv(originFlag(flags)),
|
|
39
39
|
email: typeof flags.email === 'string' ? flags.email : undefined,
|
|
40
40
|
company_id: typeof flags['company-id'] === 'string' ? flags['company-id'] : undefined,
|
|
41
41
|
min_last_engagement_days: typeof flags['min-last-engagement-days'] === 'number' ? flags['min-last-engagement-days'] : undefined,
|
|
@@ -179,12 +179,12 @@ async function events(id, flags) {
|
|
|
179
179
|
// ── Dispatcher ──────────────────────────────────────────────────────────
|
|
180
180
|
const SUBCOMMAND_USAGE = {
|
|
181
181
|
list: 'myapi crm contacts list [--limit N] [--offset N] [--org <id>] [--json]',
|
|
182
|
-
search: `myapi crm contacts search [--stage <csv>] [--
|
|
182
|
+
search: `myapi crm contacts search [--stage <csv>] [--origin <csv>] [--email <e>]
|
|
183
183
|
[--company-id <id>] [--min-last-engagement-days N] [--max-last-engagement-days N]
|
|
184
184
|
[--include-deleted] [--limit N] [--offset N] [--org <id>] [--json]
|
|
185
185
|
|
|
186
186
|
--stage cold, warm, qualified, customer, churned
|
|
187
|
-
--
|
|
187
|
+
--origin goldfox, email, pixel, webhook, manual
|
|
188
188
|
|
|
189
189
|
Engagement filters:
|
|
190
190
|
--min-last-engagement-days N contacts engaged within N days
|
|
@@ -16,6 +16,9 @@ export const SCHEMA = {
|
|
|
16
16
|
'last-name': 'string',
|
|
17
17
|
name: 'string',
|
|
18
18
|
stage: 'string',
|
|
19
|
+
origin: 'string',
|
|
20
|
+
// Deprecated alias for --origin. Kept so existing scripts keep working;
|
|
21
|
+
// undocumented, and removable no earlier than the next minor.
|
|
19
22
|
source: 'string',
|
|
20
23
|
'company-id': 'string',
|
|
21
24
|
'custom-json': 'string',
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// `--source` meant five different things across the CLI: a container build
|
|
2
|
+
// context, a git merge branch, an audience dataset, a task origin, and a CRM
|
|
3
|
+
// provenance enum. An agent that learned it in one place carried a wrong prior
|
|
4
|
+
// into the others, and no linter could catch it — `--source` really is valid
|
|
5
|
+
// for every one of those commands, so nothing was ever "unknown".
|
|
6
|
+
//
|
|
7
|
+
// It is `--origin` for provenance now (crm, task) and `--from` for the
|
|
8
|
+
// audience dataset. `--source` keeps its container meaning, and stays on
|
|
9
|
+
// `git merge` where `--target` anchors it and the pair is idiomatic.
|
|
10
|
+
//
|
|
11
|
+
// The old spellings still work, undocumented, so nobody's scripts break.
|
|
12
|
+
import { describe, it, expect } from 'vitest';
|
|
13
|
+
import { originFlag } from './pagination.js';
|
|
14
|
+
describe('originFlag', () => {
|
|
15
|
+
it('reads the new flag', () => {
|
|
16
|
+
expect(originFlag({ origin: 'webhook' })).toBe('webhook');
|
|
17
|
+
});
|
|
18
|
+
it('still accepts the old one', () => {
|
|
19
|
+
expect(originFlag({ source: 'webhook' })).toBe('webhook');
|
|
20
|
+
});
|
|
21
|
+
// Someone mid-migration may have both in a script. The new name is the
|
|
22
|
+
// one they meant.
|
|
23
|
+
it('prefers --origin when both are given', () => {
|
|
24
|
+
expect(originFlag({ origin: 'manual', source: 'webhook' })).toBe('manual');
|
|
25
|
+
});
|
|
26
|
+
it('is undefined when neither is given', () => {
|
|
27
|
+
expect(originFlag({})).toBeUndefined();
|
|
28
|
+
});
|
|
29
|
+
// csv() downstream splits this; the helper must not mangle it.
|
|
30
|
+
it('passes a comma-separated list through untouched', () => {
|
|
31
|
+
expect(originFlag({ origin: 'goldfox,webhook' })).toBe('goldfox,webhook');
|
|
32
|
+
});
|
|
33
|
+
// An explicitly empty --origin is a real (if useless) input, and must not
|
|
34
|
+
// silently fall through to a stale --source in the same command.
|
|
35
|
+
it('does not fall back when --origin is present but empty', () => {
|
|
36
|
+
expect(originFlag({ origin: '', source: 'webhook' })).toBe('');
|
|
37
|
+
});
|
|
38
|
+
});
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { type Flags } from '../../helpers.js';
|
|
1
2
|
import type { Exposes } from '../../exposes.js';
|
|
2
3
|
export declare const EXPOSES: Exposes;
|
|
4
|
+
export declare function originFlag(flags: Flags): string | boolean | number | undefined;
|
|
3
5
|
export declare function pageLine(returned: number, total: number | undefined, hasMore: boolean | undefined, singular: string, plural: string): string;
|
|
@@ -18,6 +18,15 @@
|
|
|
18
18
|
// exempted, so the coverage gate's "every module states its surface" rule
|
|
19
19
|
// stays absolute.
|
|
20
20
|
export const EXPOSES = [];
|
|
21
|
+
// --source meant five different things across the CLI: a build context, a
|
|
22
|
+
// merge branch, a dataset, a task origin, and this — where a contact came
|
|
23
|
+
// from. An agent that learned it once carried a wrong prior everywhere else,
|
|
24
|
+
// and no linter could catch it because --source really is valid for each.
|
|
25
|
+
//
|
|
26
|
+
// It is --origin here now. The old name still works and is undocumented.
|
|
27
|
+
export function originFlag(flags) {
|
|
28
|
+
return flags.origin !== undefined ? flags.origin : flags.source;
|
|
29
|
+
}
|
|
21
30
|
// "3 contacts" · "3 of 128 contacts" · "3 of 128 contacts (more available)".
|
|
22
31
|
//
|
|
23
32
|
// `total` is only rendered when the API supplied it, and the more-available
|
package/dist/commands/domain.js
CHANGED
|
@@ -89,6 +89,17 @@ export async function check(domainArg, flags) {
|
|
|
89
89
|
else {
|
|
90
90
|
const msg = typeof res.message === 'string' ? res.message : res.message ? JSON.stringify(res.message) : 'Not available';
|
|
91
91
|
info(`${domain} — ${msg} ✗`);
|
|
92
|
+
// "This TLD is not currently supported" reads as a dead end, and a team
|
|
93
|
+
// building for Switzerland took it as one and settled for a .com. It is
|
|
94
|
+
// not: registering elsewhere and importing the nameservers gives the same
|
|
95
|
+
// DNS, SSL and mail behaviour, with no registrar credentials needed. The
|
|
96
|
+
// answer belongs in the same message as the refusal.
|
|
97
|
+
if (/TLD is not (currently )?supported|not supported/i.test(msg)) {
|
|
98
|
+
info('');
|
|
99
|
+
info(`→ You can still use ${domain} on MyAPI. Register it with any registrar,`);
|
|
100
|
+
info(` point its nameservers at MyAPI, then: myapi domain import ${domain}`);
|
|
101
|
+
info(' DNS, SSL and mail records work the same way afterwards.');
|
|
102
|
+
}
|
|
92
103
|
}
|
|
93
104
|
}
|
|
94
105
|
export async function register(domainArg, flags) {
|
package/dist/commands/fn.js
CHANGED
|
@@ -54,7 +54,10 @@ function summarizeFn(f) {
|
|
|
54
54
|
id: f.id,
|
|
55
55
|
name: f.name,
|
|
56
56
|
trigger: f.trigger_type === 'cron' ? `cron ${f.cron_schedule ?? '?'}` : 'http',
|
|
57
|
-
|
|
57
|
+
// A cron function is never reachable over HTTP — its URL 404s. Printing
|
|
58
|
+
// one contradicted the docs more loudly than the docs denied it, and a
|
|
59
|
+
// user wrote a `fetch` handler for manual runs that could never fire.
|
|
60
|
+
url: f.trigger_type === 'cron' ? '— (cron: not HTTP-invocable)' : (f.invocation_url || '(not deployed)'),
|
|
58
61
|
updated_at: f.updated_at,
|
|
59
62
|
};
|
|
60
63
|
}
|
|
@@ -128,7 +131,9 @@ export async function get(id, flags) {
|
|
|
128
131
|
info(`ID: ${fn.id}`);
|
|
129
132
|
info(`Name: ${fn.name}`);
|
|
130
133
|
info(`Trigger: ${fn.trigger_type}${fn.cron_schedule ? ` (${fn.cron_schedule})` : ''}`);
|
|
131
|
-
info(
|
|
134
|
+
info(fn.trigger_type === 'cron'
|
|
135
|
+
? 'Invocation URL: — (cron functions are not reachable over HTTP)'
|
|
136
|
+
: `Invocation URL: ${fn.invocation_url || '(not deployed)'}`);
|
|
132
137
|
info(`Created: ${fn.created_at}`);
|
|
133
138
|
info(`Updated: ${fn.updated_at}`);
|
|
134
139
|
}
|
package/dist/commands/task.js
CHANGED
|
@@ -15,6 +15,12 @@ export const EXPOSES = [
|
|
|
15
15
|
'POST /task/orgs/{org_id}/tasks/{id}/fail',
|
|
16
16
|
'POST /task/orgs/{org_id}/tasks/{id}/resolve',
|
|
17
17
|
];
|
|
18
|
+
// --source meant five different things across the CLI. Here it is --origin;
|
|
19
|
+
// the old name still works and is undocumented. See crm/pagination.ts.
|
|
20
|
+
function taskOrigin(flags) {
|
|
21
|
+
const v = flags.origin !== undefined ? flags.origin : flags.source;
|
|
22
|
+
return typeof v === 'string' ? v : undefined;
|
|
23
|
+
}
|
|
18
24
|
export const SCHEMA = {
|
|
19
25
|
body: 'string',
|
|
20
26
|
importance: 'string',
|
|
@@ -24,6 +30,8 @@ export const SCHEMA = {
|
|
|
24
30
|
'depends-on': 'string',
|
|
25
31
|
'dedup-key': 'string',
|
|
26
32
|
'resolve-on': 'string',
|
|
33
|
+
origin: 'string',
|
|
34
|
+
// Deprecated alias for --origin; undocumented, removable next minor.
|
|
27
35
|
source: 'string',
|
|
28
36
|
status: 'string',
|
|
29
37
|
limit: 'number',
|
|
@@ -106,7 +114,7 @@ export async function create(description, flags) {
|
|
|
106
114
|
dependsOn: _splitList(flags['depends-on']),
|
|
107
115
|
dedupKey: typeof flags['dedup-key'] === 'string' ? flags['dedup-key'] : undefined,
|
|
108
116
|
resolveOn,
|
|
109
|
-
source:
|
|
117
|
+
source: taskOrigin(flags),
|
|
110
118
|
});
|
|
111
119
|
if (flags.json) {
|
|
112
120
|
printJson(t);
|
|
@@ -125,7 +133,7 @@ export async function list(flags) {
|
|
|
125
133
|
tag: typeof flags.tag === 'string' ? flags.tag : undefined,
|
|
126
134
|
importance: typeof flags.importance === 'string' ? flags.importance : undefined,
|
|
127
135
|
assignee: typeof flags.assignee === 'string' ? flags.assignee : undefined,
|
|
128
|
-
source:
|
|
136
|
+
source: taskOrigin(flags),
|
|
129
137
|
limit: typeof flags.limit === 'number' ? flags.limit : undefined,
|
|
130
138
|
});
|
|
131
139
|
if (flags.json) {
|
|
@@ -235,8 +243,8 @@ export async function cancel(id, flags) {
|
|
|
235
243
|
}
|
|
236
244
|
// ── Dispatcher ───────────────────────────────────────────────────────────────
|
|
237
245
|
const SUBCOMMAND_USAGE = {
|
|
238
|
-
'create': 'myapi task create "<description>" [--body <md|@file>] [--importance <i>] [--due <rfc3339>] [--assignee <email>] [--tag <t,t>] [--depends-on <id,id>] [--dedup-key <k>] [--resolve-on <event[:field=value]>] [--
|
|
239
|
-
'list': 'myapi task list [--status <s>] [--tag <t>] [--importance <i>] [--assignee <email>] [--
|
|
246
|
+
'create': 'myapi task create "<description>" [--body <md|@file>] [--importance <i>] [--due <rfc3339>] [--assignee <email>] [--tag <t,t>] [--depends-on <id,id>] [--dedup-key <k>] [--resolve-on <event[:field=value]>] [--origin <s>] [--org <id>]',
|
|
247
|
+
'list': 'myapi task list [--status <s>] [--tag <t>] [--importance <i>] [--assignee <email>] [--origin <s>] [--limit <n>] [--org <id>] [--json]',
|
|
240
248
|
'get': 'myapi task get <id> [--body] [--org <id>] [--json]\n\n--body additionally fetches the Markdown body tier (a separate read).',
|
|
241
249
|
'claim': 'myapi task claim <id> [--lease <seconds>] [--worker <name>] [--org <id>]',
|
|
242
250
|
'extend': 'myapi task extend <id> [--lease <seconds>] [--org <id>]',
|
|
@@ -4,7 +4,7 @@ version: 1.0.0
|
|
|
4
4
|
description: >
|
|
5
5
|
Auth, organizations, and billing hub. Start here to get an api_key and org_id — every other service depends on both.
|
|
6
6
|
triggers: [api key, account, organization, org, billing, balance, topup, credits, setup, defaults, brand, sync brand, doctor, health check, is my org healthy]
|
|
7
|
-
checksum: sha256-
|
|
7
|
+
checksum: sha256-fab324491446026e1600ac531bfbb164c10d46a617e528e6886be74b7dbdb4b1
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# MyApiHQ
|
|
@@ -98,4 +98,28 @@ Each org gets a free preview subdomain (`*.makeautonomous.com`) usable before re
|
|
|
98
98
|
- API keys have format `hq_live_...` and are sent as `Authorization: Bearer <key>`.
|
|
99
99
|
- `org sync-brand` is async (scrapes the site, polls the job).
|
|
100
100
|
|
|
101
|
+
## Minting a least-privilege API key
|
|
102
|
+
|
|
103
|
+
A key's authority is inline and always a subset of the key that mints it, so
|
|
104
|
+
you can hand work a key that cannot exceed its job:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
myapi keys create --name ci --grant funnel:write,storage:read
|
|
108
|
+
myapi keys create --name readonly --grant '*:read' # read anything, write nothing
|
|
109
|
+
myapi keys create --name billing-fn --org <id> --grant email --spend-cap 25
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
- `--grant <list>` — `slot:read` / `slot:write`; a bare slot means write, `*`
|
|
113
|
+
means all. **Omitting `--grant` mints an unrestricted key.**
|
|
114
|
+
- `--org <id>` — lock it to one org. Omit for account-wide.
|
|
115
|
+
- `--spend-cap <usd>` — hard ceiling; `0` means the key cannot spend at all.
|
|
116
|
+
- `keys revoke-all --kind function|manual|account` narrows the kill switch.
|
|
117
|
+
|
|
118
|
+
## Org profile fields
|
|
119
|
+
|
|
120
|
+
`myapi org create <name>` also takes `--tagline`, `--description`,
|
|
121
|
+
`--business-sector` and `--logo-url`. They populate the org's public profile
|
|
122
|
+
and the funnel created alongside it, so setting them at create avoids editing
|
|
123
|
+
two places later.
|
|
124
|
+
|
|
101
125
|
Run `myapi --help` or `myapi <command> --help` for full flag reference.
|
|
@@ -4,7 +4,7 @@ version: 1.0.0
|
|
|
4
4
|
description: >
|
|
5
5
|
Saved audiences = named Goldfox-filter snapshots over the people or company database. Build a target list once, name it, reuse it across campaigns, refresh to re-evaluate against current data. The persistence layer on top of my-people-api + my-company-api.
|
|
6
6
|
triggers: [audience, segment, target list, saved filter, goldfox, lead list, abm list, refresh, members, prospect database]
|
|
7
|
-
checksum: sha256-
|
|
7
|
+
checksum: sha256-a2c7142e880932ac2aa53cdb29b8632ce2c4d5ef33c3f8b6df705f7e987ab6af
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# MyAudienceAPI
|
|
@@ -70,7 +70,7 @@ Allowed values:
|
|
|
70
70
|
<!-- generated:start -->
|
|
71
71
|
| Command | What it does |
|
|
72
72
|
|---|---|
|
|
73
|
-
| `myapi audience create <name> --
|
|
73
|
+
| `myapi audience create <name> --from <people\|company> --filter '<json>' [--description <text>]` | Save a Goldfox filter as a named audience; returns id + initial member_count |
|
|
74
74
|
| `myapi audience list` | List all audiences in the org |
|
|
75
75
|
| `myapi audience get <id>` | Single audience (name, filter, member_count, timestamps) |
|
|
76
76
|
| `myapi audience update <id> [--name <x>] [--description <y>] [--filter '<json>']` | Patch name/description/filter; member_count re-evaluates if filter changes |
|
|
@@ -84,7 +84,7 @@ Allowed values:
|
|
|
84
84
|
```bash
|
|
85
85
|
# 1. Create the audience
|
|
86
86
|
AID=$(myapi audience create "EU decision makers w/ corporate emails" \
|
|
87
|
-
--
|
|
87
|
+
--from people \
|
|
88
88
|
--filter '{"seniority":["c_level","vp_director"],"country":["DE","FR","GB"],"email_type":["corporate"]}' \
|
|
89
89
|
--json | jq -r .id)
|
|
90
90
|
|
|
@@ -108,7 +108,7 @@ myapi audience delete $AID
|
|
|
108
108
|
```bash
|
|
109
109
|
# Build with quality controls — definitive links + registered companies + careers signal
|
|
110
110
|
AID=$(myapi audience create "EU growth-stage decision makers" \
|
|
111
|
-
--
|
|
111
|
+
--from people \
|
|
112
112
|
--filter '{"seniority":["c_level","vp_director"],"country":["DE","FR","GB"],"email_type":["corporate"],"min_link_confidence":0.9,"has_careers_page":true,"is_registered_entity":true}' \
|
|
113
113
|
--json | jq -r .id)
|
|
114
114
|
|
|
@@ -123,7 +123,7 @@ myapi audience refresh $AID
|
|
|
123
123
|
|
|
124
124
|
```bash
|
|
125
125
|
myapi audience create "EU growth-stage SaaS accounts" \
|
|
126
|
-
--
|
|
126
|
+
--from company \
|
|
127
127
|
--filter '{"country":["DE","FR","GB","NL"],"has_careers_page":true,"has_decision_maker":true,"is_registered_entity":true,"min_source_count":3}'
|
|
128
128
|
```
|
|
129
129
|
<!-- llm:end -->
|
|
@@ -4,7 +4,7 @@ version: 1.0.0
|
|
|
4
4
|
description: >
|
|
5
5
|
Add authentication to apps you build on MyAPI — a managed OIDC identity provider for your app's END USERS (à la Kinde/Auth0). One auth tenant per org; register OIDC clients; sign users in with managed Google or the hosted login page; verify RS256 tokens against the tenant JWKS.
|
|
6
6
|
triggers: [auth, authentication, login, sign-in, oidc, oauth, jwt, jwks, sso, google sign-in, user accounts, identity provider, kinde, auth0, clerk]
|
|
7
|
-
checksum: sha256-
|
|
7
|
+
checksum: sha256-5eeacc463d7323f85a330639b7073f735ccc80bddfb8217c9c15c56989b8a99a
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# MyAuthAPI
|
|
@@ -114,4 +114,11 @@ myapi auth client list
|
|
|
114
114
|
`http://localhost…` for local dev).
|
|
115
115
|
- `402 INSUFFICIENT_FUNDS` = empty wallet → `myapi billing topup <amount>` (or keep it funded automatically: `myapi billing auto-recharge set`). `402 SPEND_CAP_EXCEEDED` = you hit your account spend ceiling → raise it with `myapi billing spend-cap`.
|
|
116
116
|
|
|
117
|
+
## Anonymous accounts
|
|
118
|
+
|
|
119
|
+
`myapi account setup --anonymous` skips registration and creates an account
|
|
120
|
+
with no email — for throwaway or machine-owned orgs. It cannot receive
|
|
121
|
+
password resets or magic links, so attach a real identity before anything
|
|
122
|
+
depends on it. `myapi status` shows `Type: anonymous`.
|
|
123
|
+
|
|
117
124
|
**End-to-end example:** `examples/authenticated-app/` walks the full seam — hosted login → token verification → per-user KV record → deployed container — including the parts that cost real users hours (verify the id_token for identity; the access token is a bearer credential for `<issuer>/userinfo`).
|
|
@@ -4,7 +4,7 @@ version: 1.0.0
|
|
|
4
4
|
description: >
|
|
5
5
|
Company database backed by the Goldfox crawl. Filter companies by Goldfox confidence tier, country/TLD consistency, behavioral page signals (has_careers_page, has_investors_page, has_shop_page, has_c_level, has_decision_maker), legal-entity status, headcount, and source-URL count. Account-based targeting and B2B firmographics.
|
|
6
6
|
triggers: [companies, accounts, firmographics, abm, search, filter, goldfox, careers signal, investors, c-level, shop, b2b targeting]
|
|
7
|
-
checksum: sha256-
|
|
7
|
+
checksum: sha256-4754de8a66bf13e7e2f2a23acc407ccec147e142abf8adc670ae7962ca860a74
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# MyCompanyAPI
|
|
@@ -90,7 +90,7 @@ myapi company get auroracloud.com --include-people 5
|
|
|
90
90
|
```bash
|
|
91
91
|
# Save filter as audience (companies)
|
|
92
92
|
AID=$(myapi audience create "EU growth-stage SaaS" \
|
|
93
|
-
--
|
|
93
|
+
--from company \
|
|
94
94
|
--filter '{"country":["DE","FR","GB","NL"],"has_careers_page":true,"has_decision_maker":true,"min_source_count":3}' \
|
|
95
95
|
--json | jq -r .id)
|
|
96
96
|
|
|
@@ -105,6 +105,6 @@ myapi audience members $AID --limit 50 --json > accounts.json
|
|
|
105
105
|
- `seniority`, `email_type`, and `min_link_confidence` are people-only — passing them on company search is silently ignored.
|
|
106
106
|
- `include_people` only works on company search/get; people-source already embeds company by default.
|
|
107
107
|
- `keyword` is a substring match on the company's **domain** — use `--keyword stripe` to find domains containing "stripe".
|
|
108
|
-
- For a persistent account list, use `my-audience-api` with `--
|
|
108
|
+
- For a persistent account list, use `my-audience-api` with `--from company`.
|
|
109
109
|
|
|
110
110
|
Run `myapi company --help` for full flag reference.
|
|
@@ -4,7 +4,7 @@ version: 1.0.0
|
|
|
4
4
|
description: >
|
|
5
5
|
Run containers on demand — long-running services, background workers, and scheduled jobs. The heavier-duty sibling of edge functions, for native deps and long execution.
|
|
6
6
|
triggers: [container, cloud run, dynamic app, custom domain app, service, worker, scheduled job, deploy container, docker image]
|
|
7
|
-
checksum: sha256-
|
|
7
|
+
checksum: sha256-47eda6baa9055dadbd3e9d04df9fc425f1a7e96a9cd80c971c4951b97f1e94ff
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# MyContainerAPI
|
|
@@ -16,7 +16,11 @@ A container runs a pre-built image on managed cloud infrastructure. Three types:
|
|
|
16
16
|
The lifecycle is **create → deploy → (optionally) bind a custom domain**.
|
|
17
17
|
|
|
18
18
|
- `create` registers the container and issues a **scoped API key**, returned once. The running container receives it as the `MYAPI_KEY` env var, so your code calls other MyAPI slots with no token handling. Deploy rotates this key.
|
|
19
|
-
- `deploy`
|
|
19
|
+
- `deploy` takes **either** a pre-built image reference **or** a source
|
|
20
|
+
directory. `--source ./dir` tars the directory, builds it server-side
|
|
21
|
+
(typically ~4 minutes) and deploys the result — **no Docker on your machine,
|
|
22
|
+
no registry account, no image to push**. If you can write a Dockerfile you
|
|
23
|
+
can deploy; you do not need to be able to run one.
|
|
20
24
|
- `domain` puts the container on a **custom domain** — how you serve a dynamic app at `app.yourbrand.com`.
|
|
21
25
|
|
|
22
26
|
### Deploying safely — NOT YET POSSIBLE ON THIS PLATFORM
|
|
@@ -74,10 +78,16 @@ Get it right:
|
|
|
74
78
|
myapi container create --name api --type service --port 8080
|
|
75
79
|
# → prints a scoped API key ONCE — save it if your code needs it
|
|
76
80
|
|
|
77
|
-
#
|
|
78
|
-
#
|
|
81
|
+
# 2a. Deploy from source — MyAPI builds it. No local Docker required.
|
|
82
|
+
# Takes ~4 minutes; the CLI polls until it is live.
|
|
83
|
+
myapi container deploy <id> --source ./my-app
|
|
84
|
+
|
|
85
|
+
# 2b. Or ship an image you already built and pushed.
|
|
79
86
|
myapi container deploy <id> registry.example.com/my-app:v1
|
|
80
87
|
|
|
88
|
+
# Either way this takes 100% of traffic immediately — there is no staging
|
|
89
|
+
# step, so verify on a non-production container FIRST.
|
|
90
|
+
|
|
81
91
|
# 3. Check what you actually shipped. Assert on content: a build whose
|
|
82
92
|
# frontend never bundled still binds its port and returns 200.
|
|
83
93
|
curl -s https://<your-domain>/ | grep -q 'assets/' || echo "BROKEN BUILD"
|
|
@@ -114,6 +124,13 @@ way that looks like an application bug.
|
|
|
114
124
|
`create` and cannot be changed by `deploy`.** Passing them to `deploy` does
|
|
115
125
|
nothing. Recreate the container to change them.
|
|
116
126
|
|
|
127
|
+
### Keeping a service warm
|
|
128
|
+
|
|
129
|
+
`--min-instances 1` at create stops a `service` scaling to zero, which removes
|
|
130
|
+
cold starts at the cost of running continuously. Leave it at the default `0`
|
|
131
|
+
unless latency on the first request actually matters — a scaled-to-zero
|
|
132
|
+
service costs nothing while idle.
|
|
133
|
+
|
|
117
134
|
## Notes
|
|
118
135
|
|
|
119
136
|
- The scoped API key is shown **once** at create, and again (rotated) on every deploy. Save it if your code needs it.
|
|
@@ -122,6 +139,10 @@ way that looks like an application bug.
|
|
|
122
139
|
the same stream and share the `--tail` budget, so raise `--tail` with it.
|
|
123
140
|
- Custom domains need a deployed container **and** a MyAPI-registered parent domain — see `my-domain-api`.
|
|
124
141
|
- Containers are for dynamic apps and native deps. For static sites use `my-funnel-api`; for edge functions use `my-function-api`.
|
|
142
|
+
- **`--source` does not honour `.dockerignore`.** It tars the directory as-is,
|
|
143
|
+
so a `node_modules` can push the context past the limit and fail as
|
|
144
|
+
`invalid_json_response`. Build the tarball yourself and pass
|
|
145
|
+
`--source ctx.tar.gz`, or keep the directory clean.
|
|
125
146
|
|
|
126
147
|
Run `myapi container --help` for the full flag reference.
|
|
127
148
|
|
|
@@ -4,7 +4,7 @@ version: 1.0.0
|
|
|
4
4
|
description: >
|
|
5
5
|
The canonical store of engaged contacts + companies for an org. Auto-ingests from inbound webhooks via a configurable dot-path. Fixed lifecycle_stage enum (cold | warm | qualified | customer | churned). Append-only event timeline with reserved kinds. Soft delete + restore. Promote-from-Goldfox closes the discovery → engagement loop.
|
|
6
6
|
triggers: [crm, contact, company, lead, engagement, pipeline, lifecycle, qualified, customer, webhook ingest, promote]
|
|
7
|
-
checksum: sha256-
|
|
7
|
+
checksum: sha256-dfadb20670d9d978503549d330c2c9717fbe6d13ac35b53d9e1a8874d2136fde
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# MyCRMAPI
|
|
@@ -38,7 +38,7 @@ Move stage with `myapi crm contacts update <id> --stage qualified`. Every stage
|
|
|
38
38
|
goldfox | email | pixel | webhook | manual
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
Set automatically from how the contact entered. Filter with `--
|
|
41
|
+
Set automatically from how the contact entered. Filter with `--origin manual` (added by hand) vs `--origin goldfox` (from outreach).
|
|
42
42
|
|
|
43
43
|
### Event timeline — reserved kinds
|
|
44
44
|
|
|
@@ -75,7 +75,7 @@ A contact promoted from Goldfox carries a `goldfox_person_id`. In v2 the GET res
|
|
|
75
75
|
|
|
76
76
|
### Search filter — re-engagement semantics
|
|
77
77
|
|
|
78
|
-
`--max-last-engagement-days N` returns contacts last engaged *more than* N days ago, and intentionally **includes contacts with no engagement at all** (promoted-but-never-emailed Goldfox leads) — the natural targets of a re-engagement campaign. To separate "never tried" from "tried and went cold," layer `--
|
|
78
|
+
`--max-last-engagement-days N` returns contacts last engaged *more than* N days ago, and intentionally **includes contacts with no engagement at all** (promoted-but-never-emailed Goldfox leads) — the natural targets of a re-engagement campaign. To separate "never tried" from "tried and went cold," layer `--origin goldfox` or post-filter the JSON.
|
|
79
79
|
|
|
80
80
|
### Failure modes
|
|
81
81
|
|
|
@@ -92,7 +92,7 @@ A contact promoted from Goldfox carries a `goldfox_person_id`. In v2 the GET res
|
|
|
92
92
|
| Command | What it does |
|
|
93
93
|
|---|---|
|
|
94
94
|
| `myapi crm contacts list [--limit N] [--offset N]` | List all contacts (newest engagement first) |
|
|
95
|
-
| `myapi crm contacts search [--stage ...] [--
|
|
95
|
+
| `myapi crm contacts search [--stage ...] [--origin ...] [--email ...] [--min/max-last-engagement-days N]` | Filter contacts |
|
|
96
96
|
| `myapi crm contacts create <email> [--first-name ...] [--last-name ...] [--stage ...] [--custom-json ...]` | Manually create (source='manual') |
|
|
97
97
|
| `myapi crm contacts get <id>` | Fetch one contact (with embedded Goldfox enrichment when available) |
|
|
98
98
|
| `myapi crm contacts update <id> [--stage ...] [...]` | Patch fields. Stage change emits `stage_changed` event |
|
|
@@ -138,7 +138,7 @@ myapi crm contacts update <id> --stage customer
|
|
|
138
138
|
myapi crm contacts events <id>
|
|
139
139
|
|
|
140
140
|
# What landed in CRM from this Stripe webhook?
|
|
141
|
-
myapi crm contacts search --
|
|
141
|
+
myapi crm contacts search --origin webhook --json \
|
|
142
142
|
| jq '.contacts[] | {email, last_engagement_at}'
|
|
143
143
|
```
|
|
144
144
|
|
|
@@ -151,7 +151,7 @@ URL=$(echo "$WH" | jq -r .url)
|
|
|
151
151
|
echo "Point Stripe at: $URL"
|
|
152
152
|
|
|
153
153
|
# Later, after Stripe fires...
|
|
154
|
-
myapi crm contacts search --
|
|
154
|
+
myapi crm contacts search --origin webhook --email "$STRIPE_CUSTOMER_EMAIL"
|
|
155
155
|
myapi crm contacts events <id> --kind webhook_received
|
|
156
156
|
```
|
|
157
157
|
<!-- llm:end -->
|
|
@@ -4,7 +4,7 @@ version: 1.0.0
|
|
|
4
4
|
description: >
|
|
5
5
|
Per-org KV store with named namespaces, JSON values up to 256 KB, prefix-scan listing, and compare-and-swap via etag. The substrate for any stateful agent-built app on MyAPI — user tables, session stores, idempotency keys, per-user lookup maps.
|
|
6
6
|
triggers: [database, kv, key value, namespace, store, state, etag, cas, session, idempotency]
|
|
7
|
-
checksum: sha256-
|
|
7
|
+
checksum: sha256-924071245c33bf3e43f085fbd756af003e19c990f4522f658de33f42504452d7
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# MyDatabaseAPI
|
|
@@ -104,6 +104,27 @@ myapi database get "by-email:$EMAIL" --ns users --json | jq -r .value
|
|
|
104
104
|
- **Eventual `key_count`.** The `keys` field on a namespace is approximate; don't use it for strict pagination math.
|
|
105
105
|
- **Free in v1.** Metered later if usage shows a need. Cost discipline still applies — store data, not blobs.
|
|
106
106
|
|
|
107
|
+
|
|
108
|
+
## Calling this from deployed code (HTTP)
|
|
109
|
+
|
|
110
|
+
The CLI is not what runs in production — a deployed function or container calls
|
|
111
|
+
the HTTP API directly. That surface was previously only discoverable by
|
|
112
|
+
grepping the CLI bundle, which cost one team an hour per slot.
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
base https://api.myapihq.com
|
|
116
|
+
path /database/orgs/{org_id}/namespaces/{ns}/keys/{key}
|
|
117
|
+
auth Authorization: Bearer <api key>
|
|
118
|
+
(inside a function: env.__MYAPI_KEY · inside a container: env.MYAPI_KEY)
|
|
119
|
+
body writes take {"value": <json>} — the value is WRAPPED
|
|
120
|
+
reply { "success": true, "data": …, "error": null, "meta": {…} }
|
|
121
|
+
Unwrap `data`. On failure `success` is false and `error` is
|
|
122
|
+
{ code, message }.
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**The org id goes in the PATH, not a header.** There is no `X-Org-Id`.
|
|
126
|
+
**Base URLs differ per slot** — do not assume one host for everything.
|
|
127
|
+
|
|
107
128
|
Run `myapi database --help` for inline reference.
|
|
108
129
|
|
|
109
130
|
**End-to-end example:** `examples/authenticated-app/` walks the full seam — hosted login → token verification → per-user KV record → deployed container — including the parts that cost real users hours (KV writes must be wrapped as `{"value": …}`).
|
|
@@ -4,7 +4,7 @@ version: 1.0.0
|
|
|
4
4
|
description: >
|
|
5
5
|
Register new domains and manage edge settings. Required before a funnel can go live on a custom URL.
|
|
6
6
|
triggers: [domain, register domain, dns, custom domain, edge, cdn, security level, browser check, renew, namecheap]
|
|
7
|
-
checksum: sha256-
|
|
7
|
+
checksum: sha256-6a686b453528c69dcc791db409c04a514422951abf333c8feed7c614311815cb
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# MyDomainAPI
|
|
@@ -116,4 +116,21 @@ Set `essentially_off` + `browser-check=off` to allow AI crawlers and training bo
|
|
|
116
116
|
- All commands default to `--org` from your saved config (set with `myapi config set-org <id>`).
|
|
117
117
|
- `402 INSUFFICIENT_FUNDS` = empty wallet → `myapi billing topup <amount>` (or keep it funded automatically: `myapi billing auto-recharge set`). `402 SPEND_CAP_EXCEEDED` = you hit your account spend ceiling → raise it with `myapi billing spend-cap`.
|
|
118
118
|
|
|
119
|
+
## DNS record flags
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
myapi domain records create <domain> --type A --name @ --content 1.2.3.4 --ttl 300
|
|
123
|
+
myapi domain records create <domain> --type MX --name @ --content mx.x.com --priority 10
|
|
124
|
+
myapi domain records create <domain> --type CNAME --name app --content x.com --proxied
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
- `--ttl <n>` — seconds; default `1` meaning "automatic". Explicit range 60–86400.
|
|
128
|
+
- `--priority <n>` — MX only, and required for it (typical `10`).
|
|
129
|
+
- `--proxied` — route through the edge proxy (A/AAAA/CNAME only). Off means
|
|
130
|
+
the record resolves straight to your origin, exposing its address.
|
|
131
|
+
- `myapi domain assign <domain> --no-www` skips the `www` → apex redirect.
|
|
132
|
+
- `--force` on assign re-points a domain already bound elsewhere. It is the
|
|
133
|
+
reassign path, so pass `--org` explicitly and check `domain list --filter all`
|
|
134
|
+
first.
|
|
135
|
+
|
|
119
136
|
Run `myapi domain --help` or `myapi domain <subcommand> --help` for full flag reference.
|
|
@@ -4,7 +4,7 @@ version: 1.0.0
|
|
|
4
4
|
description: >
|
|
5
5
|
Send transactional and bulk email from your own domain. Create mailboxes, send/receive messages, generate AI templates, and manage warmup.
|
|
6
6
|
triggers: [email, mailbox, send email, transactional email, template, warmup, inbox, outbox, ses, sender reputation]
|
|
7
|
-
checksum: sha256-
|
|
7
|
+
checksum: sha256-aa22381613affcff041a8d51d2acb2ba657fecefc97f4feba45958bcc11b2e06
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# MyEmailAPI
|
|
@@ -66,4 +66,39 @@ myapi email warmup stats --address hello@yourdomain.com
|
|
|
66
66
|
- Sending is opt-in per mailbox. Newly-created mailboxes can receive but not send until `activate-sending` runs.
|
|
67
67
|
- Templates are org-scoped. Set a default org once: `myapi config set-org <id>`.
|
|
68
68
|
|
|
69
|
+
|
|
70
|
+
## Which name mail actually lives on
|
|
71
|
+
|
|
72
|
+
Two things that read as contradictory and are not:
|
|
73
|
+
|
|
74
|
+
- **Mailbox addresses are on the APEX** — `contact@yourdomain.com`, never
|
|
75
|
+
`contact@mail.yourdomain.com`. `mail.<domain>` is the *sending identity* that
|
|
76
|
+
`myapi domain email-setup` provisions, not a mailbox namespace. Creating a
|
|
77
|
+
mailbox on the subdomain fails with `DOMAIN_NOT_OWNED`.
|
|
78
|
+
- **Registration and assign put `MX`, `SPF` and `DMARC` on the apex** whether or
|
|
79
|
+
not you run `email-setup`. So "apex is never touched" — which describes
|
|
80
|
+
`email-setup` specifically — is not true of the domain as a whole. If you plan
|
|
81
|
+
to run Google Workspace or another provider on the apex, check the existing
|
|
82
|
+
records first with `myapi domain records <domain>`.
|
|
83
|
+
|
|
84
|
+
## Calling this from deployed code (HTTP)
|
|
85
|
+
|
|
86
|
+
The CLI is not what runs in production — a deployed function or container calls
|
|
87
|
+
the HTTP API directly. That surface was previously only discoverable by
|
|
88
|
+
grepping the CLI bundle, which cost one team an hour per slot.
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
base https://api.myemailapi.com ← not the gateway
|
|
92
|
+
path /email/mailboxes · /email/orgs/{org_id}/messages/send
|
|
93
|
+
auth Authorization: Bearer <api key>
|
|
94
|
+
(inside a function: env.__MYAPI_KEY · inside a container: env.MYAPI_KEY)
|
|
95
|
+
body application/json
|
|
96
|
+
reply { "success": true, "data": …, "error": null, "meta": {…} }
|
|
97
|
+
Unwrap `data`. On failure `success` is false and `error` is
|
|
98
|
+
{ code, message }.
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**The org id goes in the PATH, not a header.** There is no `X-Org-Id`.
|
|
102
|
+
**Base URLs differ per slot** — do not assume one host for everything.
|
|
103
|
+
|
|
69
104
|
Run `myapi email --help` or `myapi email <namespace> --help` for full flag reference.
|
|
@@ -4,7 +4,7 @@ version: 1.0.0
|
|
|
4
4
|
description: >
|
|
5
5
|
Deploy JavaScript functions to the MyAPI edge runtime. Register a function, upload a single-file JS bundle, get a live HTTP invocation URL or run it on a cron schedule. Each function gets a scoped capability key for cross-slot calls.
|
|
6
6
|
triggers: [function, deploy function, edge function, serverless, cloudflare worker, cron, scoped api key, capability key, invocation url, bundle]
|
|
7
|
-
checksum: sha256-
|
|
7
|
+
checksum: sha256-1ef76e07c9fb4f295b491224261b5719314f15d3645c32e6e7b443a7fdaf95c6
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# MyFunctionAPI
|
|
@@ -78,9 +78,36 @@ myapi fn get fn_abc123
|
|
|
78
78
|
myapi fn delete fn_abc123
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
+
### The scoped API key is already in your function — as `__MYAPI_KEY`
|
|
82
|
+
|
|
83
|
+
**Two leading underscores, and it is injected for you.** Verified by probing a
|
|
84
|
+
deployed function: `Object.keys(env)` returns exactly `["__MYAPI_KEY"]`, and
|
|
85
|
+
`MYAPI_KEY` (no underscores) is NOT present.
|
|
86
|
+
|
|
87
|
+
```js
|
|
88
|
+
export default {
|
|
89
|
+
async fetch(request, env) {
|
|
90
|
+
const r = await fetch('https://api.myapihq.com/database/orgs/<org>/namespaces/app/keys/x', {
|
|
91
|
+
headers: { Authorization: `Bearer ${env.__MYAPI_KEY}` },
|
|
92
|
+
});
|
|
93
|
+
return new Response(await r.text());
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**Do not capture the key printed at `fn create` and set it yourself.** Every
|
|
99
|
+
`fn deploy` rotates it, so a manually-set copy goes stale on the next deploy
|
|
100
|
+
and the function starts returning 502 with nothing in the deploy output to
|
|
101
|
+
explain it. The injected `__MYAPI_KEY` is always current.
|
|
102
|
+
|
|
103
|
+
Note the name differs from containers, which receive `MYAPI_KEY` without the
|
|
104
|
+
underscores. Both verified 2026-07-28.
|
|
105
|
+
|
|
81
106
|
### Using the scoped API key
|
|
82
107
|
|
|
83
108
|
```bash
|
|
109
|
+
# You do NOT need this — env.__MYAPI_KEY is injected and always current.
|
|
110
|
+
# Shown only for calling the function's slots from OUTSIDE the function.
|
|
84
111
|
# Save the API key returned at create/deploy time
|
|
85
112
|
SCOPED_KEY="hq_live_..."
|
|
86
113
|
|
|
@@ -100,5 +127,6 @@ curl -H "Authorization: Bearer $SCOPED_KEY" \
|
|
|
100
127
|
- The bundle is a **single JavaScript file** (≤4MB). Bundle your dependencies before deploy (esbuild/rollup/etc.).
|
|
101
128
|
- `--cron` is set at create time; the trigger type is fixed for the function's lifetime.
|
|
102
129
|
- Deploy rotates the scoped API key on every call — re-capture the printed value if other systems use it.
|
|
130
|
+
- `myapi fn env <id> --set KEY=VALUE,OTHER=VALUE` sets several secrets in one call instead of one command each.
|
|
103
131
|
|
|
104
132
|
Run `myapi fn --help` or `myapi fn <subcommand> --help` for full flag reference.
|
|
@@ -4,7 +4,7 @@ version: 1.0.0
|
|
|
4
4
|
description: >
|
|
5
5
|
Create and publish websites (funnels) to the edge. Push raw HTML to any slug and it goes live instantly on your org's domain or preview subdomain.
|
|
6
6
|
triggers: [funnel, landing page, website, page, publish, push, slug, html, edge, preview subdomain, makeautonomous]
|
|
7
|
-
checksum: sha256-
|
|
7
|
+
checksum: sha256-849afbb7c2c60ea88c3476d50bf51289b77cedc819a0c2b69787075ff9c23b4b
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# MyFunnelAPI
|
|
@@ -33,7 +33,7 @@ Every funnel auto-provisions a **webhook** at creation (`org_webhook_id`), and e
|
|
|
33
33
|
| `myapi funnel push [slug]` | Push HTML from stdin to a slug (default: `/`). **Overwrites** an existing page — refused without `--force`. `--json` prints `{slug, subdomain_url, overwritten, org_id, funnel_id}` |
|
|
34
34
|
| `myapi funnel publish <dir>` | Upload a whole directory as the funnel's site (`--env dev\|prod`, default prod; `--api-fn <id>`; `--json`). Prod refuses to replace a live site without `--force` |
|
|
35
35
|
| `myapi funnel pages [funnel_id]` | List the pages currently published to a funnel |
|
|
36
|
-
| `myapi funnel form [funnel_id]` | Emit canonical form HTML (
|
|
36
|
+
| `myapi funnel form [funnel_id]` | Emit canonical form HTML (`--capture-to`, `--cta`, `--success`, `--honeypot`) |
|
|
37
37
|
| `myapi funnel verify [slug]` | Verify a published page is reachable + check links/webhooks |
|
|
38
38
|
<!-- generated:end -->
|
|
39
39
|
|
|
@@ -83,7 +83,10 @@ Zero-config form (the happy path most agents want) — still pin the org + funne
|
|
|
83
83
|
|
|
84
84
|
```bash
|
|
85
85
|
myapi funnel create --name acme-demo --org <org_id>
|
|
86
|
-
myapi funnel form --slug join --fields email:required,name --funnel <funnel_id>
|
|
86
|
+
myapi funnel form --slug join --fields email:required,name --funnel <funnel_id> \
|
|
87
|
+
--cta "Join" --success "Thanks — check your inbox." --honeypot company_url > snippet.html
|
|
88
|
+
# --honeypot names a hidden field: bots fill it, humans never do, so a
|
|
89
|
+
# submission carrying it is dropped.
|
|
87
90
|
# paste snippet.html into your page (or pipe through funnel push):
|
|
88
91
|
cat page-with-snippet.html | myapi funnel push / --funnel <funnel_id>
|
|
89
92
|
# Submissions land in the funnel's auto-provisioned webhook → CRM upsert on `email` → any bound workflow fires.
|
|
@@ -4,7 +4,7 @@ version: 1.0.0
|
|
|
4
4
|
description: >
|
|
5
5
|
Hosted git repositories over HTTP. Create repos, read history (log/show/tree/blob/diff), and write atomically (commit/branch/tag/merge) — no clone needed. Real `git clone`/`push` also work over HTTPS with your API key as the password.
|
|
6
6
|
triggers: [git, repo, repository, clone, push, commit, branch, tag, merge, diff, version control, source control, vcs]
|
|
7
|
-
checksum: sha256-
|
|
7
|
+
checksum: sha256-417bafc3e56707f637937f98341d6200c8a9bb6ad5d0b13f84f7b6810e0340f5
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# MyGitAPI
|
|
@@ -119,4 +119,10 @@ surface never leaks which repos exist).
|
|
|
119
119
|
- **Limits.** A push body is capped at 100 MiB; per-repo size limits apply (a push past the cap is reported as a receive-pack failure).
|
|
120
120
|
- **Auth field.** git may put the API key in the username or password slot — both work. Embedding it in the URL (`https://x:$KEY@…`) avoids the interactive prompt but writes the API key into `.git/config`; use a credential helper for anything persistent.
|
|
121
121
|
|
|
122
|
+
## Commit authorship
|
|
123
|
+
|
|
124
|
+
`myapi git commit … --author-name "<n>" --author-email "<e>"` sets the commit
|
|
125
|
+
author. Without them the commit is attributed to the API key's account, which
|
|
126
|
+
makes every agent-written commit look like the same person.
|
|
127
|
+
|
|
122
128
|
Run `myapi git --help` for the full flag reference.
|
|
@@ -4,7 +4,7 @@ version: 1.0.0
|
|
|
4
4
|
description: >
|
|
5
5
|
Contact database backed by the Goldfox crawl. Filter people by Goldfox confidence tier, seniority, email type, country, link confidence, plus rich behavioral company signals (has_c_level, has_careers_page, has_decision_maker, etc.). The targeting layer for outbound campaigns.
|
|
6
6
|
triggers: [people, contacts, leads, prospects, search, filter, goldfox, decision-makers, c-level, b2b targeting, corporate email]
|
|
7
|
-
checksum: sha256-
|
|
7
|
+
checksum: sha256-1eb93087638966eee65fb7a88fe37baaa27a01dd5d97c1ef17387b1a36300c0e
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# MyPeopleAPI
|
|
@@ -88,7 +88,7 @@ myapi people get p_MTdlc2llY2xlLmZy.0
|
|
|
88
88
|
```bash
|
|
89
89
|
# Build the target audience (saved filter)
|
|
90
90
|
AID=$(myapi audience create "EU decision makers w/ careers signal" \
|
|
91
|
-
--
|
|
91
|
+
--from people \
|
|
92
92
|
--filter '{"seniority":["c_level","vp_director"],"country":["DE","FR","GB"],"email_type":["corporate"],"has_careers_page":true}' \
|
|
93
93
|
--json | jq -r .id)
|
|
94
94
|
|
|
@@ -100,7 +100,7 @@ myapi audience members $AID --limit 100 --json > targets.json
|
|
|
100
100
|
## Notes
|
|
101
101
|
|
|
102
102
|
- The dataset is the Goldfox crawl — multi-million-row corporate contact data with provenance signals. Filter quality matters: defaults to `confidence=high` gives 96.4% of rows by count, but it's the curated tier; widening with `confidence=low` brings UGC rows that need spot-checking.
|
|
103
|
-
- `seniority`, `email_type`, and `min_link_confidence` are people-only — silently ignored on `my-company-api` and on audiences with `--
|
|
103
|
+
- `seniority`, `email_type`, and `min_link_confidence` are people-only — silently ignored on `my-company-api` and on audiences with `--from company`.
|
|
104
104
|
- `keyword` matches the row's **domain**, not name/title. Use `--keyword acme` to find people whose domain contains "acme".
|
|
105
105
|
- For a persistent target list, use `my-audience-api` (snapshot the filter; re-evaluate on `audience refresh`).
|
|
106
106
|
|
|
@@ -4,7 +4,7 @@ version: 1.0.0
|
|
|
4
4
|
description: >
|
|
5
5
|
Tracking pixel + identity resolution for MyAPI funnels and email. Capture visits and events, resolve known users to anonymous sessions, stream interaction events for analytics. Pairs with mycrmapi for auto-ingest of pixel_visit events on known contacts.
|
|
6
6
|
triggers: [pixel, analytics, tracking, visit, event, identity, session, attribution, geo, open pixel]
|
|
7
|
-
checksum: sha256-
|
|
7
|
+
checksum: sha256-562f081ef28c0dae01045a4135f9d073d69c50899145e75c6c97fe75b974cb15
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# MyPixelAPI
|
|
@@ -83,6 +83,17 @@ myapi pixel audience
|
|
|
83
83
|
- **No write API for synthetic events** — the pixel records what the embedded JS/email-pixel observes. To inject custom timeline entries, use `myapi crm contacts/{id}/events` instead (when reserved-kind allows; today event writes are platform-only).
|
|
84
84
|
- **`my-crm-api` is the durable record.** Pixel data ages out at ~90 days; CRM events are permanent. If a behavioral signal matters for long-term targeting, promote it into the CRM.
|
|
85
85
|
|
|
86
|
+
## Linking a known identity
|
|
87
|
+
|
|
88
|
+
`myapi pixel identify <pixel_id>` attaches a known identity to an anonymous
|
|
89
|
+
visitor:
|
|
90
|
+
|
|
91
|
+
- `--email <addr>` — the address to link.
|
|
92
|
+
- `--external-id <id>` — your own user id, for joining back to your database.
|
|
93
|
+
|
|
94
|
+
Pass either or both. After this, `pixel identity <pixel_id>` resolves the
|
|
95
|
+
graph across the visitor's sessions.
|
|
96
|
+
|
|
86
97
|
Run `myapi pixel --help` for inline reference.
|
|
87
98
|
|
|
88
99
|
## Status
|
|
@@ -4,7 +4,7 @@ version: 1.0.0
|
|
|
4
4
|
description: >
|
|
5
5
|
Edge-hosted asset storage. Upload a local file of any content type directly, or have the server fetch from a public URL. Each asset gets a stable public CDN URL.
|
|
6
6
|
triggers: [storage, upload, ingest, asset, cdn, image hosting, file upload, get-url, download, public url]
|
|
7
|
-
checksum: sha256-
|
|
7
|
+
checksum: sha256-9172b0d8590a3102ce35b94ef48015ec36c624ab9bcc37fe0f7efa15bc54cf62
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# MyStorageAPI
|
|
@@ -89,8 +89,37 @@ Both produce identical asset records — `list` doesn't distinguish.
|
|
|
89
89
|
|
|
90
90
|
## Notes
|
|
91
91
|
|
|
92
|
-
- Assets are public
|
|
92
|
+
- **Assets are public, permanently, with no auth.** Anyone with the URL can
|
|
93
|
+
fetch it; there is no private mode, no signed URL, and no revocation. The id
|
|
94
|
+
being long and random is **not** access control — treat the URL as public the
|
|
95
|
+
moment it exists.
|
|
96
|
+
- **For personal or regulated data, encrypt before upload.** Storage only ever
|
|
97
|
+
sees ciphertext. A team shipping Swiss lease documents (names, dates of
|
|
98
|
+
birth, permit type, IBAN) used AES-256-GCM envelope encryption with a
|
|
99
|
+
per-document data key wrapped under a master key held in function secrets.
|
|
100
|
+
That is the pattern to copy until private assets exist.
|
|
93
101
|
- Delete is immediate and unrecoverable — run `myapi storage list` first to confirm the asset, pass `--org` explicitly, and pass `--yes` in non-interactive runs.
|
|
94
102
|
- The URL is permanent until you `myapi storage delete <id>` — embed it freely.
|
|
95
103
|
|
|
104
|
+
|
|
105
|
+
## Calling this from deployed code (HTTP)
|
|
106
|
+
|
|
107
|
+
The CLI is not what runs in production — a deployed function or container calls
|
|
108
|
+
the HTTP API directly. That surface was previously only discoverable by
|
|
109
|
+
grepping the CLI bundle, which cost one team an hour per slot.
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
base https://api.mystorageapi.com ← not the gateway
|
|
113
|
+
path /storage/orgs/{org_id}/assets/upload (multipart, field: file)
|
|
114
|
+
auth Authorization: Bearer <api key>
|
|
115
|
+
(inside a function: env.__MYAPI_KEY · inside a container: env.MYAPI_KEY)
|
|
116
|
+
body multipart/form-data
|
|
117
|
+
reply { "success": true, "data": …, "error": null, "meta": {…} }
|
|
118
|
+
Unwrap `data`. On failure `success` is false and `error` is
|
|
119
|
+
{ code, message }.
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**The org id goes in the PATH, not a header.** There is no `X-Org-Id`.
|
|
123
|
+
**Base URLs differ per slot** — do not assume one host for everything.
|
|
124
|
+
|
|
96
125
|
Run `myapi storage --help` for full flag reference.
|
|
@@ -4,7 +4,7 @@ version: 1.0.0
|
|
|
4
4
|
description: >
|
|
5
5
|
Agent-task queue — file units of work, rank them, claim under a lease, then resolve, fail, or cancel. The agent-loop hot path.
|
|
6
6
|
triggers: [task, task queue, agent loop, work queue, claim task, resolve task, lease, backlog, to-do, assignee]
|
|
7
|
-
checksum: sha256-
|
|
7
|
+
checksum: sha256-ceb6cdfffe465d8b0cd232eaa16868c1b8c8b10288f1cf9b4174fdd48a8d2c18
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# MyTaskAPI
|
|
@@ -71,4 +71,12 @@ myapi task create "Ship once payment clears" \
|
|
|
71
71
|
- `resolve` unblocks dependents; `fail` cascades to dependents that can never proceed.
|
|
72
72
|
- `resolve_on` matches platform events. Today few event kinds are emitted in production — verify the kind exists before relying on it.
|
|
73
73
|
|
|
74
|
+
## Idempotency and provenance
|
|
75
|
+
|
|
76
|
+
- `--dedup-key <k>` — creating a task with a key that already exists returns
|
|
77
|
+
the existing task instead of a duplicate. Use it whenever a task is created
|
|
78
|
+
from a retryable event, which for an agent is nearly always.
|
|
79
|
+
- `--origin <s>` — records what created the task, and filters `task list`.
|
|
80
|
+
(Formerly `--source`, which still works and is undocumented.)
|
|
81
|
+
|
|
74
82
|
Run `myapi task --help` for the full flag reference.
|
|
@@ -4,7 +4,7 @@ version: 1.0.0
|
|
|
4
4
|
description: >
|
|
5
5
|
Inbound webhook endpoints for non-funnel sources — Stripe, GitHub, custom services. Funnel forms use the my-funnel-api proxy.
|
|
6
6
|
triggers: [webhook, inbound, receiver, stripe events, github webhook, slack notification, delivery, payload, event ingest]
|
|
7
|
-
checksum: sha256-
|
|
7
|
+
checksum: sha256-17b358d780333cabe76cb01df3be3c3f11db10a2b068449bcf9e10e2ed89393d
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# MyWebhookAPI
|
|
@@ -97,4 +97,15 @@ The form sends `{name, email, message}` → webhook stores it → workflow runs
|
|
|
97
97
|
- Failed workflow runs don't affect the delivery record — the inbound POST is always saved.
|
|
98
98
|
- Inbound responses: `200` on success, `4xx` if the endpoint is missing or body isn't valid JSON.
|
|
99
99
|
|
|
100
|
+
## Auto-ingest and forwarding
|
|
101
|
+
|
|
102
|
+
- `--crm-email-path <dot-path>` — where to find the email in an incoming
|
|
103
|
+
payload, so submissions become CRM contacts automatically. Default `email`
|
|
104
|
+
(top level). Stripe: `data.object.customer_email`. GitHub: `sender.email`.
|
|
105
|
+
An empty string disables ingest for that endpoint.
|
|
106
|
+
- `--forward-url <url>` — POST a copy of every delivery onward. The forward
|
|
107
|
+
status is recorded on the delivery, so a failing forward is visible in
|
|
108
|
+
`webhook deliveries` rather than silent.
|
|
109
|
+
- `--description <text>` — free text, shown in `webhook list`.
|
|
110
|
+
|
|
100
111
|
Run `myapi webhook --help` for full flag reference.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@myapihq/cli",
|
|
3
3
|
"license": "Apache-2.0",
|
|
4
|
-
"version": "2.7.
|
|
4
|
+
"version": "2.7.2",
|
|
5
5
|
"description": "MyAPI command-line interface",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -37,11 +37,12 @@
|
|
|
37
37
|
"lint:request-fields": "node scripts/lint-request-fields.js",
|
|
38
38
|
"audit:doctor": "npm run build && node scripts/audit-doctor.js",
|
|
39
39
|
"lint:docs": "node scripts/lint-docs.js",
|
|
40
|
+
"lint:skill-coverage": "node scripts/lint-skill-coverage.js",
|
|
40
41
|
"lint:skills": "node scripts/copy-skills.js && node scripts/lint-skills.js",
|
|
41
42
|
"lint:skills:strict": "node scripts/copy-skills.js && node scripts/lint-skills.js --strict"
|
|
42
43
|
},
|
|
43
44
|
"dependencies": {
|
|
44
|
-
"@myapihq/sdk": "^2.7.
|
|
45
|
+
"@myapihq/sdk": "^2.7.2"
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|
|
47
48
|
"@types/node": "^25.6.0",
|