---
title: "Send a passwordless sign-in link to an email address"
method: POST
path: "/auth/magic-link"
tags: ["Auth"]
---

# Send a passwordless sign-in link to an email address

`POST /auth/magic-link`

## Request

- Base URL: `https://api.nippy.host`
- URL: `https://api.nippy.host/auth/magic-link`
- Auth: none declared

## Request body

- MagicLinkRequestDto
  - `email` string, email, required: Email address to send the magic sign-in link to
  - `callbackPath` string: Path to embed in the magic link, relative to the app origin (e.g. "/dashboard")
  - `ref` string: First-touch acquisition channel (e.g. "cli", "mcp", "extension", a launch slug). Recorded on the user only if this request creates the account; ignored for existing users.
  - `checkoutPlan` 'basic' | 'pro': When set, the magic link returns the user straight into Stripe Checkout for this paid plan after their email is verified (verify-then-checkout, ADR 0030). Only personal-eligible tiers; the Team plan needs an org.
  - `checkoutInterval` 'month' | 'year': Billing cadence for the carried checkout intent.
  - `checkoutCurrency` 'usd' | 'gbp' | 'eur' | 'chf': Presentment currency for the carried checkout intent; omitted lets Stripe localize.

## Response `200`

A magic link will be emailed if the address is valid. The response is identical regardless of whether an account already exists.

- APIMessageResponse
  - `message` string, required

## Other responses

- `400`: Invalid input data
- `422`: The address cannot be used for a new account (ADR 0048). The body carries `code: "EMAIL_DOMAIN_NOT_ALLOWED"` (a blocked or disposable domain), `code: "EMAIL_ALIAS_NOT_ALLOWED"` (a `+` alias) or `code: "ACCOUNT_LIMIT_REACHED"` (a likely second account, ADR 0050). Existing users are never refused.

---

[API](https://skmtc.dev/nippy/apis/nippy-backend-api.md) · [All operations](https://skmtc.dev/nippy/apis/nippy-backend-api/llms.txt) · [OpenAPI document](https://skmtc.dev/nippy/apis/nippy-backend-api/revisions/7ab23f040a55?raw)
