Network access
Browser and generated-server connections begin denied.
Granting an origin
1. set_network_access(action: "list", app_id) — returns the live grants and policy_version. Skip this step only for an app you created in this conversation with no grants yet: create_app's response already told you policy_version is 0.
2. Copy that policy_version **integer** into expected_policy_version. It is a counter, not a version string: a brand-new app is 0, and it increases by one per change. Sending "0.0" is wrong.
3. set_network_access(action: "grant", app_id, surface, origin, reason, idempotency_key, expected_policy_version). The origin must be an exact public HTTPS origin — no path, query, port, wildcard, or IP literal. Server grants also bind server_methods. Choose the surface yourself from the app's architecture — server for Worker-side calls like a data sync, browser for fetches the page itself makes; the owner approves or declines at the native consent prompt, so do not ask which surface in chat first.
4. The client asks the owner to confirm; the grant only exists after they accept. An agent can never self-approve, and a client that cannot show a confirmation prompt fails closed.
NETWORK_POLICY_CONFLICT means the policy changed underneath you: list again and reuse the new integer. Revoking needs no new permission — same call with action: "revoke".
What a browser grant does and does not open
A browser grant lets page JavaScript fetch the origin and load its images and media. Loading executable scripts, stylesheets, or fonts additionally requires browser_directives naming them:
{ "action": "grant", "app_id": "<app_id>", "surface": "browser", "origin": "https://cdn.jsdelivr.net", "browser_directives": ["script"], "expected_policy_version": 0, "reason": "Load the three.js renderer", "idempotency_key": "grant-cdn" }
A script grant runs third-party code inside the private app with the app's full privileges, and the origin can change that code at any time — the owner is told exactly that before approving. Vendoring the library into the app is usually better: it is one call, it cannot change underneath the app, and it needs no grant. See get_docs(dependencies).
An app must also declare any remote origin it references in podda.json network.expectedOrigins, or the deploy is rejected with the remedy. Frames, external forms, and service workers stay denied.
Browser revocation applies to newly served HTML; an already loaded page keeps its prior CSP until reload.
Last updated 22 August 2026 · Documentation version 7