Creator Flow
From a rough token idea to a scored, enrolled, and launched token.
The happy path (5 minutes)
- Score it at
/launch— name, ticker, one-paragraph pitch, image URL, X handle, creator wallet. Submit. - Read the score at
/score/:id. Aggregate + band + six-signal breakdown + explanation + OG share card. Copy the URL and share it. - Iterate, if amber/red — the "Why this score?" block tells you which signals are dragging. Re-score after editing the weakest one (usually image or social).
- Enroll — click "Enroll for launch" on the score page. Connect wallet, sign an EIP-191 message. No gas, no transaction.
- Schedule — optional. Pick a launch time in your timezone. Hatch schedules T-60min / T-10min / T+0 notifications automatically.
- Share the pre-launch page —
/score/:id/launchis a countdown + share card. This is the URL you post to your community. - Launch on Four.meme — Hatch doesn't replace Four.meme. You still launch via their bonding curve. The hatching-window integration (E.1) reserves the first 60s for verified humans.
- Watch the dashboard —
/dashboard(wallet-gated) shows every launch you enrolled, scheduled dispatches, attendance, share links.
Enrolling — what happens under the hood
You click "Enroll for launch"
↓
Web fetches GET /v1/enroll/message?scoreRequestId=<id>&creatorAddress=<addr>
↓
Returns canonical string:
"Hatch Enrollment
Score: <id>
Creator: <0x…>
Domain: gohatch.fun"
↓
Wallet prompts personal_sign
↓
Web POSTs { scoreRequestId, creatorAddress, signature, scheduledFor? }
↓
API verifies signature via viem, checks:
- score exists
- hasStubs === false (else 409 has_stubs)
- creatorAddress matches stored submission (else 409 conflict)
- not already enrolled by a different creator (else 409 conflict)
↓
Save enrollment. Seed notifications. Emit enrollment.created webhook.
↓
Web redirects to /score/:id/launch (confirmation page with countdown)
Why EIP-191, not EIP-712
The message is user-facing — the creator reads it in MetaMask. A newline-delimited canonical string reads naturally; EIP-712 is overkill for a two-field payload. Domain line prevents cross-deployment replay.
Idempotency
Same creator signing the same score → same enrollment record (no new
row, 200 OK). A different creator attempting to enroll the same score →
409 conflict. This keeps the "first enrollment wins" invariant strict
without making the UX fragile.
Scheduling + notifications
When you set scheduledFor, the API seeds three notification slots:
| Offset | Purpose | Default transport |
|---|---|---|
| T-60min | "Launch in 1 hour" heads-up | logging (D.5 swaps to Telegram+email) |
| T-10min | "10 minutes out" final push | logging |
| T+0 | "Launching now" | logging |
The dispatcher runs via POST /v1/launch/dispatch (admin bearer). In
production this is a cron-driven tick on Railway.
You can override the default schedule by editing the launch page:
PATCH /v1/launch/:id/page with a creator-signed payload.
Public profile
/creator/:address is your public profile. It pulls every enrollment
signed by that wallet and shows:
- Total enrolled launches.
- Green/amber/red band counts (preliminary excluded).
- Latest 25 launches with score + band.
This is the URL you can link from your Twitter bio — proof of the launches you've put on Hatch.
See API.md GET /api/v1/creator/:address.
Dashboard (wallet-connect)
/dashboard — client-driven. Connect
your wallet; the page fetches /api/creator/:address (web proxy) with
your address and renders:
- Every launch you enrolled.
- Band + aggregate.
- Scheduled launch time + notification state.
- Attendance stats (pageviews, unique sessions).
- Share URLs (score page, launch page, OG image).
Session state lives in localStorage — no server session, no cookies.
Editing the pre-launch page
On /score/:id/launch, click "Edit this page". The editor is
creator-signed: every save sends a viem-verified signature so the API
can prove the change came from the enrolled creator, not a random
visitor.
Editable fields:
tagline— one-line hook above the countdown.description— longer pitch for your community.ctaLabel+ctaUrl— e.g., "Join our Telegram" + link.
Changes take effect immediately. Copy rate-limits: 60 edits/min/creator.
Common errors
| Error | Cause | Fix |
|---|---|---|
has_stubs (409) on enroll |
Score has preliminary signals | Wait for keys, re-score, then enroll |
conflict (409) on enroll |
Different wallet already enrolled | Only the original creator can enroll |
not_found (404) on score |
UUID mismatch / stale URL | Score via /launch to generate a fresh UUID |
rate_limit (429) on score |
60/min/IP limit | Wait a minute, or use an API key for higher tier |
| No wallet prompt on enroll | No EVM wallet installed | Install MetaMask or any EVM-compatible browser wallet |
See support FAQ for more.