it be nice if the frontend followed the same protocol i made for the back json restful api returns. I dunno if this is ideal, but instead of just whatever data wherever. Here is how my backend returns look:

* API Return Structure for All Responses:
*
* 'success' => bool
* - Required boolean indicating the overall success (true) or failure (false) of the request.
*
* 'message' => string|null
* - Optional human-readable summary message intended for general user feedback.
*   For example: "Signup completed successfully." or "Validation failed. Please review errors."
*
* 'errors' => array|null
* - Optional detailed field-level errors provided as an associative array keyed by attribute name,
*   e.g. ['email' => ['Email already registered'], 'password' => ['Password too weak']]
* - Should be included typically for validation failures or form errors.
* - Should NOT aggregate all field errors into this or the 'message' string.
*
* 'data' => array|null
* - Optional container for domain-specific returned data relevant to the successful request,
*   such as user IDs, signup phases, tokens, or other payload.
*   Example: ['userId' => 123, 'signup_phase' => 2]
*
* Guidelines:
* - Always use the 'success' boolean to convey request outcome; do NOT rely on other status indicators.
* - Always include a clear and concise 'message' to aid frontend user messaging.
* - Only include 'errors' when there are validation or field-specific errors to display inline.
* - Group all additional return values inside the 'data' object to keep the response consistent.
* - Use appropriate HTTP status codes (e.g. 422 for validation errors, 200 for success) together
*   with this body structure for clarity and RESTfulness.
*
* Example error response:
* 	[
*		'success' => false,
*		'message' => 'Validation failed. Please review the errors.',
* 		'errors' => $model->getErrors(),
* 		// 'data' omitted
* 	]
*
* Example success response:
* 	[
* 		'success' => true,
*		'message' => 'Signup completed successfully.',
* 		'errors' => [],// or omitted
* 		'data' => [
*  			'userId' => $user->id,
* 			'signup_phase' => $user->signup_phase,
* 		]
*	 ]
*

Now i understand the apiClient for the frontend handles the bearer and csrf:

// src/services/apiClient.ts
import axios from 'axios';
import { API_BASE_URL } from '../constants/api';
import { emitEvent } from '../utils/eventBus';
import logger from '../utils/logger';

const apiClient = axios.create({
	baseURL: API_BASE_URL,
	withCredentials: true,// send cookies for CORS requests automatically
	headers:
	{
		'Content-Type': 'application/json',
	},
	timeout: 10000,// Aborts the request and throws an error after 10 seconds
	// timeout, etc.
});

/**
* Add request interceptor
*
* Axios interceptors allow you to intercept and modify requests or responses globally before 
* they are handled by your individual API calls.
* - Request interceptors run before a request is sent, letting you add headers (e.g., auth tokens), 
*   modify request config, or log requests.
* - Response interceptors run after receiving a response, enabling centralized error handling, token 
*   refresh logic, or response transformation.
* 
* Using interceptors helps keep your API client DRY, consistent, and easier to maintain.
*/
apiClient.interceptors.request.use((config) =>
{
	// e.g. attach Authorization token here if using JWT
	const token = localStorage.getItem('jwtToken') || userToken;// TODO - Or use context/state store
	
	if (token)
	{
		config.headers['Authorization'] = `Bearer ${token}`;
	}
	
	return config;
});

/**
* Add response interceptor to handle errors globally, refresh tokens, etc.
*/
apiClient.interceptors.response.use(
	(response) => response,// Pass through successful responses unchanged
	async (error) =>
	{
		// Handle Axios timeout errors explicitly
		if (error.code === 'ECONNABORTED' && error.message.includes('timeout'))
		{
			logger.warn('Request timed out:', error);
			emitEvent('alert', { type: 'warning', key: 'alert.timeout' });
			
			return Promise.reject(new Error('Request timed out. Please try again.'));
		}
		
		// Otherwise handle by HTTP status code
		const status = error.response?.status;
		
		switch (status)
		{
			case 400:
				// Bad Request — maybe validation failed
				logger.warn('400 Bad Request:', error);
				emitEvent('alert', { type: 'warning', key: 'alert.badRequest' });
				break;
				
			case 401:
				// Unauthorized — handle auth refresh or redirect login
				logger.error('Error 401 Unauthorized:', error);
				emitEvent('alert', { type: 'danger', key: 'alert.unauthorized' });
				
				// TODO: Add logic to refresh auth token here and retry the original request
				// Or redirect the user to the login page if refresh is unavailable or fails
				
				/* Example pseudo-code:
				const refreshed = await tryRefreshToken();
				if (refreshed)
				{
					// Update the failed request with new token and retry
					error.config.headers['Authorization'] = `Bearer ${newToken}`;
					return apiClient.request(error.config);
				}
				else
				{
					redirectToLogin();
				}//*/
				break;
			
			case 403:
				// Forbidden — user lacks permissions
				logger.warn('403 Forbidden:', error);
				emitEvent('alert', { type: 'danger', key: 'alert.forbidden' });
				// Maybe redirect or show permission error dialog
				break;
				
			case 404:
				// Not Found — resource missing
				logger.info('404 Not Found:', error);
				emitEvent('alert', { type: 'info', key: 'alert.notFound' });
				break;
				
			case 500:
				// Server error — inform user, retry options, etc
				logger.error('500 Server Error:', error);
				emitEvent('alert', { type: 'danger', key: 'alert.serverError' });
				break;
				
			default:
				// Other errors: network issues, etc.
				logger.error('Unhandled error:', error);
				emitEvent('alert', { type: 'danger', key: 'alert.unknownError' });
		}
	
		// handle 401, token refresh, global error logging here
		return Promise.reject(error);
	}
);

