Skill v1.1.0
currentAutomated scan100/100+2 new
name: my-function-api version: 1.1.0 description: > 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. triggers: [function, deploy function, edge function, serverless, cloudflare worker, cron, scoped api key, capability key, invocation url, bundle] checksum: sha256-3702cfd630b5ff8a892704c4f6aee9f6678881c73fd3522ce4bd52be865e639e
MyFunctionAPI
Deploy backend code without running a server. Register a function, upload a single-file JS bundle, and it goes live on the MyAPI edge runtime with a public invocation URL — or runs on a cron schedule. Each function carries a scoped capability key so it can call other MyAPI slots with its own authority.
The full loop is live: create → deploy → invoke → inspect runs → set secrets.
Capabilities
<!-- llm:start --> Two-step lifecycle: register, then deploy. myapi fn create --name <slug> persists the function record and mints a scoped_api_key, returned exactly once (save it if you need it). myapi fn deploy <id> <bundle.js> uploads a single-file JavaScript bundle (≤4MB); the backend wraps it with the MYAPI shim and ships it to the edge runtime. Propagation is typically 4-45s, so poll the invocation URL rather than redeploying. After deploy the function has a live invocation_url.
Scoped key = capability key. It is org-locked. By default it inherits the deployer's slot grants; narrow it at create time with --scope <slot>[,<slot>...] (comma-separated, e.g. --scope email,storage) — the primary way to deploy a deliberately narrow function. Grants can never exceed the caller's, so a function never out-reaches the credential that created it. It is rejected with 403 SCOPE_FORBIDDEN at /hq/*, /admin/*, /internal/*. Deploy rotates this key — the fresh value is printed once on every deploy. (Minting a narrow account key first — myapi keys create --grant ... — is only needed when the deploy credential itself must be constrained, e.g. handing deploy rights to another system.)
HTTP or cron triggers. Default is http — the function gets a public invocation URL once deployed. Pass --cron "<expr>" at create time to run on a schedule (e.g. "0 8 * * *") instead.
Secrets are encrypted at rest. myapi fn env <id> <name> <value> sets a secret (Stripe key, API token, …) on a deployed function. The value is encrypted at rest by the edge runtime and never stored or echoed by MyAPI. The function must already be deployed.
Inspect invocations. myapi fn runs <id> lists recent invocation records (most recent first, up to 100) with status, duration, and any error message.
Name rules (validated client- and server-side, kept identical):
^[a-z0-9][a-z0-9-]{0,49}$— kebab-case, 1-50 chars- Reserved server-side:
www,api,admin,system,default
<!-- llm:end -->
Commands
<!-- generated:start -->
| Command | What it does | |
|---|---|---|
myapi fn create --name <name> [--cron <expr>] [--scope <slot>[,<slot>...]] | Register a function record + receive scoped API key (returned once). --scope narrows the key's slot grants | |
myapi fn deploy <id> <bundle.js> | Upload a single-file JS bundle (≤4MB) and go live; rotates the scoped API key | |
myapi fn env <id> <name> <value> | Set an encrypted secret on a deployed function | |
myapi fn runs <id> | List recent invocation records (status, duration, errors) | |
myapi fn list | List functions in your org | |
myapi fn get <id> | Inspect a function (name, trigger, invocation URL) | |
myapi fn scopes <id> --set <slot,slot> | Change which slots the function may call, in place. Replaces the list; rotates the scoped key | |
myapi fn delete <id> | Soft-delete the record + revoke the scoped API key |
<!-- generated:end -->
Examples
<!-- llm:start -->
# Register an HTTP function (invocation_url is empty until you deploy)myapi fn create --name my-app-api# → Function created: fn_abc123# Scoped API key (returned once — save it if you need it):# hq_live_... (scoped API keys are not visually distinct from account keys)# Deploy a single-file JS bundle → goes live, scoped API key is rotatedmyapi fn deploy fn_abc123 ./dist/bundle.js# → Deployed function fn_abc123# Invocation URL: https://fn-abc123.<...>.workers.dev# Scoped API key was rotated. New value (returned once): hq_live_...# Set a secret (encrypted at rest; never echoed)myapi fn env fn_abc123 STRIPE_KEY sk_live_...# Inspect recent invocationsmyapi fn runs fn_abc123# Register a cron function instead of HTTPmyapi fn create --name daily-report --cron "0 8 * * *"# Register with a narrowed key — the function can only call email + storagemyapi fn create --name mailer --scope email,storage# Need another slot later? Change it in place — same id, same URL.myapi fn scopes fn_abc123 --set email,storage,crm# List + inspectmyapi fn listmyapi fn get fn_abc123# Delete (revokes the scoped API key — future calls with it return 401)myapi fn delete fn_abc123
The scoped API key is already in your function — as __MYAPI_KEY
Two leading underscores, and it is injected for you. Verified by probing a deployed function: Object.keys(env) returns exactly ["__MYAPI_KEY"], and MYAPI_KEY (no underscores) is NOT present.
export default {async fetch(request, env) {const r = await fetch('https://api.myapihq.com/database/orgs/<org>/namespaces/app/keys/x', {headers: { Authorization: `Bearer ${env.__MYAPI_KEY}` },});return new Response(await r.text());},};
Do not capture the key printed at `fn create` and set it yourself. Every fn deploy rotates it, so a manually-set copy goes stale on the next deploy and the function starts returning 502 with nothing in the deploy output to explain it. The injected __MYAPI_KEY is always current.
Note the name differs from containers, which receive MYAPI_KEY without the underscores. Both verified 2026-07-28.
Using the scoped API key
# You do NOT need this — env.__MYAPI_KEY is injected and always current.# Shown only for calling the function's slots from OUTSIDE the function.# Save the API key returned at create/deploy timeSCOPED_KEY="hq_live_..."# Call slots the API key was granted — works (within its org + grants)curl -H "Authorization: Bearer $SCOPED_KEY" \https://api.myapihq.com/database/orgs/$ORG_ID/namespaces# Calling /hq/* with it — denied (403 SCOPE_FORBIDDEN)curl -H "Authorization: Bearer $SCOPED_KEY" \https://api.myapihq.com/hq/orgs# → 403 {"error":{"code":"SCOPE_FORBIDDEN"}}
<!-- llm:end -->
Notes
- The bundle is a single JavaScript file (≤4MB). Bundle your dependencies before deploy (esbuild/rollup/etc.).
--cronis set at create time; the trigger type is fixed for the function's lifetime.- Deploy rotates the scoped API key on every call — re-capture the printed value if other systems use it.
myapi fn env <id> --set KEY=VALUE,OTHER=VALUEsets several secrets in one call instead of one command each.
Scopes are changeable in place — `myapi fn scopes <id> --set <slot,slot>`. The function id and invocation URL are unchanged, so references already handed out keep working. This used to be create-only, and adding a slot meant delete + recreate with a new id and URL; that is no longer the trade-off.
Two things to know:
- `--set` REPLACES the list, it does not add to it. Name every slot the
function should reach. myapi fn get <id> shows the current set.
- It rotates the scoped key, exactly as a deploy does — a narrowing that
left the old key alive would narrow nothing. env.__MYAPI_KEY inside the function is updated for you; a copy you saved elsewhere goes stale.
HTTP (from deployed code)
<!-- http:start --> <!-- generated by npm run canonical-sync — do not edit -->
base https://api.myapihq.compath POST /function/orgs/{org_id}/functionsauth Authorization: Bearer <key> (fn: env.__MYAPI_KEY · container: env.MYAPI_KEY)reply { "success": true, "data": …, "error": null, "meta": {…} }
- Per-slot host — do not assume one host serves every slot.
- Org id goes in the PATH — there is no
X-Org-Idheader.
<!-- http:end -->
Run myapi fn --help or myapi fn <subcommand> --help for full flag reference.