Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/IvanchoDev89/maleku-system/llms.txt

Use this file to discover all available pages before exploring further.

The Maleku System API uses JWT (JSON Web Token) Bearer authentication. When you register or log in, the API returns an access_token and a refresh_token. Include the access token in the Authorization: Bearer header of every request that requires authentication. Access tokens are short-lived (60 minutes by default); use the refresh token to obtain a new access token before expiry without requiring the user to log in again. Tokens are signed with HS256 using a server-side secret and validated on every request. Revoked tokens (after logout or password change) are tracked in a Redis blacklist.

Token Types

TokenLifetimeAlgorithmPurpose
Access token60 minutes (configurable via ACCESS_TOKEN_EXPIRE_MINUTES)HS256Authenticate API requests via Authorization header
Refresh token7 days (configurable via REFRESH_TOKEN_EXPIRE_DAYS)HS256Obtain a new access token without re-authenticating
Token rotation is enforced on refresh: each call to POST /auth/refresh invalidates the old refresh token and issues a brand new pair. Store the latest refresh token after every refresh call.

POST /auth/register

Register a new user account. On success the API returns a token pair and a minimal user object so your client can authenticate immediately — no separate login step required.
New accounts are created with role: "client" and is_verified: false. A verification email is sent automatically. Verified email is required before creating bookings.

Request body

email
string
required
A valid email address. Must be unique across all accounts. Stored in lowercase.
password
string
required
The account password. Must be 8–100 characters and satisfy the complexity rules described in the Password Requirements section below.
full_name
string
required
The user’s full name (2–255 characters). Must not contain the @ symbol.
phone
string
Optional phone number (up to 20 characters), e.g. +50612345678.

Example request

curl -X POST https://api.costaricatravel.dev/api/v1/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "email": "john.doe@example.com",
    "password": "SecurePass123!",
    "full_name": "John Doe",
    "phone": "+50612345678"
  }'

Response 201 Created

access_token
string
Signed JWT access token. Valid for ACCESS_TOKEN_EXPIRE_MINUTES minutes (default 60).
refresh_token
string
Signed JWT refresh token. Valid for REFRESH_TOKEN_EXPIRE_DAYS days (default 7).
token_type
string
Always "bearer".
expires_in
integer
Access token lifetime in seconds (e.g. 3600 for 60 minutes).
user
object
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "expires_in": 3600,
  "user": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "john.doe@example.com",
    "full_name": "John Doe",
    "role": "client"
  }
}

POST /auth/login

Authenticate an existing user with email and password. Returns a fresh token pair.
After 5 consecutive failed login attempts the account is automatically locked for 30 minutes. The API returns 423 Locked during the lock period. See Account Locking below.

Request body

email
string
required
The registered email address.
password
string
required
The account password.

Example request

curl -X POST https://api.costaricatravel.dev/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "john.doe@example.com",
    "password": "SecurePass123!"
  }'

Response 200 OK

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "expires_in": 3600,
  "user": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "john.doe@example.com",
    "full_name": "John Doe",
    "role": "client",
    "is_verified": true
  }
}
Error responses:
StatusdetailCause
401"Invalid credentials"Email not found or password incorrect
403"Account is inactive"Account has been deactivated by an admin
423"Account temporarily locked due to failed attempts"Too many failed attempts

Using the Access Token

Pass the access token in the Authorization header on every authenticated request:
Authorization: Bearer <access_token>

Example — fetching your profile

curl https://api.costaricatravel.dev/api/v1/auth/me \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
If the token is missing, expired, or has been revoked the API returns 401 Unauthorized:
{
  "detail": "Could not validate credentials"
}

POST /auth/refresh

Exchange a valid refresh token for a new access token. Token rotation is applied: the old refresh token is immediately invalidated and a brand new refresh token is returned alongside the new access token.

Request body

refresh_token
string
required
The refresh token returned by register, login, or a previous refresh call.

Example request

curl -X POST https://api.costaricatravel.dev/api/v1/auth/refresh \
  -H "Content-Type: application/json" \
  -d '{
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
  }'

