Skip to content
Hypamoon
API docs

Start for free. Sign up without a card and you'll get a test project and a test key right away. Once your company (or, for a personal account, you) is verified, you can create a live key in the portal.

Quickstart

Hypamoon is the infrastructure your chat builds on for a business. Your site goes live on a real address or your own domain, your forms keep every message, and when you want more, the same project adds an app with sign-in, a checkout, email from your domain, a phone number that answers and agents. Your chat reaches it through MCP, your code through the REST API; both work on the same project.

Sign up at https://app.hypamoon.com with your email address. It's free, needs no card, and gives you a test project and a test key right away. Then pick your track: from your chat, without code, or from code, with curl. Both end with a site that has a working contact form.

From your chat

No code, no hosting, no form service. You talk, and your chat does the work.

1. Connect Hypamoon once

Add Hypamoon to Claude, ChatGPT or Grok as a connector and sign in. It takes a minute: Connect your chat shows every click. In ChatGPT it is Plugins, Add, Add custom MCP server, also on the free plan. Or download the plugin archive and upload it in ChatGPT or Claude. Grok connectors work on every Grok plan, the free one included. Claude Code, Cursor and Grok Build sign in the same way; Lovable uses a key for the time being (see MCP). No account yet? You'll create one as you sign in.

2. Publish your site

Your chat asks for what it needs, writes the page and publishes it. You'll get a link like https://acme-bakery.hypamoon.app that works on any phone. Want a change? Say it ("make the opening hours bigger") and the link stays the same.

3. Add a contact form

Every message is saved in your project, with a bot check in front of the form. In live mode it also lands in your inbox, and your reply goes straight to the visitor. In your test project the messages are saved, but no email is sent.

4. Read what came in

Your chat reads the messages, newest first, and tells you who wants what. Ask a follow-up like "only this week" or "mark Ann's question as answered".

5. Choose where it lives

Your chat connects a domain you already own and copies its existing records first, so your email keeps working. Then it tells you the two nameservers to set at your registrar, and keeps checking until the site is live on your domain.

No domain? Pick how people find the site:

  • Public: on its readable address, for everyone. "Change the address of my site to acme-bakery."
  • Unlisted: only on a secret link, kept out of search engines. "Make my site unlisted."
  • Password: one shared password for every visitor. "Put a password on my site so only my team can see it."

What next

  • A number that answers. "Give my business a number that rings me first and lets the receptionist pick up when I can't." See Phone, SMS and chat.
  • Agents. "When a new request comes in, email me a short summary." An agent follows your instructions when something happens and asks you before it contacts anyone. See Agents.
  • Apps. Server code under your site's /api path, with your data and secrets within reach. See Apps.
  • Versions. Every change to your site is kept, on every plan; "go back to yesterday's version" puts it back, and "put app.js back the way it was" restores just that file. If an agent tries to replace most of your site in one go, the change waits as a preview until you say yes. See Pricing for how long versions are kept.
  • Payments: a checkout on your own site, paid into your own account. See Payments.

Say this has more sentences that work today.

From code

The same steps with the REST API. Every call below is a real path with real field names; the API reference has every option.

  • The base URL is https://api.hypamoon.com/api/v1.
  • $HYPAMOON_API_KEY is your key. Keep it on your server, never in a page.
  • Every error is application/problem+json with a type URL that explains the fix, like https://hypamoon.com/docs/errors/version_conflict.

1. Get your test key

Right after you sign up, the portal shows your first test key (hm_test_...) once. Store it as a secret. It belongs to your test project: it has every scope, never costs anything and needs no payment method. Sites and data are real in test mode too, so your site is public right away; email, calls and SMS are simulated.

Your live project sits alongside it. Once your company (or, for a personal account, you) is verified under Verification, you create a live key (hm_live_...) yourself in the portal under API keys. Your code stays the same; only the key changes. See Test mode and Authentication.

curl
curl https://api.hypamoon.com/api/v1/project \
  -H "Authorization: Bearer $HYPAMOON_API_KEY"

The response says "mode": "test" and shows your project.

2. Publish a site

Send the files the browser loads: at least /index.html, plain HTML, CSS and JavaScript. There is no build step, so send built output, never React or Vite source.

curl
curl -X POST https://api.hypamoon.com/api/v1/sites \
  -H "Authorization: Bearer $HYPAMOON_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Bakery",
    "slug": "acme-bakery",
    "files": [
      { "path": "/index.html", "content": "<!doctype html><html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><title>Acme Bakery</title><link rel=\"stylesheet\" href=\"/style.css\"></head><body><h1>Acme Bakery</h1><p>Fresh bread every morning from 7.</p></body></html>" },
      { "path": "/style.css", "content": "body { font-family: system-ui, sans-serif; margin: 2rem; }" }
    ]
  }'
