npx skills add ...
npx skills add caffeinelabs/skills --skill extension-http-endpoints
Serve inbound HTTP from a Motoko canister (webhooks, curl POST/GET, bot callbacks, ingest/health APIs) via the IC HTTP Gateway methods `http_request` / `http_request_update`. Load whenever the user or spec needs a canister URL that external HTTP clients can hit — Stripe/GitHub/Slack webhooks, Telegram bots, health checks, or any plain REST-ish endpoint. NOT for calling external APIs from the canister (use `extension-http-outcalls`); NOT for certified static asset serving.
npx skills add caffeinelabs/skills --skill extension-http-endpoints
Inbound HTTP for Caffeine AI Motoko backends via mo:caffeineai-http-endpoints.
| Need | Skill |
|---|---|
External client (curl, webhook, bot) hits the canister over HTTPS | this skill |
| Canister calls an external HTTPS API | extension-http-outcalls |
| Typed OpenAI / Google / X / Stripe client | the matching domain skill (those wrap outbound calls) |
Do not implement inbound handlers with the management-canister http_request / Call.httpRequest outcall API — that is the opposite direction.
*.caffeine.xyz, custom domain, or frontend/asset canister).http_request (query).Http.upgrade() so the gateway re-issues as http_request_update (update).URLs
https://<backend-canister-id>.icp0.io/... (or .ic0.app)https://<backend-canister-id>.raw.icp0.io/... — non-raw gateways expect certified query bodies (out of scope)Use the prefabricated modules (do not modify them):
Add mops add caffeineai-http-endpoints. Wire handlers on the existing actor in main.mo — keep MixinAuthorization, do not replace the actor or redeclare http_request*.
onQuery must stay query-safe: no awaits, no state writes. Mutating work belongs in onUpdate after Http.upgrade() from the query path.
The migration chain head:
onUpdate. Query returns Http.upgrade() for POST/PUT/PATCH/DELETE routes that write.http_request..raw.icp0.io. Do not invent response certificates.Http.header, raw req.body).curlUncertified GET on a non-raw host is a hard gateway failure (503 / backend_response_verification / Certification values not found), not a 404 from your handler. POSTs that return Http.upgrade() skip that check.
?canisterId=<id> on https://icp0.io/... is an alternate host form. Prefer the canister subdomain. An IP/localhost GET with only ?canisterId= can return an empty 204 instead of your body — treat that as the wrong URL shape, not an empty handler.
extension-http-outcalls — canister → internet (module helpers, no inbound mixin)extension-stripe — checkout via outcalls; inbound Stripe webhooks still use this skillPocketIC is useful for proving the upgrade dance, not as a drop-in curl replica.
pocket-ic binary is a control server. It does not listen for curl until a client (@dfinity/pic) creates an instance (include an NNS subnet) and calls makeLive(), which returns a port.mops one-liner that prints a curl URL. The gateway dies with that Node/pic process.http://<canister-id>.raw.localhost:<port>/health — uncertified GEThttp://127.0.0.1:<port>/notes?canisterId=<id> — POST / upgrade (worked in a live gateway test)http://<canister-id>.localhost:<port>/health (no .raw) — 503 certification failure*.icp0.io / *.raw.icp0.io forms above.