# Railway Hosting Primary public hosting option for Cohesivity tenants. Cohesivity creates and owns the Railway project/service/environment/domain, and tenant agents deploy by uploading source files directly to Cohesivity. No GitHub repo, Railway CLI install, or tenant Railway credentials are required. ## Prerequisites Edge calls require this resource to be provisioned first; unprovisioned calls return an error. ### Provision curl -s -X POST https://cohesivity.ai/api/resources/railway-hosting \ -H "Authorization: Bearer " ### Delete curl -s -X DELETE https://cohesivity.ai/api/resources/railway-hosting \ -H "Authorization: Bearer " Provisioning happens once, before the application runs; the running application does not provision its own resources. ## What Happens on Provision - Creates a Railway project `coh-` under Cohesivity-owned Railway credentials - Creates an empty `web` service and `production` environment - Attaches an existing tenant vanity, or otherwise the automatic `.cohesivity.app` host, and returns it as the single `deployment_url` - Applies Cohesivity tier compute caps to the Railway service instance and stores the applied cap/status metadata in Cohesivity - Stores Railway project, service, environment, domain, compute cap, and last deployment metadata in Cohesivity The provisioning response is intentionally small: `success`, `resource`, `status`, `deployment_url`, `compute_limits`, `already_provisioned`, `deploy_endpoint`, and `docs_url`. It does not return provider ids, provider domains, generated scripts, or repeated next-step prose. ## Compute Caps Railway topology and CPU/RAM/replica/sleep limits are Cohesivity-managed and not tenant-callable in v1. The service is always `web` and the environment is always `production`; bodies containing `service_name` or `environment_name` return `400 railway_topology_managed`. Re-provisioning `railway-hosting` idempotently reapplies the active tier cap, and claiming an ephemeral tenant reconciles its Railway cap to the claimed account tier in the background. - Ephemeral: 0.5 vCPU, 1 GB RAM, 1 replica, sleep enabled - Claimed Free: 0.5 vCPU, 1 GB RAM, 1 replica, sleep enabled - Plus: 1 vCPU, 2 GB RAM, 1 replica, sleep disabled - Pro: 2 vCPU, 4 GB RAM, 1 replica, sleep disabled ## Runtime metering A minute-level poller reads Railway `usage` for the UTC month (`CPU_USAGE`, `MEMORY_USAGE_GB`, `NETWORK_TX_GB`) and records deltas as `vcpu_seconds`, `memory_gb_seconds`, and `egress_bytes`. Railway reports CPU and memory in its per-minute billing units, which Cohesivity normalizes to seconds on ingest; egress is a volume and is converted from GB to bytes. Claimed overage auto-purchases fluid blocks at Railway's published rates plus 10%. When fluid is exhausted the offering pauses; the poller then sets `sleepApplication: true`, and after a grace window (immediate for Ephemeral/Free, 24h for Plus/Pro) stops the running deployment. Stopping halts compute billing without destroying anything — the service, its source, variables, domains, and TLS certificate all survive. Hosting is never deleted for non-payment. Topup or a new monthly grant redeploys the stopped deployment, restores tier compute caps, and resumes the offering. Metering starts when a project first becomes observable to the poller: a project provisioned mid-month is metered from provisioning onward, and consumption that predates metering is never billed retroactively. ## How to Deploy POST `multipart/form-data` to `/api/railway/deploy`: each project file is a `files` part. The endpoint validates paths/count/size, creates the gzip tarball Railway expects, and uploads it to Railway server-side with Cohesivity-owned auth. Append `?wait=ready` to block until Railway reports SUCCESS and the public application route answers without a 5xx response for an additional stability window. This application probe catches immediate crashes and Railway restart loops even when Railway continues to label the deployment SUCCESS. If the 60-second wait expires while the provider or application is not ready, the endpoint returns HTTP 202 with `success: false`, `wait_timed_out: true`, and `readiness_state: "pending"|"unhealthy"`; poll the deployment detail route. A normal response contains only `success`, `deployment_id`, `state`, the Cohesivity `deployment_url`, and the Cohesivity `logs_url`. Railway provider URLs and dashboard links remain internal. ### curl ``` curl -F "files=@package.json" \ -F "files=@src/index.js" \ -H "Authorization: Bearer " \ https://cohesivity.ai/api/railway/deploy?wait=ready ``` ### JSON shape ``` POST https://cohesivity.ai/api/railway/deploy?wait=ready Authorization: Bearer Content-Type: application/json { "files": [ { "file": "package.json", "data": "{...}" }, { "file": "src/index.js", "data": "console.log(process.env.PORT)" }, { "file": "public/logo.png", "data": "", "encoding": "base64" } ] } ``` ### Response ```json { "success": true, "deployment_id": "", "state": "SUCCESS", "deployment_url": "https://.cohesivity.app", "logs_url": "https://cohesivity.ai/api/railway/deployments//logs" } ``` ## Deployment Management All endpoints require `Authorization: Bearer `. - **List deployments:** `GET https://cohesivity.ai/api/railway/deployments` returns deployment ids, one `state`, the Cohesivity `deployment_url`, the Cohesivity `logs_url`, and timestamps - **Deployment details:** `GET https://cohesivity.ai/api/railway/deployments/:id` returns the same public fields plus a curated `last_error` for terminal failures - **Deployment logs:** `GET https://cohesivity.ai/api/railway/deployments/:id/logs?type=build|runtime|http` (Cohesivity proxies Railway build, deployment, and HTTP log queries; build/runtime severity is normalized from message prefixes, with a differing raw value preserved as `provider_severity`) - **Domain/status detail:** `GET https://cohesivity.ai/api/railway/domain` or `GET https://cohesivity.ai/api/railway/status` ## Environment Variables Set env vars before deploying when your build reads them. Railway does not return decrypted values on list, so list responses include names/metadata only. The account env manager uses Railway for `railway-hosting` tenants. - **List env vars:** `GET https://cohesivity.ai/api/railway/env` - **Upsert env var:** `POST https://cohesivity.ai/api/railway/env` with `{ "key": "MY_SECRET", "value": "abc123" }`. Values are limited to 32,768 UTF-8 bytes. Writes always use `skip_deploys: true`; `skip_deploys: false` returns `400 provider_deploy_not_allowed`, and callers must use the explicit deploy endpoint. - **Delete env var:** `DELETE https://cohesivity.ai/api/railway/env/:key`; a missing key returns `404 env_var_not_found`. Environment responses expose variable names, sealed/write-only state, update timestamps, and create-time fingerprints only. They never include Railway variable or service ids. ## Tenant Vanity (claimed tenants) A tenant may claim one immutable vanity such as `acme`. Hosting uses `acme.cohesivity.app`; an active Inbox uses `acme@inbox.cohesivity.app`. Whichever offering is provisioned second inherits the first offering's existing claim automatically. Cohesivity manages the Railway and Cloudflare bindings, including Railway's required routing CNAME and ownership TXT records; tenants never provide provider tokens. Multi-record Cloudflare changes are transactional: if a later record fails, earlier records are restored or deleted before the Railway domain is rolled back. - **Check availability** (no auth): `GET https://cohesivity.ai/api/vanity/check?name=acme`. - **Get current** (auth): `GET https://cohesivity.ai/api/vanity`. Railway-backed vanities refresh provider verification status before responding and persist the latest verification records/certificate metadata. `verified` becomes true only after both DNS ownership and TLS certificate issuance are complete; the issued certificate is the authoritative readiness signal when Railway's auxiliary DNS flag remains false behind proxied DNS. - **Claim once** (auth): `POST https://cohesivity.ai/api/vanity` with `{ "name": "acme" }`. For Railway hosting, `https://acme.cohesivity.app` becomes the hosting `deployment_url` immediately; no re-provision is required. Reposting `acme` is idempotent. Posting a different name returns `409 vanity_immutable`. - **No release or transfer:** `DELETE https://cohesivity.ai/api/vanity` returns `409 vanity_immutable`. Account deletion leaves a permanent tombstone, so the identity is never reassigned. Legacy `/api/railway/custom-subdomain` remains a compatibility alias for the shared vanity handlers. ## Custom Domains Claimed Railway tenants can attach their own apex domain with `POST /api/railway/domains`. Cohesivity keeps provider ids and managed-DNS bookkeeping internally in `railway_custom_domains`; tenant responses contain only the domain state and actions the caller can take. - **Cohesivity-purchased domain**: `POST https://cohesivity.ai/api/railway/domains` with `{ "domain_name": "yourapp.com", "source": "cohesivity-purchased", "include_www": true }`. Cohesivity attaches the domain, creates the required Name.com DNS records, and polls readiness. Purchased-domain responses never expose provider ids or managed DNS ids. Omitting `source` keeps this default. - **Bring-your-own-domain (BYOD)**: `POST https://cohesivity.ai/api/railway/domains` with `{ "domain_name": "yourapp.com", "source": "byod", "include_www": true }`. Cohesivity returns BYOD `records_to_add` containing only `host`, `type`, `value`, and `ttl`. Add every routing record and every ownership TXT record at the external registrar. The required CNAME value may name Railway because it is DNS configuration, never an app or dashboard URL. - **Status**: `GET https://cohesivity.ai/api/railway/domains/yourapp.com` refreshes current readiness. `verified` is true only when TLS certificates are issued for the apex and requested `www` host; issuance proves ownership even if Railway's auxiliary DNS flag remains false behind proxied DNS. - **Detach**: `DELETE https://cohesivity.ai/api/railway/domains/yourapp.com` removes Cohesivity-created Railway custom domains. Purchased domains also remove only tracked Name.com records; BYOD returns `records_to_remove` for the external registrar. Hosting teardown and account deletion perform the same binding cleanup before deleting the Railway project. A binding that references an already-deleted project is reconciled locally instead of remaining a permanent conflict. - `source` is strict (`byod` or `cohesivity-purchased`) and `include_www` must be a JSON boolean; invalid values return 400 instead of being silently coerced. ## Security Tenant agents never send Railway tokens. The only auth they use is Cohesivity `coh_management_key`; Cohesivity injects Railway auth server-side and records only ownership/metadata needed for lifecycle, status, and teardown. Railway service URLs, project links, topology ids, custom-domain ids, DNS bookkeeping ids, and environment-variable ids are excluded from tenant-facing responses. The sole provider hostname a tenant may see is an actionable BYOD CNAME value that must be copied into external DNS. ## Rate Limits Ephemeral tenants pause as a whole if any authoritative hard cap below is exceeded. Claimed tiers use account-scoped buckets shared across every project owned by the Cohesivity user; OpenAI, AI Gateway, Deepgram, and Exa are fluid-only after tier, rate, and concurrency checks; AI Gateway and Deepgram have no fixed monthly usage bucket for claimed tiers. **Ephemeral** - projects: 1 max total - deploys: 20 per ephemeral tenant lifetime before claim or expiry - uploaded bytes: 250 MB per ephemeral tenant lifetime before claim or expiry - vCPU-seconds: 50000 per ephemeral tenant lifetime before claim or expiry - memory GB-seconds: 150000 per ephemeral tenant lifetime before claim or expiry - egress bytes: 2 GB per ephemeral tenant lifetime before claim or expiry - deploys: 3 per minute **Claimed Free** - projects: 10 max total - deploys: 3 per minute - deploys: 60 per month - uploaded bytes: 2 GB per month - vCPU-seconds: 100000 per month - memory GB-seconds: 400000 per month - egress bytes: 5 GB per month **Claimed Plus** - projects: 30 max total - deploys: 10 per minute - deploys: 200 per month - uploaded bytes: 10 GB per month - vCPU-seconds: 400000 per month - memory GB-seconds: 1500000 per month - egress bytes: 50 GB per month **Claimed Pro** - projects: 100 max total - deploys: 10 per minute - deploys: 600 per month - uploaded bytes: 50 GB per month - vCPU-seconds: 1500000 per month - memory GB-seconds: 6000000 per month - egress bytes: 250 GB per month ### Notes - Railway deploys and upload bytes remain Cohesivity-side hard counters. Runtime vCPU-seconds, memory GB-seconds, and egress bytes are polled from Railway each minute into the same counter tables; claimed overage draws from fluid at provider cost plus 10%. When fluid is exhausted the offering pauses and the graduated ladder sleeps then stops the Railway service.