JSON
{
  "id": "6a7b8c9d-1e2f-4a5b-8c7d-9e0f1a2b3c4d",
  "slug": "acme-bakery",
  "name": "Acme Bakery",
  "url": "https://acme-bakery.hypamoon.app",
  "files": [
    { "path": "/index.html", "content_type": "text/html", "bytes": 296, "updated_at": "..." },
    { "path": "/style.css", "content_type": "text/css", "bytes": 58, "updated_at": "..." }
  ],
  "version": "k3Q9vXbT2mLc8Rw1",
  "password_protected": false,
  "test": true,
  "taken_offline": null,
  "...": "..."
}

The site is live at url as soon as the call returns. Leave out slug and we'll make one from name; to check first, GET /sites/address-suggestions?name=Acme%20Bakery suggests available ones. Images and fonts work best as "source_url": "https://...", which we fetch once.

Change it with PUT /sites/{id}; the URL stays the same. Send "keep_existing": true, the current version as "if_match_version", and only the files you add or change (delete_paths removes files). If someone changed the site in the meantime, you'll get 409 version_conflict with current_version, and nothing is changed.

Coming from another static host? Send your redirects and headers along as two plain-text files.

/_redirects has one rule per line: from, to, and a status (301, 302, 307 or 308; 301 if you leave it out). To is a path on your site or a full https:// URL. A * at the end of from matches everything under it, and :splat puts that part in the path of to. The domain of an outside URL is always the one in the file; nothing a visitor types can change it, and the query is not passed on.

