Sideby / HandbookWEBSITE IMPLEMENTATION · V1.0OpenAPI ↓
THE SIDEBY WEBSITE

Two requests. Two jobs.

Register an email. Remove a registration. The complete HTTP contract of the early-access website.

Before making a request.

MethodPOST
Body limit2,048 bytes
AuthenticationNo API keys

Both endpoints accept application/json and application/x-www-form-urlencoded. JSON submissions receive JSON. Successful URL-encoded submissions receive an HTML confirmation; their errors remain JSON. The Accept header does not select the response format.

Browser requests must be same-origin. A supplied Origin must match this website, and cross-site Sec-Fetch-Site is rejected. An absent Origin is allowed for non-browser clients. CORS access is not enabled. Responses use Cache-Control: no-store.

POST

/api/early-access

Send an email and consent.

Input is validated before the signup rate counter is incremented.

email REQUIRED STRING
Trimmed and lowercased. At most 254 characters; local part at most 64. No leading, trailing or consecutive dots in the local part. ASCII mailbox syntax; use punycode for internationalized domains. Domain must contain a dot.
consent REQUIRED
JSON accepts true or "on". An HTML form sends on. Other values are rejected.
website OPTIONAL HONEYPOT
Omit or leave empty. Non-empty trimmed string values are rejected.

Additional fields are ignored. Syntax validation does not confirm mailbox ownership or delivery.

Browser / JSON
// Use the values from your own same-origin form.
const response = await fetch('/api/early-access', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    email: emailInput.value,
    consent: consentInput.checked,
    website: ''
  })
});
const result = await response.json();
if (!response.ok || result.success !== true) {
  throw new Error(result.error || 'Not confirmed.');
}
// Save result.removalToken privately if present.
// Duplicates do not return a new token.
Local / native form
# Local database. Use an email address you control.
: "${SIGNUP_EMAIL:?Set SIGNUP_EMAIL first}"
curl -i http://localhost:8791/api/early-access \
  -H 'Origin: http://localhost:8791' \
  --data-urlencode "email=$SIGNUP_EMAIL" \
  --data-urlencode 'consent=on'

Read the confirmed result.

201

New JSON signup. A row was saved. The response contains success: true and removalToken: a random 64-character lowercase hexadecimal credential. Save it privately.

200

Existing JSON signup. Returns {"success":true}. The original removal credential is retained and never disclosed by an email lookup.

200

Successful native form. Returns an HTML confirmation. A newly saved signup also shows its private removal link and token.

A success response requires a successful D1 operation. This endpoint does not send email. Validated attempts, including duplicates, share a limit of ten per network address per Unix-time hourly bucket. The next attempt receives 429 and Retry-After seconds.

POST

/api/remove

Present the private credential.

token REQUIRED STRING
Must match ^[a-f0-9]{64}$. The server hashes it and deletes the matching signup. No email address is needed.

JSON success is {"success":true} with status 200. Native form success is an HTML confirmation.

An unknown but well-formed token also succeeds. Removal is idempotent and does not reveal whether a row existed. It uses the shared request checks but not the signup rate limiter.

Browser / removal
// token comes from the saved private removal link.
const response = await fetch('/api/remove', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ token })
});
const result = await response.json();
if (!response.ok || result.success !== true) {
  throw new Error('Removal was not confirmed.');
}
Keep the credential out of URLs sent to servers.

The website puts it after # in the private link, then submits it in a POST body. Do not put it in query parameters or logs.

When a request fails.

Errors are JSON objects with success: false and a human-readable error string. There is no separate machine-readable error code.

400
Invalid input, malformed JSON, missing consent, a filled honeypot or an invalid removal token.
403
A supplied Origin differs from the request origin, or Sec-Fetch-Site is cross-site.
405
The request method is not POST. The response includes Allow: POST.
413
The request body exceeds 2,048 bytes.
415
Content-Type is not application/json or application/x-www-form-urlencoded.
429
Signup attempt limit reached. Retry-After contains the seconds until the next hourly bucket. Signup only.
503
The required database binding is unavailable or the database operation failed.

Correct invalid input before retrying. Respect Retry-After. For network failures and 503, show an unconfirmed state and offer a later retry.

Persistence and delivery are different.

A row may be saved even if its response is lost. A retry then returns duplicate success without the original removal token. There is no email delivery or credential-recovery flow in this implementation.

REAL CODE. DOCUMENTED BOUNDARIES.Back to the handbook ↑