Getting Started
Authentication
Pasona Finance Tracker API uses Sanctum bearer token authentication. You receive a token
when you register or log in, and you must include it in the Authorization
header of every request to a protected endpoint.
1. Get a token
Call POST /api/login with your email and password, or POST /api/register to create a new account. The response includes an access_token that you can use on every subsequent request.
curl -X POST /api/login \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"password": "supersecret123"
}'
The response includes a Sanctum personal-access token:
{
"access_token": "1|abc123def456...",
"token_type": "Bearer",
"user": { "id": 1, "name": "Jane Doe", "email": "[email protected]" }
}
2. Pass it in the Authorization header
For every authenticated request, add this header:
Authorization: Bearer YOUR_ACCESS_TOKEN
You may also need:
Authorization: Bearer YOUR_ACCESS_TOKEN
Accept: application/json
Content-Type: application/json
3. Full example: authenticated request
Below is a complete example of an authenticated POST request to
/api/transactions.
curl -X POST /api/transactions \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"account_id": 1,
"type": "expense",
"amount": 25.50,
"description": "Lunch with team",
"transaction_date": "2026-06-03"
}'const response = await fetch('/api/transactions', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + token,
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
account_id: 1,
type: 'expense',
amount: 25.50,
description: 'Lunch with team',
transaction_date: '2026-06-03',
}),
});
if (!response.ok) {
throw new Error(`Request failed: ${response.status}`);
}
const data = await response.json();
console.log(data);$ch = curl_init('/api/transactions');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer YOUR_ACCESS_TOKEN',
'Accept: application/json',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'account_id' => 1,
'type' => 'expense',
'amount' => 25.50,
'description' => 'Lunch with team',
'transaction_date' => '2026-06-03',
]),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status >= 400) {
throw new RuntimeException('Request failed: ' . $status);
}
print_r(json_decode($response, true));import requests
response = requests.post(
'/api/transactions',
headers={
'Authorization': f'Bearer {token}',
'Accept': 'application/json',
'Content-Type': 'application/json',
},
json={
'account_id': 1,
'type': 'expense',
'amount': 25.50,
'description': 'Lunch with team',
'transaction_date': '2026-06-03',
},
)
response.raise_for_status()
print(response.json())Rotating & revoking tokens
Call POST /api/logout to revoke the token used for the current request.
If a token is leaked, log in again to receive a fresh one and treat the leaked token as compromised.
Authentication errors
If your token is missing, malformed, or revoked, the API will respond with 401 Unauthorized:
{
"message": "Unauthenticated."
}
Email verification (opt-in)
The User model implements MustVerifyEmail. A verification
email is queued automatically on register
— the response includes email_verified: false until the user clicks the link.
Verification is not required to use the API. The only endpoints that
return a 403 for unverified users are the sensitive bulk writers:
POST /api/transactions/sync, POST /api/import/store, and
POST /api/import/kuda/store. Those return
{ "message": "Your email address is not verified.", "requires_verified_email": true }
so the frontend can prompt the user to verify.
The SPA can poll GET /api/email/verification-status to decide whether
to render a “please confirm your email” banner without fetching the full
profile, and call POST /api/email/verification-notification (throttled
6/min) to resend the link.
Google OAuth (GET /api/auth/google) auto-verifies the user on first
login, so users who sign in with Google never see the verification banner.
Full reference on the Authentication page.