Create Endpoint
Provision a new endpoint — the routing entry that connects a public URL to an agent. The endpoint persists across agent reconnects; tunnels are the live connections that come and go on top of it.
Endpoints are protocol-agnostic — one endpoint serves HTTP, TCP, UDP and QUIC at once. The protocol is chosen per tunnel by the agent (ngris http|tcp|udp), not at endpoint create, so there is no protocol field. Endpoints are also region-less — region is a property of the serving tunnel/agent (GeoDNS steers public traffic to the nearest region), so there is no region field; the plan's region:<slug> entitlements are enforced when a tunnel connects, not at create. Before creating, the server checks that the user has remaining endpoint quota on their plan and (for custom subdomains and root @ endpoints) that the user owns the target domain. Per-protocol plan entitlements are enforced when a tunnel of that protocol connects.
To serve an application instead of a tunnel, send serving_mode: "agentless" and the app's application_uuid. An app can have several endpoints (for example example.com and www.example.com): send the same application_uuid again for each. Every endpoint serves the app's production deploy with its own settings — a new endpoint does not get the sign-in of the app's other endpoints, so set it with PUT /v1/endpoints/{uuid}/settings (or one mode on many at once with POST /v1/endpoints/bulk-settings). The app's first endpoint becomes its primary. Every endpoint, app or tunnel, counts against the same endpoint quota.
Only a function gets an endpoint when it is created (and Quick Deploy makes one for a static app), so this call is how a static, backend, full-stack or WordPress app gets its URL. Adding an endpoint to a WordPress app restarts the site so it picks up its new address: about a minute of downtime.
Request body
is_custom: true and you own the target domain — otherwise the platform auto-generates a memorable word-word-word identifier. Pass "@" to claim the root of the domain (admin or strict domain owner only).true to use the supplied subdomain. Requires the custom-subdomains entitlement on your plan and ownership of the target domain. Silently downgraded to false if either prerequisite isn't met.uuid of a domain you can use — one registered to your account or a platform domain (/domains). Omit to use the plan's configured default system domain (e.g. ngris.io).agentless (or managed) serves the application named by application_uuid; the platform derives how from the app's type (static files from the edge, or the app's backend).serving_mode agentless or managed: the app in your active account to serve. The app may already have other endpoints. Requires application hosting on your plan.Deprecated: domain_id (integer) is still accepted until the sunset. Send domain_uuid; sending both for different objects is a 400 id_uuid_mismatch.
Response (201 Created)
/endpoints/{uuid}).myapp.example.com). Share this with the agent and clients.hostname — the bare FQDN with no scheme, because the endpoint may serve HTTP/TCP/UDP/QUIC. For HTTP/unified endpoints, build a browser URL as https://<public_url>.agent (a tunnel — the default), agentless or managed (an application endpoint).agent endpoints.unified — endpoints are protocol-agnostic.false even if you requested true (entitlement or ownership check failed).uuid of the domain the endpoint is anchored to. Omitted when the endpoint has no domain row.inactive — the endpoint exists and turns active once an agent (or, for an application endpoint, a live deploy) serves it — or pending_dns when the platform still has to create the endpoint's DNS record on your domain (it then moves to inactive, or dns_failed with dns_last_error set).disabled, optional, required): disabled for a new endpoint; configure via PUT /v1/endpoints/{uuid}/mtls.true for a new endpoint. Change it via PUT /v1/endpoints/{uuid}/settings/capture.full | metadata | off), as stored. Omitted when unset, as on a new endpoint.false for an endpoint created here.0 at creation.Deprecated: until the sunset this response also carries the legacy integer id and *_id fields. Don't use them; read uuid and the *_uuid fields.
Errors
protocol/region fields are accepted-but-ignored), invalid subdomain format, a malformed domain_uuid, domain_id and domain_uuid naming different domains (id_uuid_mismatch), or an application endpoint without application_uuid (application_uuid is required for an application endpoint).{"error":"endpoint limit reached (N)"}, where N is your plan's endpoint limit. Every endpoint counts, app and tunnel endpoints alike (ephemeral endpoints have their own quota); remove one or upgrade your plan. Also: root @ endpoint without strict ownership, organization endpoint limit hit, or an application endpoint on a plan without application hosting (Application hosting is not available on your plan). (Per-protocol and per-region plan entitlements are enforced when a tunnel connects, not at endpoint create.)domain_uuid names no domain you can use (domain not found — an unknown domain and another account's domain read the same), or application_uuid no application in your active account (application not found).quota_paused): no endpoint can be added to it until the account has room again.