Documentation

App Sites

Create, list, get, and delete app sites via the OrbitKit API.

App sites are the top-level resource in OrbitKit. Each app site has its own privacy policy, support page, custom domain, and subscription. A single account can have up to 10 app sites.

Endpoints

Method Path Description
GET /api/apps List all apps
POST /api/apps Create an app
GET /api/apps/:appId Get a single app
DELETE /api/apps/:appId Delete an app
GET /api/apps/:appId/site Get site configuration
PATCH /api/apps/:appId/site Update site configuration

List all apps

GET /api/apps

Returns all apps for the authenticated user.

Response

[
  {
    "appId": "-NtestApp123",
    "appName": "My Weather App",
    "slug": "my-weather-app",
    "createdAt": 1712345678000,
    "updatedAt": 1712345678000
  }
]

Returns an empty array [] if the user has no apps.


Create an app

POST /api/apps

Creates a new app with an auto-generated URL slug derived from the app name.

Rate limit: 5/hour per user

Request body

Field Type Required Description
appName string Yes App display name (1–200 chars)

Full example

curl -X POST https://api.orbitkit.io/api/apps \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"appName": "My Weather App"}'
var request = URLRequest(url: URL(string: "https://api.orbitkit.io/api/apps")!)
request.httpMethod = "POST"
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try JSONEncoder().encode(["appName": "My Weather App"])

let (data, response) = try await URLSession.shared.data(for: request)
let result = try JSONDecoder().decode(CreateAppResponse.self, from: data)
print(result.appId) // "-NtestApp123"
const res = await fetch("https://api.orbitkit.io/api/apps", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${token}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ appName: "My Weather App" }),
});
const { appId, appName, slug } = await res.json();

Response 201 Created

{
  "appId": "-NtestApp123",
  "appName": "My Weather App",
  "slug": "my-weather-app"
}

Errors

Code Status When
VALIDATION_FAILED 400 appName is missing or invalid
APP_LIMIT_REACHED 400 Account already has 10 apps
SLUG_TAKEN 409 Generated slug is already in use

Get a single app

GET /api/apps/:appId

Returns app details including the site configuration.

Response

{
  "appId": "-NtestApp123",
  "appName": "My Weather App",
  "site": {
    "appName": "My Weather App",
    "description": "Accurate weather forecasts",
    "slug": "my-weather-app",
    "iconUrl": "https://storage.googleapis.com/.../icon.png",
    "deployed": true,
    "deployedAt": 1712345678000,
    "createdAt": 1712345678000,
    "updatedAt": 1712345678000
  }
}

The site field is null if the app has not been configured yet.


Delete an app

DELETE /api/apps/:appId

Permanently deletes the app and all associated data:

  • Releases the URL slug
  • Removes the custom domain and SSL certificate
  • Cancels the app’s Stripe subscription
  • Deletes all files from storage
  • Removes the app record from the database

Response 204 No Content

No response body.


Get site configuration

GET /api/apps/:appId/site

Returns the site configuration for an app.

Response

{
  "appName": "My Weather App",
  "description": "Accurate weather forecasts",
  "slug": "my-weather-app",
  "iconUrl": "https://storage.googleapis.com/.../icon.png",
  "customDomain": "privacy.myapp.com",
  "subscriptionStatus": "active",
  "deployed": true,
  "deployedAt": 1712345678000,
  "createdAt": 1712345678000,
  "updatedAt": 1712345678000
}

Update site configuration

PATCH /api/apps/:appId/site

Partially updates site fields. Only provided fields are changed.

Request body

All fields are optional:

Field Type Description
appName string Display name (1–200 chars)
description string Site description (max 4000 chars)
slug string URL slug (1–63 chars, lowercase alphanumeric + hyphens)

Full example

curl -X PATCH https://api.orbitkit.io/api/apps/-NtestApp123/site \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"description": "Accurate weather forecasts for iOS"}'
var request = URLRequest(url: URL(string: "https://api.orbitkit.io/api/apps/-NtestApp123/site")!)
request.httpMethod = "PATCH"
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try JSONEncoder().encode(
  ["description": "Accurate weather forecasts for iOS"]
)

let (data, _) = try await URLSession.shared.data(for: request)
let site = try JSONDecoder().decode(SiteConfig.self, from: data)
const res = await fetch(
  "https://api.orbitkit.io/api/apps/-NtestApp123/site",
  {
    method: "PATCH",
    headers: {
      Authorization: `Bearer ${token}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      description: "Accurate weather forecasts for iOS",
    }),
  }
);
const site = await res.json();

Response

Returns the full merged site object (same shape as GET /api/apps/:appId/site).

Errors

Code Status When
VALIDATION_FAILED 400 Invalid field value
SLUG_TAKEN 409 New slug is already in use