Magic-Link — API Reference
Public endpoints
POST /api/magic-link/send
Request a magic link by email.
curl -X POST http://localhost:1337/api/magic-link/send \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com"}'Response:
200 OK
{
"message": "Magic link sent",
"expiresIn": 900
}Rate-limited per IP and per email.
GET /api/magic-link/verify?token=...
Verify a magic link token. On success returns a JWT.
curl "http://localhost:1337/api/magic-link/verify?token=eyJ..."Success (Free tier, or Premium without OTP):
200 OK
{
"jwt": "eyJ...",
"user": { "id": 1, "email": "user@example.com", "username": "..." }
}Success (Premium with OTP required):
200 OK
{
"requiresOtp": true,
"magicLinkId": "ml_abc123",
"otpExpiresIn": 300
}Error:
410 Gone
{ "error": "TOKEN_EXPIRED" | "TOKEN_ALREADY_USED" | "TOKEN_INVALID" }POST /api/magic-link/otp/verify (Premium)
Verify email OTP after link click.
curl -X POST http://localhost:1337/api/magic-link/otp/verify \
-H "Content-Type: application/json" \
-d '{"magicLinkId":"ml_abc123","otp":"123456"}'→ { "jwt": "...", "user": {...} }
POST /api/magic-link/totp/enroll (Advanced)
Begin TOTP enrollment. Requires authenticated JWT.
curl -X POST http://localhost:1337/api/magic-link/totp/enroll \
-H "Authorization: Bearer <jwt>"→ { "qrCodeUri": "...", "secret": "...", "backupCodes": ["...", ...] }
POST /api/magic-link/totp/verify (Advanced)
Verify a TOTP code at login (or post-link).
curl -X POST http://localhost:1337/api/magic-link/totp/verify \
-H "Content-Type: application/json" \
-d '{"code":"123456"}'→ { "jwt": "..." }
Supports backup codes:
-d '{"backupCode":"12345678"}'POST /api/magic-link/totp/disable (Advanced)
Disable MFA on the current user. Requires current TOTP code.
curl -X POST http://localhost:1337/api/magic-link/totp/disable \
-H "Authorization: Bearer <jwt>" \
-d '{"code":"123456"}'→ { "disabled": true }
Rate-limit headers
Every response includes:
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 7
X-RateLimit-Reset: 1712000000When rate-limited:
429 Too Many Requests
Retry-After: 2400
{ "error": "RATE_LIMITED", "retryAfter": 2400 }Admin endpoints
All admin endpoints require a Strapi admin token (header Authorization: Bearer <admin-token>).
| Method | Path | Purpose |
|---|---|---|
| GET | /magic-link/settings | Get current plugin config |
| PUT | /magic-link/settings | Update settings |
| GET | /magic-link/stats | Login/send stats per day |
| GET | /magic-link/banned-ips | List banned IPs |
| DELETE | /magic-link/banned-ips/:ip | Unban an IP |
| GET | /magic-link/tokens | List active tokens (for audit) |
| DELETE | /magic-link/tokens/:id | Revoke a specific token |
Error codes
| Code | Meaning |
|---|---|
TOKEN_EXPIRED | Token past TTL |
TOKEN_ALREADY_USED | One-time token was already consumed |
TOKEN_INVALID | Signature verification failed |
OTP_INVALID | Wrong OTP code |
OTP_EXPIRED | OTP past 5-minute TTL |
TOTP_INVALID | Wrong TOTP code |
RATE_LIMITED | Too many requests |
ACCOUNT_DISABLED | User is blocked |
EMAIL_INVALID | Malformed email |
MFA_REQUIRED | User has MFA enabled but did not provide code |
Integration with Magic-Sessionmanager
When Magic-Sessionmanager is installed, every successful verification creates a session record. Force logout in Sessionmanager invalidates both the JWT and refresh token.
Next: Examples →