Learn how to integrate MagicAuth passwordless authentication into your application in minutes.
Base URL:
https://magicauth.app/api
Sign up at magicauth.app/dashboard and create an app to get your API key.
POST /api/send-link
Content-Type: application/json
{
"email": "user@example.com",
"app_key": "your_app_key_here",
"redirect_url": "https://yourapp.com/dashboard"
}
They're redirected to:
https://yourapp.com/dashboard?magic_token=xxx
POST /api/verify-token
Content-Type: application/json
{
"token": "xxx",
"app_key": "your_app_key_here"
}
Create a session on your backend using the verified user data.
POST /api/send-link
{
"email": "user@example.com", // Required
"app_key": "your_app_key", // Required
"redirect_url": "https://..." // Optional
}
{
"success": true,
"message": "Magic link sent to email",
"expires_at": "2025-11-13T12:45:00Z"
}
{
"success": false,
"error": "Rate limit exceeded",
"retry_after": 60
}
POST /api/verify-token
{
"token": "abc123...", // Required (from URL param)
"app_key": "your_app_key" // Required
}
{
"success": true,
"user": {
"id": 123,
"email": "user@example.com",
"name": null,
"email_verified_at": "2025-11-13T12:30:00Z",
"last_login_at": "2025-11-13T12:45:00Z"
},
"token": "jwt_token_here",
"redirect_url": "https://yourapp.com/dashboard"
}
// Invalid token
{
"success": false,
"error": "Invalid token"
}
// Token already used
{
"success": false,
"error": "Token already used"
}
// Token expired (default: 15 minutes)
{
"success": false,
"error": "Token expired"
}
// Send magic link
async function sendMagicLink(email) {
const response = await fetch('https://magicauth.app/api/send-link', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: email,
app_key: process.env.MAGICAUTH_APP_KEY,
redirect_url: 'https://yourapp.com/auth/callback'
})
});
const data = await response.json();
return data;
}
// Verify token (in your /auth/callback route)
app.get('/auth/callback', async (req, res) => {
const token = req.query.magic_token;
const response = await fetch('https://magicauth.app/api/verify-token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
token: token,
app_key: process.env.MAGICAUTH_APP_KEY
})
});
const data = await response.json();
if (data.success) {
// Create session for user
req.session.user = data.user;
res.redirect('/dashboard');
} else {
res.redirect('/login?error=' + data.error);
}
});
// Send magic link
public function sendMagicLink(Request $request)
{
$response = Http::post('https://magicauth.app/api/send-link', [
'email' => $request->email,
'app_key' => env('MAGICAUTH_APP_KEY'),
'redirect_url' => url('/auth/callback')
]);
return $response->json();
}
// Verify token
public function callback(Request $request)
{
$token = $request->query('magic_token');
$response = Http::post('https://magicauth.app/api/verify-token', [
'token' => $token,
'app_key' => env('MAGICAUTH_APP_KEY')
]);
$data = $response->json();
if ($data['success']) {
Auth::loginUsingId($data['user']['id']);
return redirect('/dashboard');
}
return redirect('/login')->with('error', $data['error']);
}
import requests
import os
# Send magic link
@app.route('/send-link', methods=['POST'])
def send_magic_link():
response = requests.post('https://magicauth.app/api/send-link', json={
'email': request.json['email'],
'app_key': os.environ['MAGICAUTH_APP_KEY'],
'redirect_url': 'https://yourapp.com/auth/callback'
})
return response.json()
# Verify token
@app.route('/auth/callback')
def callback():
token = request.args.get('magic_token')
response = requests.post('https://magicauth.app/api/verify-token', json={
'token': token,
'app_key': os.environ['MAGICAUTH_APP_KEY']
})
data = response.json()
if data['success']:
session['user'] = data['user']
return redirect('/dashboard')
return redirect('/login?error=' + data['error'])
400 Bad Request
Missing required fields or invalid data
401 Unauthorized
Invalid app_key
403 Forbidden
App disabled or redirect URL not whitelisted
429 Too Many Requests
Monthly limit exceeded - upgrade your plan
500 Internal Server Error
Something went wrong on our end
| Plan | Links/Month | Burst Limit | Ads |
|---|---|---|---|
| Free Forever | Unlimited | 100/minute | Sponsored emails + in-page ads |
| Custom | Unlimited | Custom | Ad-free (contact sales) |
✓ Always use HTTPS
Never send API keys over HTTP
✓ Whitelist redirect URLs
Configure allowed domains in your dashboard to prevent phishing
✓ Store app_key securely
Use environment variables, never commit to git
✓ Verify tokens server-side
Never trust client-provided authentication - always verify with our API
✓ Tokens are single-use
Each token can only be verified once and expires after 15 minutes
Create your free account and start sending magic links in minutes
Get Your API Key