POST /auth/register
Create a new user in your project. This endpoint allows new users to sign up with email and password (password required).
Endpoint
Section titled “Endpoint”POST /v1/public/projects/:projectSlug/auth/registerRequest Parameters
Section titled “Request Parameters”Path Parameters
Section titled “Path Parameters”| Parameter | Type | Required | Description |
|---|---|---|---|
projectSlug | string | ✅ | Your project’s unique slug (found in admin dashboard) |
Request Body
Section titled “Request Body”| Field | Type | Required | Description |
|---|---|---|---|
email | string | ✅ | User’s email address (valid format) |
password | string | ✅ | Strong password (8+ chars, mixed case + number) |
name | string | ❌ | User’s display name |
customFields | object | Depends* | Keys must match Dashboard → Project → Auth → Custom Registration Fields. Prebuilt (e.g. phone) and custom keys go here. |
turnstileToken | string | ❌ | Turnstile token for captcha (if enabled) |
* Each custom field has its own required flag in admin. Required custom fields must be present or the API returns 400.
Prebuilt and Custom Fields
Section titled “Prebuilt and Custom Fields”Prebuilt fields (system-recognized):
phone– Add a custom field with keyphonein admin to collect during signup. Send ascustomFields.phone. Stored in profile (returned by GET /auth/me). The dedicatedusers.phonecolumn is used only for Phone OTP signups.
Custom fields: Any other keys you configure (e.g. company, role). Stored in profile_extras.
Important: Only fields you add in Dashboard → Project → Auth → Custom Registration Fields are accepted. Unconfigured keys in customFields are ignored.
| Field | Required | Configured In |
|---|---|---|
| Yes | (always) | |
| password | Yes | (always) |
| name | No | (always) |
| customFields.* | Per field | Auth → Custom Registration Fields (key + required toggle) |
See Configuration scenarios for per-method examples (Email only, Phone only, Both).
Example Request Body
Section titled “Example Request Body”{ "email": "user@example.com", "password": "StrongPassword123!", "name": "Jane Doe", "customFields": { "company": "Acme Inc", "phone": "+1-555-1234" }}Add phone and company in Auth → Custom Registration Fields first. Mark Required for any field that must be present.
Response
Section titled “Response”Success (200 OK)
Section titled “Success (200 OK)”When email verification is NOT required (or user already verified):
{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "user": { "id": "user-uuid-here", "email": "user@example.com", "name": "Jane Doe" }, "requiresVerification": false}When email verification IS required (project has “Require Email Verification” enabled):
{ "requiresVerification": true, "message": "Please check your email to verify your account before signing in.", "user": { "id": "user-uuid-here", "email": "user@example.com", "name": "Jane Doe" }}No token is returned until the user verifies their email. Use GET /auth/verify-email (link in email) then POST /auth/login or POST /auth/otp/verify.
Error Responses
Section titled “Error Responses”| Status Code | Error Code | Description |
|---|---|---|
| 400 | INVALID_REQUEST | Validation failed (weak password, invalid email, missing required fields) |
| 409 | EMAIL_ALREADY_IN_USE | An account with this email already exists |
| 429 | RATE_LIMIT_EXCEEDED | Too many signup requests from this IP |
| 500 | INTERNAL_SERVER_ERROR | Server error occurred |
Example Error Response
Section titled “Example Error Response”{ "error": "EMAIL_ALREADY_IN_USE", "message": "An account with this email already exists", "details": { "email": "user@example.com" }}Available Hooks
Section titled “Available Hooks”This endpoint can trigger the following project-specific hooks:
Lifecycle Hooks
Section titled “Lifecycle Hooks”-
beforeSignup- When: After base validation, before user is created in database
- Can do: Enforce extra validation (e.g., only allow
@company.comemails), modify custom fields, throw errors to reject signup with custom message
-
afterSignup- When: After user is successfully created (and after verification email is queued if enabled)
- Can do: Send welcome emails, sync to CRM, create related records, enqueue background jobs
Webhook Events
Section titled “Webhook Events”- Event:
auth.signup- When: After successful user creation
- Can do: Call external webhooks (HTTP endpoints you host), run script hooks with the Hook SDK
Try It Now
Section titled “Try It Now”https://api.aerostack.dev/v1/public/projects/your-project/auth/registerSDK Examples
Section titled “SDK Examples”JavaScript / TypeScript
Section titled “JavaScript / TypeScript”const response = await fetch( 'https://api.aerostack.dev/v1/public/projects/your-project/auth/register', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ email: 'user@example.com', password: 'StrongPassword123!', name: 'Jane Doe' }) });
if (!response.ok) { const error = await response.json(); console.error('Signup failed:', error); throw new Error(error.message);}
const { user, token } = await response.json();console.log('User created:', user);
// Store token for authenticated requestslocalStorage.setItem('authToken', token);function SignupForm() { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [name, setName] = useState(''); const [loading, setLoading] = useState(false); const [error, setError] = useState(null);
const handleSignup = async (e) => { e.preventDefault(); setLoading(true); setError(null);
try { const res = await fetch('https://api.aerostack.dev/v1/public/projects/your-project/auth/register', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password, name }) });
if (!res.ok) { const errorData = await res.json(); throw new Error(errorData.message); }
const { user, token } = await res.json();
// Store token localStorage.setItem('authToken', token);
// Redirect or update UI window.location.href = '/dashboard'; } catch (err) { setError(err.message); } finally { setLoading(false); } };
return ( <form onSubmit={handleSignup} className="space-y-4"> {error && ( <div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded"> {error} </div> )}
<input type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email" required className="w-full px-4 py-2 border rounded" />
<input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="Password" required minLength={8} className="w-full px-4 py-2 border rounded" />
<input type="text" value={name} onChange={(e) => setName(e.target.value)} placeholder="Name (optional)" className="w-full px-4 py-2 border rounded" />
<button type="submit" disabled={loading} className="w-full bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded disabled:opacity-50" > {loading ? 'Signing up...' : 'Sign Up'} </button> </form> );}React Native
Section titled “React Native”import { View, TextInput, Button, Alert, ActivityIndicator } from 'react-native';import AsyncStorage from '@react-native-async-storage/async-storage';
export default function SignupScreen({ navigation }) { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [name, setName] = useState(''); const [loading, setLoading] = useState(false);
const handleSignup = async () => { setLoading(true);
try { const response = await fetch( 'https://api.aerostack.dev/v1/public/projects/your-project/auth/register', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ email, password, name }) } );
const data = await response.json();
if (!response.ok) { throw new Error(data.message || 'Signup failed'); }
const { user, token } = data;
// Store token securely await AsyncStorage.setItem('authToken', token);
Alert.alert('Success', 'Account created successfully!'); navigation.navigate('Dashboard'); } catch (error) { Alert.alert('Error', error.message); } finally { setLoading(false); } };
return ( <View style={{ padding: 20 }}> <TextInput placeholder="Email" value={email} onChangeText={setEmail} autoCapitalize="none" keyboardType="email-address" style={{ borderWidth: 1, padding: 10, marginBottom: 10, borderRadius: 5 }} />
<TextInput placeholder="Password" value={password} onChangeText={setPassword} secureTextEntry style={{ borderWidth: 1, padding: 10, marginBottom: 10, borderRadius: 5 }} />
<TextInput placeholder="Name (optional)" value={name} onChangeText={setName} style={{ borderWidth: 1, padding: 10, marginBottom: 15, borderRadius: 5 }} />
{loading ? ( <ActivityIndicator size="large" /> ) : ( <Button title="Sign Up" onPress={handleSignup} /> )} </View> );}Best Practices
Section titled “Best Practices”✅ Validate input on both client and server side
✅ Use strong passwords - enforce minimum 8 characters with mixed case, numbers, and special characters
✅ Handle errors gracefully - show user-friendly error messages
✅ Store tokens securely - use httpOnly cookies for web or secure storage for mobile
✅ Implement rate limiting on your frontend to prevent abuse
✅ Consider email verification - enable in project settings for added security
Related Endpoints
Section titled “Related Endpoints”- POST /auth/login - Authenticate existing users
- GET /auth/me - Get current user information
- POST /auth/resend-verification - Resend verification email
- POST /auth/reset-password-request - Request password reset
Need Help?
Section titled “Need Help?”- 📖 Quick Start Guide: Get started in 5 minutes
- 💬 Discord: Join our community
- 📧 Support: support@aerostack.dev