---
title: "Signup"
method: POST
path: "/api/v1/auth/signup"
tags: ["grandline-auth"]
---

# Signup

`POST /api/v1/auth/signup`

## Request

- Base URL: `https://grandline.luzomi.com`
- URL: `https://grandline.luzomi.com/api/v1/auth/signup`
- Auth: none declared

Start the magic-link signup flow.

1. Validate the email against the Company-Email policy (G-014).
2. Idempotency: if this email already has an unexpired attempt
   (within the 15-minute TTL), do nothing and return the same
   success response — never spam a second email.
3. Otherwise: generate a fresh 32-byte token, store its SHA-256
   hash in Postgres (durable) and Redis (hot lookup with TTL),
   and dispatch the email.

Always returns the same success message regardless of whether a
new email was sent — keeps the response side-channel-free for
enumeration attempts.

## Request body

- SignupRequest
  - `email` string, required: Company email (not generic, not a free provider)
  - `company_name` string, required
  - `what_building` string, nullable: Optional: one-line answer to 'what are you building?'

## Response `200`

Successful Response

- SignupResponse
  - `message` string, required

## Other responses

- `400`: Validation error
- `422`: Validation Error
- `429`: Rate-limit exceeded

---

[API](https://skmtc.dev/luzomi/apis/grandline-api.md) · [All operations](https://skmtc.dev/luzomi/apis/grandline-api/llms.txt) · [OpenAPI document](https://skmtc.dev/luzomi/apis/grandline-api/revisions/4ce06aea012b?raw)
