POST /api/register

Register a new account

Creates a new user and immediately returns a Sanctum access token.

Request body

NameTypeRequiredDescription
name string Required Full name. Max 255 characters.
email string Required Must be a valid, unique email address.
password string Required Minimum 8 characters.
password_confirmation string Required Must match password.

Request body example

REQUEST
{
  "name": "Jane Doe",
  "email": "[email protected]",
  "password": "supersecret123",
  "password_confirmation": "supersecret123"
}

Responses

200 OK
{
  "access_token": "1|abc123def456...",
  "token_type": "Bearer",
  "user": {
    "id": 1,
    "name": "Jane Doe",
    "email": "[email protected]"
  },
  "email_verified": false,
  "email_verified_at": null
}
422 Unprocessable Entity
{
  "message": "The given data was invalid.",
  "errors": {
    "email": ["The email has already been taken."],
    "password": ["The password must be at least 8 characters."]
  }
}
POST /api/login

Log in

Authenticates a user with email and password and returns a Sanctum access token.

Request body

NameTypeRequiredDescription
email string Required The user's email address.
password string Required The user's password.

Responses

200 OK
{
  "access_token": "1|abc123def456...",
  "token_type": "Bearer",
  "user": {
    "id": 1,
    "name": "Jane Doe",
    "email": "[email protected]"
  },
  "email_verified": false,
  "email_verified_at": null
}
422 Unprocessable Entity
{
  "message": "The provided credentials are incorrect.",
  "errors": {
    "email": ["The provided credentials are incorrect."]
  }
}
GET /api/me

Get current user

Returns the authenticated user's profile. Requires a valid bearer token.

Responses

200 OK
{
  "id": 1,
  "name": "Jane Doe",
  "email": "[email protected]",
  "google_id": null,
  "avatar": null,
  "email_verified_at": "2026-06-04T09:12:33Z",
  "reminder_time": "21:10",
  "reminder_last_sent_at": "2026-06-05T21:10:11Z"
}
401 Unauthorized
{ "message": "Unauthenticated." }
POST /api/logout

Log out

Revokes the bearer token used for the current request. Requires authentication.

Responses

200 OK
{ "message": "Successfully logged out" }
POST /api/forgot-password

Request a password reset link

Sends a password-reset email to the given address if the user exists.

Request body

NameTypeRequiredDescription
email string Required The user's email address.

Responses

200 OK
{ "message": "We have e-mailed your password reset link!" }
422 Unprocessable Entity
{
  "errors": {
    "email": ["We can't find a user with that e-mail address."]
  }
}
POST /api/reset-password

Reset password

Finalises a password reset using the token emailed by the forgot-password endpoint.

Request body

NameTypeRequiredDescription
token string Required Reset token from the password reset email.
email string Required Email of the account being reset.
password string Required The new password (min 8 chars).
password_confirmation string Required Must match password.

Responses

200 OK
{ "message": "Your password has been reset!" }
422 Unprocessable Entity
{
  "message": "The given data was invalid.",
  "errors": {
    "email": ["This password reset token is invalid."]
  }
}
GET /api/auth/google

Redirect to Google

Returns a JSON payload containing the Google OAuth redirect URL. The frontend should send the user to that URL to begin the sign-in flow.

Response

200 OK
{
  "url": "https://accounts.google.com/o/oauth2/auth?client_id=...&redirect_uri=...&response_type=code&scope=openid%20profile%20email"
}
GET /api/auth/google/callback

Google OAuth callback

Handled automatically by Google. On success the user is redirected to FRONTEND_URL/login?token=...&user=.... On failure they are redirected with an error query string.

Response

HTTP 302 redirect. Body is empty.

Email verification opt-in

The User model implements MustVerifyEmail and a verification email is queued automatically on register. Verification is not required to use the API — unverified users can list accounts, log transactions, and read summaries. The only endpoints that require a verified email are the sensitive bulk writers:

  • POST /api/transactions/sync — offline batch upload
  • POST /api/import/store — generic CSV import
  • POST /api/import/kuda/store — Kuda bank-statement import

Those routes return a 403 with { "requires_verified_email": true } — see the Errors page for the shape.

Google OAuth auto-flips email_verified_at on first login, so users who sign in with Google never see the verification banner.

GET /api/email/verify/{id}/{hash}

Verify email address

The click-target of the verification email. The URL is signed and must be presented exactly as it appears in the message — it is the proof that the user controls the inbox. On success the server marks the address verified, fires the Verified event, and 302-redirects to FRONTEND_URL/dashboard?verified=1 (or ?verified=already if the address was already verified).

The frontend should send users to this URL with no extra wrapping — the SPA doesn't need to call it with Authorization headers. Just navigate the browser.

Responses

302 Found
HTTP/1.1 302 Found
Location: https://app.yourdomain.com/dashboard?verified=1
403 Forbidden
HTTP/1.1 403 Forbidden

Invalid or expired verification link.
404 Not Found
HTTP/1.1 404 Not Found
POST /api/email/verification-notification

Resend verification email

Queues a fresh verification email for the authenticated user. Throttled to 6 requests per minute per token. The notification is sent from the VerifyEmailNotification class and uses the VerifyEmail mail template.

Responses

200 OK
{
  "message": "Verification email queued.",
  "email_verified": false,
  "verification_sent_at": "2026-06-06T21:10:11+00:00"
}

If the user is already verified, the response short-circuits to { "message": "Email already verified.", "email_verified": true }.

429 Too Many Requests
{ "message": "Too Many Attempts." }
GET /api/email/verification-status

Get verification status

Lightweight endpoint for the SPA to decide whether to render the verification banner. Cheaper than /me if you don't need the full profile.

Response

200 OK
{
  "email_verified": true,
  "email": "[email protected]"
}
GET /api/auth/check-email?email={email}

Check email availability

Public, rate-limited probe used by the register / login screens to show a “Sign in instead” / “Register instead” hint. Always responds with a 200 and the same shape — the response never reveals whether the email is registered, which is the standard mitigation against user-enumeration attacks.

Response

200 OK
{ "available": true }

© 2026 Pasona Finance Tracker API. All rights reserved.

API version: v1