/challenge     https://appchallenge.hypamoon.com   301
/docs/*        https://docs.example.com/:splat     301
/blog/old/*    /blog/:splat                        308
/?p=12         /my-post/                           301

/_headers sets response headers per path, like Netlify: a path line, then the headers indented below it. Allowed: Content-Security-Policy, X-Frame-Options, Referrer-Policy, Permissions-Policy, Cache-Control (up to a year), Link, Strict-Transport-Security without preload, Access-Control-Allow-* (not on /api) and your own X- headers. Not allowed, and deploy_site names the line: Set-Cookie, Location, Content-Type, Content-Length, anything under /_hypamoon/. At most 100 paths and 300 header lines.

/*
  X-Frame-Options: DENY
  Referrer-Policy: strict-origin-when-cross-origin
  Permissions-Policy: camera=(), microphone=()
/_next/static/*
  Cache-Control: public, max-age=31536000, immutable

Your Content-Security-Policy is applied next to ours (ours only limits where forms may post), and a password-protected site always stays private, no-store.

A Next.js static export (output: "export" in next.config) deploys as it is: send the files in out/, /_next/ included, without assetPrefix. Route handlers, middleware and server rendering do not export; put that code in an app on /api. A path may use letters, digits and . _ ~ -, so leave out the __next.*.txt prefetch files whose names hold other characters (like ! for a route group): links then load the full page, which works the same. A webpack build can name chunks after a route like [slug]; build with Turbopack (the default since Next 16), or leave those files out.

3. Add a contact form

A form needs two things: a collection that accepts entries, and your project's public token.

curl
curl -X POST https://api.hypamoon.com/api/v1/collections \
  -H "Authorization: Bearer $HYPAMOON_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "contact",
    "access": { "public_write": true },
    "triggers": { "email_on_insert": true, "webhook_on_insert": true },
    "schema": {
      "type": "object",
      "properties": {
        "name": { "type": "string", "minLength": 1, "maxLength": 100 },
        "email": { "type": "string", "format": "email" },
        "message": { "type": "string", "minLength": 1, "maxLength": 5000 }
      },
      "required": ["name", "email", "message"]
    }
  }'

A collection is private until you say otherwise; public_write lets a form on your site add entries, behind a bot check and limits. email_on_insert emails every entry to your billing email address (live only), and webhook_on_insert sends document.created to your webhooks. The schema is optional; an entry that does not match is rejected with 422 schema_mismatch, naming the field that is wrong.

The public token is not a secret: it goes in the page, and only works from the origins you list.

curl
curl -X POST https://api.hypamoon.com/api/v1/chat-tokens \
  -H "Authorization: Bearer $HYPAMOON_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Acme Bakery site", "allowed_origins": ["https://acme-bakery.hypamoon.app"] }'

The response includes token (hm_pubtest_... with a test key). Put it in the form and add the form to index.html with another PUT /sites/{id}:

html
<form data-hypamoon-collection="contact" data-hypamoon-token="hm_pubtest_..." data-hypamoon-success="Thanks, we received your message.">
  <label for="name">Name</label>
  <input id="name" name="name" required>
  <label for="email">Email</label>
  <input id="email" name="email" type="email" required>
  <label for="message">Message</label>
  <textarea id="message" name="message" rows="5" required></textarea>
  <input type="text" name="website" data-hypamoon-honeypot tabindex="-1" autocomplete="off" aria-hidden="true" style="position:absolute;left:-9999px">
  <button type="submit">Send</button>
</form>
<script src="https://api.hypamoon.com/form.js" defer></script>

form.js adds the bot check, sends the fields, and shows the text from data-hypamoon-success. The name of each input becomes a field of the entry. A bot that fills in the hidden website field gets a thank you, and nothing is stored.

4. Read what came in

curl
curl https://api.hypamoon.com/api/v1/collections/contact/documents \
  -H "Authorization: Bearer $HYPAMOON_API_KEY"
JSON
{
  "data": [
    {
      "id": "be97ef66-6c17-491a-873f-ce173f8f3c87",
      "collection_id": "c27449ad-8fad-4125-a852-afbde676bdef",
      "data": { "name": "Ann Example", "email": "ann@example.com", "message": "Do you bake gluten-free bread?" },
      "source": "public",
      "created_at": "2026-10-06T16:37:26.605Z",
      "updated_at": "2026-10-06T16:37:26.605Z",
      "test": true
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Entries come newest first; follow next_cursor while has_more is true. Mark an entry as handled and list only those:

curl
curl -X PATCH https://api.hypamoon.com/api/v1/collections/contact/documents/be97ef66-6c17-491a-873f-ce173f8f3c87 \
  -H "Authorization: Bearer $HYPAMOON_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "merge": { "status": "answered" } }'

curl -G https://api.hypamoon.com/api/v1/collections/contact/documents \
  -H "Authorization: Bearer $HYPAMOON_API_KEY" \
  --data-urlencode 'filter={"status":"answered"}'

Testing without a browser? POST /collections/contact/documents with { "data": { ... } } adds an entry with your key ("source": "api").

5. Choose where it lives

Your own domain. Connect a domain you already own and put the site on it:

curl
curl -X POST https://api.hypamoon.com/api/v1/domains \
  -H "Authorization: Bearer $HYPAMOON_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "domain": "example.com", "site_id": "6a7b8c9d-1e2f-4a5b-8c7d-9e0f1a2b3c4d" }'

We copy the existing records first, email included, and respond with the two nameservers to set at your registrar and the next_step. Then POST /domains/{id}/activate checks whether they are in place and puts the site on the domain and on www once they are. Can't change the nameservers? Send "method": "cname" for www only. Looking for a new domain? Use GET /domains/check?domain=example.com.

Unlisted. Only on a secret link, kept out of search engines:

curl
curl -X PUT https://api.hypamoon.com/api/v1/sites/6a7b8c9d-1e2f-4a5b-8c7d-9e0f1a2b3c4d/address \
  -H "Authorization: Bearer $HYPAMOON_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "visibility": "unlisted" }'

The response has the secret link in url; "visibility": "public" brings the readable address back, and "slug" renames the site (the old address keeps redirecting for 90 days; at most 3 renames per site per 30 days). A change of address gives the site a new version, so read it again before your next PUT /sites/{id}.

Password. A secret link is not a login. For a site only your team may see, send { "password": "spring-tour-2027" } with PUT /sites/{id}: every visitor enters it once per browser. "password": null opens the site again.

6. Add a phone number

Same project, same key. Phone, SMS and chat takes you from here to a number that rings your team first and lets a voice AI pick up when nobody answers, with a webhook for every call. Calls and Webhooks describe what you get back.

Going live

When your test run works, finish the verification in the portal at https://app.hypamoon.com, create a live key under API keys and swap it in. The live project starts empty: deploy your site and create your collection there again with the live key. What a plan includes is on Pricing.

Let your coding agent do it

Paste this into Claude Code, Cursor or Lovable, with your test key in the environment as HYPAMOON_API_KEY:

Publish this site with the Hypamoon API (base URL https://api.hypamoon.com/api/v1,
auth "Authorization: Bearer $HYPAMOON_API_KEY"; never put the key in client code).

1. POST /sites with { name, slug, files }: the built output, at least /index.html.
   Save the returned id and version.
2. POST /collections with { name: "contact", access: { public_write: true },
   triggers: { email_on_insert: true }, schema } for name, email and message.
3. POST /chat-tokens with { name, allowed_origins: [<the site url>] } and use its
   token in a form with data-hypamoon-collection="contact" and
   data-hypamoon-token, plus <script src="https://api.hypamoon.com/form.js" defer>.
4. PUT /sites/{id} with keep_existing: true, if_match_version: <version> and only
   the changed files.
5. Show me how to read the entries: GET /collections/contact/documents.

Every error is application/problem+json. Its "type" is a URL that explains the fix;
read it and follow it before trying something else.
Hypamoon is the infrastructure your chat or agent builds on for a business. Hypamoon API, version 1.hypamoon.com