API ReferenceAuthentication APIPOST /register

POST /auth/register

Create a new user in your project. This endpoint allows new users to sign up with email and password.

Authentication: This endpoint does not require authentication. It’s a public endpoint.

Endpoint

POST /api/v1/public/projects/:projectSlug/auth/register

Request Parameters

Path Parameters

ParameterTypeRequiredDescription
projectSlugstringβœ…Your project’s unique slug (found in admin dashboard)

Request Body

FieldTypeRequiredDescription
emailstringβœ…User’s email address (must be valid format)
passwordstringβœ…Strong password (minimum 8 characters)
namestring❌User’s display name
customFieldsobject❌Additional fields configured in project settings
turnstileTokenstring❌Cloudflare Turnstile token for captcha verification

Example Request Body

{
  "email": "user@example.com",
  "password": "StrongPassword123!",
  "name": "Jane Doe",
  "customFields": {
    "company": "Acme Inc",
    "phone": "+1-555-1234"
  }
}

Response

Success (201 Created)

{
  "user": {
    "id": "user-uuid-here",
    "email": "user@example.com",
    "name": "Jane Doe",
    "email_verified_at": null,
    "profile_extras": {
      "company": "Acme Inc",
      "phone": "+1-555-1234"
    }
  },
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
⚠️

The token field may be null if email verification is required for your project. In this case, the user must verify their email before receiving a JWT token.

Error Responses

Status CodeError CodeDescription
400INVALID_REQUESTValidation failed (weak password, invalid email, missing required fields)
409EMAIL_ALREADY_IN_USEAn account with this email already exists
429RATE_LIMIT_EXCEEDEDToo many signup requests from this IP
500INTERNAL_SERVER_ERRORServer error occurred

Example Error Response

{
  "error": "EMAIL_ALREADY_IN_USE",
  "message": "An account with this email already exists",
  "details": {
    "email": "user@example.com"
  }
}

Available Hooks

This endpoint can trigger the following project-specific hooks:

Lifecycle Hooks

  • beforeSignup

    • When: After base validation, before user is created in database
    • Can do: Enforce extra validation (e.g., only allow @company.com emails), 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

  • Event: auth.signup
    • When: After successful user creation
    • Can do: Call external webhooks (HTTP endpoints you host), run script hooks with the Hook SDK

Learn more about hooks β†’

Try It Now

POSThttps://api.aerocall.app/api/v1/public/projects/your-project/auth/register

SDK Examples

JavaScript / TypeScript

const response = await fetch(
  'https://api.aerocall.app/api/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 requests
localStorage.setItem('authToken', token);

React

import { useState } from 'react';
 
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.aerocall.app/api/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

import { useState } from 'react';
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.aerocall.app/api/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

Security: Always use HTTPS in production. Never expose API keys or sensitive tokens in client-side code.

βœ… 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

Need Help?