Response 200 OK

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "expires_in": 3600,
  "user": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "john.doe@example.com",
    "full_name": "John Doe",
    "role": "client",
    "is_verified": true
  }
}
Always replace both the access token and the refresh token stored client-side after a successful refresh. The old refresh token is blacklisted and will be rejected if reused.

POST /auth/logout

Invalidates the current access token by adding it to the Redis-backed token blacklist. The token cannot be used again even if it has not yet expired. Requires: Authorization: Bearer <access_token> header.

Example request

curl -X POST https://api.costaricatravel.dev/api/v1/auth/logout \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

Response 200 OK

{
  "message": "Logged out successfully"
}

Password Reset

Use the two-step flow below to let users reset a forgotten password.

Step 1 — POST /auth/forgot-password

Sends a password reset link to the provided email address. The reset token is valid for 1 hour. To prevent email enumeration, the API always returns a success response regardless of whether the email exists.
email
string
required
The email address associated with the account.
curl -X POST https://api.costaricatravel.dev/api/v1/auth/forgot-password \
  -H "Content-Type: application/json" \
  -d '{"email": "john.doe@example.com"}'
{
  "message": "If email exists, reset instructions sent"
}

Step 2 — POST /auth/reset-password

Completes the password reset. The token comes from the link emailed in step 1.
token
string
required
The password reset token extracted from the reset link.
new_password
string
required
The new password. Must meet the same complexity requirements as registration (8–100 chars, uppercase, lowercase, digit, special character).
curl -X POST https://api.costaricatravel.dev/api/v1/auth/reset-password \
  -H "Content-Type: application/json" \
  -d '{
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "new_password": "NewSecurePass123!"
  }'
{
  "message": "Password reset successfully"
}
After a successful reset, all failed login attempt counters and any account locks are cleared automatically.

Email Verification

After registration, a verification email containing a time-limited token is sent to the user’s address. Tokens are valid for 24 hours.

POST /auth/verify-email

token
string
required
The verification token from the email link.
curl -X POST https://api.costaricatravel.dev/api/v1/auth/verify-email \
  -H "Content-Type: application/json" \
  -d '{"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}'
{
  "message": "Email verified successfully"
}
A verified email (is_verified: true) is required to create bookings. Attempts to book while unverified return 403 Forbidden with the message "Email verification required. Please verify your email before proceeding.".

POST /auth/resend-verification

Resend the verification email. Rate-limited to 3 requests per hour. Requires a valid access token.
curl -X POST https://api.costaricatravel.dev/api/v1/auth/resend-verification \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
{
  "message": "Verification email sent"
}

GET /auth/me

Returns the authenticated user’s profile. Use this endpoint to confirm token validity or retrieve current role and verification status. Requires: Authorization: Bearer <access_token> header.
curl https://api.costaricatravel.dev/api/v1/auth/me \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

Response 200 OK

id
string
User UUID.
email
string
Verified email address.
full_name
string
User’s full name.
phone
string | null
Phone number, or null if not set.
role
string
Current role. One of: client, vendor, agent, customer_service, admin, super_admin.
is_active
boolean
true if the account is active.
is_verified
boolean
true if the email address has been verified.
last_login
string | null
ISO 8601 timestamp of the most recent successful login, or null.
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "email": "john.doe@example.com",
  "full_name": "John Doe",
  "phone": "+50612345678",
  "role": "client",
  "is_active": true,
  "is_verified": true,
  "last_login": "2024-06-01T14:22:00+00:00"
}

Password Requirements

All passwords — on registration and password reset — are validated by the following rules enforced server-side:
Passwords that do not satisfy all of the following rules will be rejected with 422 Unprocessable Entity:
  • Minimum 8 characters
  • At least one uppercase letter (A–Z)
  • At least one lowercase letter (a–z)
  • At least one digit (0–9)
  • At least one special character from !@#$%^&*(),.?":{}|<>

Account Locking

After 5 consecutive failed login attempts, the account is automatically locked for 30 minutes. During this period all login attempts return 423 Locked:
{
  "detail": "Account temporarily locked due to failed attempts"
}
The lock is lifted automatically after 30 minutes or immediately upon a successful password reset. A security event is recorded in the audit log each time an account is locked or unlocked.

Build docs developers (and LLMs) love