Deploys
A deploy is a single PUT to the project's domain, with the project packed as a gzipped tarball in the request body. The response is a live stream of newline-delimited JSON describing the publish as it happens: upload, propagation to the CDN, certificate work, and the final result.
PUT /:domain
Request
PUT /my-site.surge.sh HTTP/1.1
Host: surge.surge.sh
Authorization: Basic dG9rZW46…
Content-Type: application/gzip
Accept: application/x-ndjson
Transfer-Encoding: chunked
version: 1.0.0
file-count: 42
project-size: 123456
The body is a gzipped tar archive of the project directory. Notes on the format the official clients produce:
- Entries are prefixed with a single top-level directory (the server unpacks with the first path segment stripped), so
site/index.htmlbecomes/index.html. - Files matched by the default ignore rules (
.git, dotfiles,node_modules,bower_components) and by the project's.surgeignoreare excluded before packing.
Deploy headers
Metadata about the deploy travels in request headers:
| Header | Description |
|---|---|
version |
Your client's version string. |
file-count |
Number of files in the archive—used for progress totals and limits. |
project-size |
Total bytes—used for progress and limits. |
message |
A deploy message, shown in the revision list (surge list <domain>). |
stage |
Set to make this a preview deploy: uploaded and given a revision preview URL, but not cut over to production. |
add / rem |
Comma-separated emails of collaborators to add or remove as part of the deploy. |
ssl |
Signals the project should force HTTPS. |
The response stream
The server responds 200 and begins streaming JSON objects, one per line. Each object has a type. In a typical successful deploy you'll see, in order:
{ "type": "progress", "id": "upload", "written": 51200, "total": 123456 }
{ "type": "progress", "id": "cdn", "written": 12, "total": 42, "file": "index.html" }
{ "type": "cert", "data": { "issuer": "Let's Encrypt", "altnames": ["my-site.surge.sh"], "expiresInWords": "89 days" } }
{ "type": "subscription", "data": null }
{ "type": "info", "urls": [...], "instances": [...], "metadata": {...}, "config": {...} }
| Type | Meaning |
|---|---|
progress |
Progress through a phase. id is upload, cdn, or encrypt; the final message of a phase carries "end": true. |
cert |
Certificate details, when certificate work happens during the deploy. |
subscription |
The project's plan, if any. |
collect |
Payment required—carries the plan and a checkout URL. The deploy will not complete until the account subscribes. |
info |
The success marker. Contains the deploy result: urls (where the project is reachable, including the revision preview URL), instances (the edge nodes serving it), and metadata (revision id, message, file counts, sizes). |
A stream that ends without an info line means the deploy did not succeed.
Failures
Failures before the stream starts arrive as plain HTTP errors, with the explanation in the reason response header:
| Status | Reason |
|---|---|
401 |
Invalid or expired token. |
403 |
No permission to publish to this domain; or rate limited (30 deploys per domain, 60 per account, 240 per IP, per 15 minutes—halved for unverified accounts); or the project exceeds the limits (10,100 files / 450 MB). |
422 |
The domain is invalid. |
Revisions and previews
Every deploy creates a revision, identified by a millisecond timestamp, and each revision gets its own permanent preview URL. A normal deploy is cut over to production immediately; a deploy with the stage header stops after upload, leaving production untouched until you cut it over.
Revisions are managed with a small family of endpoints—list, rollback, rollfore, cutover, discard—documented in the Endpoint Reference, and correspond directly to the CLI's revision commands.
Certificates over the same stream
Two more endpoints speak the same NDJSON protocol:
PUT /:domain/encrypt— provision a managed SSL certificate for a custom domain. No body. Streamsprogress(idencrypt),cert, and finallyinfo.PUT /:domain/ssl— upload a custom PEM bundle (Content-Type: application/x-pem-file, raw body). The server validates the bundle;202with amsgobject on success,400if the PEM is rejected. Requires a paid plan.