Gateway
Publish an HTTP or WebSocket API for your application. Point routes at a function or an event bus, then choose who can call them: a Cloud session, an access key, users of your product, or anyone.
The same edge also carries skippr and SDK calls to other Cloud services.
Status: Preview. See the API action reference for the full command list.
At a glance
| Fact | Value |
|---|---|
| CLI | skippr gateway <operation> |
| Target prefix | CloudGateway. |
| Authentication | Cloud JWT or SigV4 service gateway |
| Api hostname | Returned as platformHostname |
| Protocols | HTTPS request/response and WSS |
| Contract | API actions |
What you can do
- Publish HTTP routes backed by a function or event bus.
- Protect a route with a Skippr Cloud session, an access key, an Auth user pool, or no authorizer for a public route.
- Open WebSocket connections and send a frame to one
ConnectionId. - Call supported Skippr Cloud service APIs through the shared edge.
Before you start
You need skippr login or an operator/workload SigV4 key. To complete the HTTP example, create a function named hello first. Your policy must allow the CloudGateway.* operations and access to the integration target.
Create your first HTTP Api
The same Api, integration, authorizer, and route are CLI, Terraform, CDKTF TypeScript, or CDKTF Python. For provider credentials and the shared cloud provider block, see Terraform and CDKTF.
1. Create the Api
skippr gateway create-api --name hello-api --protocol-type HTTPresource "cloud_api" "hello" {
name = "hello-api"
protocol_type = "HTTP"
}import { CloudProvider, CloudApi } from "@skippr/provider-cloud";
const cloud = new CloudProvider(this, "cloud", { region: "eu-central-1" });
const api = new CloudApi(this, "hello", {
name: "hello-api",
protocolType: "HTTP",
provider: cloud,
});from skippr_cdktf import CloudProvider, CloudApi
cloud = CloudProvider(self, "cloud", region="eu-central-1")
api = CloudApi(
self,
"hello",
name="hello-api",
protocol_type="HTTP",
provider=cloud,
)Save the returned apiId and platformHostname.
2. Connect the function
skippr gateway create-integration --api-id '<apiId>' --integration-type FUNCTION --function-name hello
skippr gateway create-authorizer --api-id '<apiId>' --authorizer-type NONEresource "cloud_api_integration" "hello" {
api_id = cloud_api.hello.api_id
integration_type = "FUNCTION"
function_name = "hello"
}
resource "cloud_api_authorizer" "public" {
api_id = cloud_api.hello.api_id
authorizer_type = "NONE"
}import { CloudApiAuthorizer, CloudApiIntegration } from "@skippr/provider-cloud";
const integration = new CloudApiIntegration(this, "hello", {
apiId: api.apiId,
integrationType: "FUNCTION",
functionName: "hello",
provider: cloud,
});
const authorizer = new CloudApiAuthorizer(this, "public", {
apiId: api.apiId,
authorizerType: "NONE",
provider: cloud,
});from skippr_cdktf import CloudApiAuthorizer, CloudApiIntegration
integration = CloudApiIntegration(
self,
"hello",
api_id=api.api_id,
integration_type="FUNCTION",
function_name="hello",
provider=cloud,
)
authorizer = CloudApiAuthorizer(
self,
"public",
api_id=api.api_id,
authorizer_type="NONE",
provider=cloud,
)Save the returned integrationId. Terraform and CDKTF also create a public NONE authorizer so the route can attach it.
3. Create the route
skippr gateway create-route --api-id '<apiId>' --integration-id '<integrationId>' --route-key 'POST /hello'resource "cloud_api_route" "hello" {
api_id = cloud_api.hello.api_id
route_key = "POST /hello"
integration_id = cloud_api_integration.hello.integration_id
authorizer_id = cloud_api_authorizer.public.authorizer_id
}import { CloudApiRoute } from "@skippr/provider-cloud";
new CloudApiRoute(this, "hello", {
apiId: api.apiId,
routeKey: "POST /hello",
integrationId: integration.integrationId,
authorizerId: authorizer.authorizerId,
provider: cloud,
});from skippr_cdktf import CloudApiRoute
CloudApiRoute(
self,
"hello",
api_id=api.api_id,
route_key="POST /hello",
integration_id=integration.integration_id,
authorizer_id=authorizer.authorizer_id,
provider=cloud,
)Send POST /hello to the returned platformHostname. Add an authorizer before using the route for protected data.
Understand the Api model
| Concept | Meaning |
|---|---|
| Api | The primary HTTP or WebSocket resource; there are no stages |
| Route | METHOD /path for HTTP, or a route key for WebSocket |
| Integration | A FUNCTION or EVENTS_PUT backend; CLOUD_SERVICE is reserved for platform HTTP Apis |
| Authorizer | JWT, SIGV4, USER_POOL, or NONE |
| ConnectionId | Opaque identifier for one live WebSocket connection |
| DomainName | A verified custom hostname attached to one Api |
Gateway does not have stages. CreateStage, DeployStage, and stage variables are not part of the product.
Manage HTTP Apis
| Task | Supported operations |
|---|---|
| Manage Apis | CreateApi, GetApi, ListApis, UpdateApi, DeleteApi |
| Manage routes | CreateRoute, GetRoute, ListRoutes, UpdateRoute, DeleteRoute |
| Manage integrations | CreateIntegration, GetIntegration, ListIntegrations, UpdateIntegration, DeleteIntegration |
| Manage authorizers | CreateAuthorizer, GetAuthorizer, ListAuthorizers, DeleteAuthorizer |
| Execute integrations | ExecuteFunctionIntegration, ExecuteEventsPut |
FUNCTION invokes a named function and returns the handler payload as the HTTP or WebSocket response body. HTTP status is the function statusCode. Direct skippr functions invoke still returns { "statusCode": 200, "payload": "..." }. EVENTS_PUT writes to an event bus. CLOUD_SERVICE is not an integration option for your Apis.
Add authentication
| Authorizer | Use |
|---|---|
JWT | Someone signed in to your Skippr Cloud account |
SIGV4 | A signed request from an operator or workload key |
USER_POOL | A user of your product, from an Auth user pool |
NONE | A public route |
Use WebSocket after HTTP
Create a second Api with protocolType: "WEBSOCKET". WebSocket Apis use the same Api, integration, authorizer, and route operations as HTTP Apis.
| Route key | When it runs |
|---|---|
CONNECT | Once after the WSS upgrade and authorization succeeds |
DISCONNECT | When the connection ends; delivery is best-effort |
DEFAULT | When no custom route matches |
| A custom key | For a matching inbound JSON message |
Set routeSelectionExpression on CreateApi, such as $request.body.action, when your frames select custom route keys. WebSocket routes support FUNCTION and EVENTS_PUT; they do not support CLOUD_SERVICE.
Connection management operations are supported:
PostToConnectionsends one UTF-8 JSON frame to oneConnectionId.DisconnectConnectioncloses one connection.GetConnectionandListConnectionsreturn connection data for this Api.
Preview is a managed multi-node service, not a customer-selectable single-node mode. The supported contract is per-connection delivery. There is no broadcast or multicast operation; application fan-out requires one PostToConnection call per recipient.
Hostnames
These hosts are the ones you call from the CLI and SDKs. Check the API action reference before depending on a service that is still coming.
| Capability | Hostname |
|---|---|
| Shared Cloud API | api.cloud.skippr.io |
| Gateway | gateway.{region}.cloud.skippr.io |
| Auth | auth.cloud.skippr.io |
| Tables, queue, events, scheduler | {service}.{region}.cloud.skippr.io |
| Secrets, functions, inventory | {service}.{region}.cloud.skippr.io |
| DNS, certificates, sites | {service}.{region}.cloud.skippr.io |
| Logs, metrics, traces, elt | {service}.{region}.cloud.skippr.io |
| Objects | objects.cloud.skippr.io |
streams and machines are not available yet. A reserved hostname does not mean you can call those products. Streams protocol traffic is also not gateway HTTP or WebSocket traffic.
Bind a custom domain
Create the Api, then create a domain name with CLI, Terraform, CDKTF TypeScript, or CDKTF Python. For provider credentials and the shared cloud provider block, see Terraform and CDKTF.
skippr gateway create-domain-name --hostname api.example.com --api-id '<apiId>'resource "cloud_api_domain_name" "api" {
hostname = "api.example.com"
api_id = cloud_api.hello.api_id
}import { CloudApiDomainName } from "@skippr/provider-cloud";
new CloudApiDomainName(this, "api", {
hostname: "api.example.com",
apiId: api.apiId,
provider: cloud,
});from skippr_cdktf import CloudApiDomainName
CloudApiDomainName(
self,
"api",
hostname="api.example.com",
api_id=api.api_id,
provider=cloud,
)The response includes an ownership TXT (_skippr-challenge.{hostname}) and an ACME CNAME target ({token}.validation.skippr.io). Publish these records at your DNS provider together with a traffic CNAME from your hostname to the Api platformHostname ({api_id}.gateway.{region}.cloud.skippr.io). Then:
- Call
VerifyDomainName. - Request a certificate with the same hostname and
acmeDelegationCname. - After the certificate is issued,
AttachDomainNamewith the Api id andcertificateId. Terraform can setcertificate_idoncloud_api_domain_nameonce the certificate exists.
Leave the ownership TXT and ACME CNAME in place so renewal can update TXT under validation.skippr.io without another DNS change. Do not proxy a Gateway Api hostname through Cloudflare for SaaS.
A Site custom domain uses a Sites domain binding, not a gateway domain name.
Limits and errors
- Coarse per-IP and per-credential rate limits apply. A rate-limited request returns 429; wait before retrying.
- Missing or invalid credentials on a protected route return 401.
- A valid identity without permission returns 403.
PostToConnectionreturns 410 when the connection is already closed.- A request for an Api, domain, or connection that is not yours returns 403.
- A failed WebSocket authorization returns HTTP 401 or 403 before the upgrade; no connection is opened.
No additional numeric WebSocket quota is part of this public Preview contract. Use the generated operation schemas for required fields and error responses.
