What you can publish
Everything on this platform reaches the internet the same way: you publish an endpoint for it through the API Gateway. There is one publishing path, one place the access policy lives, and one audit trail.
This page has a section per resource type. Each one gives the exact command, what protections that type supports, and the one thing about it that catches people out.
The short version
| Resource | Target | Takes a name? | How it is reached | Protections available |
|---|---|---|---|---|
| Agent | agent | yes | Web requests | Credential, rate limit, address allow list, your own domain |
| Function | function | yes | Web requests | Credential, rate limit, address allow list, your own domain |
| Serverless service | serverless | yes | Web requests | Credential, rate limit, address allow list, your own domain |
| Container app | container | yes | Web requests | Credential, rate limit, address allow list, your own domain |
| MCP server | mcp | yes | Web requests | Credential, rate limit, address allow list, your own domain |
| Vector database | vectordb | no | Web requests | Credential, rate limit, address allow list, your own domain |
| Pub/Sub | pubsub | no | Raw connection | Address allow list only |
| MemoryStore | memorystore | yes | Raw connection | Address allow list only |
Two distinctions run through the whole table, and they decide what you can and cannot ask for.
Named or project-wide. Most targets are one workload you named, so you publish agent/research-buddy. The vector database and Pub/Sub are one shared engine per project, so the type is the target: you publish vectordb, with no name. Sending a name for those is refused rather than ignored, because a name would suggest you had addressed something narrower than you had.
Web requests or a raw connection. Agents, functions, serverless services, container apps, MCP servers and the vector database speak HTTP, so the gateway can read each request: it can check a credential, count the request against a limit, and route on the path. Pub/Sub and MemoryStore speak their own binary protocols over a raw TCP connection. There are no requests there to check or to count, so an authentication mode or a rate limit on one of those would be a protection that does not exist, and the API refuses to pretend otherwise. Address allow lists still work on both, because those are enforced on the connection itself.
If you publish an HTTP endpoint with --auth none, the API requires a rate limit as well. Public is not the hazard; public and unmetered is. An agent behind an open endpoint spends model tokens on every call, for anyone who finds the URL, and with no credential there is no key to attribute a flood to. The limit protects your spend.
Raw-connection endpoints are exempt because they cannot have one at all.
Agents
platformctl gateway publish agent/research-buddy --auth apikey
The address is https://research-buddy-<short>.apps.<domain>.
Scale-to-zero keeps working. An idle agent has no instances running; the first request through the gateway wakes one and waits for it. You do not need to keep a warm instance for a published address to answer.
What the caller sends. Whatever your agent's framework expects. The gateway does not rewrite the path or the body — it checks the policy and passes the request through.
See Agents.
Functions
platformctl gateway publish function/resize-image --auth apikey
The address is https://resize-image-<short>.apps.<domain>.
A function's event carries the inbound request headers under _headers, so a published function can read what the caller sent. See Functions.
Scale-to-zero applies here too.
Serverless services and container apps
platformctl gateway publish serverless/web --auth none --rate-limit 600/minute
platformctl gateway publish container/dashboard --auth apikey
serverless and container are two names for the same routing behaviour; use whichever matches what you deployed. Both scale to zero, and both are woken by an inbound request.
See Serverless.
MCP servers
platformctl gateway publish mcp/weather-tools --auth apikey
An MCP server is a serverless workload like an agent, and it publishes exactly like one — named target, web requests, the full set of protections, scale-to-zero preserved.
/mcp, and the bare address is not itPoint MCP clients at the published address with /mcp on the end:
https://weather-tools-<short>.apps.<domain>/mcp
Without the path a client connects, POSTs to /, and gets a 404 that surfaces as "Failed to create MCP session". That reads exactly like a broken network, and it is a wrong URL.
Two credentials, and they check different things. The gateway's --auth is the edge check: it decides who may reach the address at all. The server's own per-server bearer token is still required by the server. Publishing with --auth none does not make the server open — it makes the address open, and the server still refuses a caller with no token.
Use the name you gave the server, and nothing else. Internally the platform prefixes an MCP server's name to keep it distinct from an agent that happens to share it, and the gateway applies that prefix for you. Publishing mcp/mcp-weather-tools would look for a server whose name already had the prefix, and find nothing.
See MCP servers.
Vector database
platformctl gateway publish vectordb --auth apikey
No resource name. The endpoint covers this project's whole vector database, so the type is the whole target. Passing a collection name is refused — the address is not scoped to one collection, and a name in the command would suggest it was.
The address is https://vectordb-<short>.apps.<domain>, and it speaks the vector database's own HTTP API.
Your project's vector-database credential is still required by the database itself. The gateway's --auth decides who may reach the address; the credential decides who may read and write data. Publishing with --auth none opens the address, not the data.
See Vector database.
Pub/Sub
platformctl gateway publish pubsub --allow-cidr 203.0.113.0/24
No resource name, for the same reason as the vector database: the endpoint covers this project's whole messaging broker.
Raw connection. Clients connect over the broker's binary protocol, not web requests. So:
--authand--rate-limitare not available, and asking for them is refused rather than silently ignored.--allow-cidris available and is the only network-level control there is.- Your project's messaging credential is what actually lets a caller in.
Treat the allow list as a coarse net in front of the credential, never as the boundary itself — shared egress and NAT both mean an address is a weak identity.
See Pub/Sub.
MemoryStore
platformctl memorystore create cache
platformctl gateway publish memorystore/cache --allow-cidr 203.0.113.0/24
A named target, unlike the two shared engines — one endpoint per instance.
Raw connection, like Pub/Sub: no --auth, no --rate-limit, --allow-cidr only, and the instance's own password is what lets a caller in.
The address is rediss://cache-<short>.apps.<domain>:443. TLS terminates at the gateway, so connect with a TLS-enabled client on port 443, using the same password as the private address inside your project:
redis-cli --tls -h cache-<short>.apps.<domain> -p 443 -a <password>
Creating a memory store used to take an external_exposure flag that published it. That is retired: sending it now returns a 400 naming this command instead. The endpoint is better in every direction — it can be turned off and back on without rebuilding the instance, it carries an audit row per publish, and the allow list lives with the address rather than on the cache.
See MemoryStore and connecting from outside.
What you cannot publish, and why
| Resource | Why not |
|---|---|
| Inference | Already a platform API you call with your own credential. It is not a per-project workload, so there is no address of yours to publish. |
| Secrets Manager | Deliberately unreachable from outside. Secrets are delivered to your workloads by the platform; an internet address for the secret store would be an internet address for every secret in the project. |
| Code sandbox | A sandbox is created for one session and torn down. There is nothing stable to point an address at. |
If you need one of these reachable from outside, put a workload of your own in front of it — an agent, function or serverless service that holds the credential and enforces whatever policy you want — and publish that.
Next steps
- Publish an endpoint — the full lifecycle: create, publish, inspect, update, unpublish.
- Authentication — API keys, your own JWT issuer, or open.
- Rate limits — what a limit counts and what it is keyed on.
- IP allowlists — address ranges, and why they are a net rather than a boundary.
- Custom domains — publish on a name you own, with TLS issued for you.
- Troubleshooting — an endpoint that is green and not answering.