export default apiClient;

// src/services/signupService.ts
import apiClient from './apiClient';
import { ENDPOINTS } from '../constants/api';
import { fetchCsrfToken, CsrfData } from '../../services/csrfService';
import type { GenericResponse } from '../types/signupApi';

/**
* Stage/step Zero - Submit email to receive verification token
*
* This function constructs a POST request including the user’s email and necessary CSRF tokens for security.
* The backend processes this information—typically saving the email, starting user creation,
* and possibly sending a verification email with a token for the user.
* 
* The backend then responds with a structured JSON payload indicating success or failure,
* along with important data such as a newly assigned user ID and the current signup phase.
* 
* The frontend consumes this response, extracting `userId` and `signup_phase` to update the UI state
* and guide the user through the subsequent signup steps.
* 
* This single function encapsulates the entire request/response interaction for this signup stage,
* handling low-level API details and returning the backend's response data for further use in the application.
*
**
* The payload sent to the backend for signup stage zero:
* Contains user-entered data required to start the signup process (e.g., email).
*/
export interface SignupStageZeroEmailData
{
	email: string;
}

/**
* The data you expect to receive from the backend response after submitting stage zero:
* Includes server-generated identifiers like userId and possibly the current signup phase.
*/
export interface SignupStageZeroEmailResponseData
{
	userId: number;
	signup_phase?: number;
	// other fields if any
}

export async function submitSignupStageZeroEmail(
	data: SignupStageZeroEmailData,
	csrf: CsrfData
): Promise<GenericResponse<SignupStageZeroEmailResponseData>>
{
	const postData =
	{
		...data,
		[csrf.csrfParam]: csrf.csrfToken,
	};
	
	const response = await apiClient.post(ENDPOINTS.signup.stageZeroEmail, postData,
	{
		headers: { 'X-CSRF-Token': csrf.csrfToken },
	});
	
	// Return the 'data' part of the backend response
	return response.data;
}

/**
* Stage/step One - Verify token
*/
export interface SignupStageOneVerifyData
{
	userId: number;
	token: string;
}

export async function submitSignupStageOneVerify(
	data: SignupStageOneVerifyData,
	csrf: CsrfData
): Promise<GenericResponse>
{
	const postData =
	{
		...data,
		[csrf.csrfParam]: csrf.csrfToken,
	};
	
	const response = await apiClient.post(ENDPOINTS.signup.stageOneVerify, postData,
	{
		headers: { 'X-CSRF-Token': csrf.csrfToken },
	});
	
	return response.data;
}

/**
* Stage/step Two - Credentials(Password, bearer token, etc)
*/
export interface SignupStageTwoCredentialsData
{
	fullName: string;
	password: string;
	passwordRepeat: string;
}

export interface SignupStageTwoCredentialsResponseData
{
	token: string;
	userId?: number;
	signup_phase?: number;
}

export async function submitSignupStageTwoCredentials(
	userId: number,
	data: SignupStageTwoCredentialsData,
	csrf: CsrfData
): Promise<GenericResponse<SignupStageTwoCredentialsResponseData>>
{
	const postData =
	{
		...data,
		[csrf.csrfParam]: csrf.csrfToken,
	};
	
	const response = await apiClient.post(ENDPOINTS.signup.stageTwoCredentials, postData,
	{
		headers: { 'X-CSRF-Token': csrf.csrfToken },
	});
	
	return response.data;
}

/**
* Stage Three - Category
*/
export interface SignupStageThreeCategoryData
{
	category: string;
}

export interface SignupStageThreeCategoryResponseData
{
	// define any specific data expected from this step
	signup_phase?: number;
}

export async function submitSignupStageThreeCategory(
	userId: number,
	data: SignupStageThreeCategoryData,
	csrf: CsrfData
): Promise<GenericResponse<SignupStageThreeCategoryResponseData>>
{
	const postData =
	{
		...data,
		[csrf.csrfParam]: csrf.csrfToken,
	};
	
	const response = await apiClient.post(ENDPOINTS.signup.stageThreeCategory, postData,
	{
		headers: { 'X-CSRF-Token': csrf.csrfToken },
	});
	
	return response.data;
}

and the calls from the frontend to the backend restful api will be different, but setting a standard(protocal) would be awesome.