Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/CRISTIANCAMACH34/Zippi/llms.txt

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

Zippi’s authentication layer is built on JWT (JSON Web Tokens). Every login — whether for a platform admin or a customer — issues a short-lived access token and a longer-lived refresh token. The access token is used in the Authorization: Bearer <access_token> header on every protected request. When the access token expires, exchange the refresh token for a new one without re-entering credentials. Refresh sessions also enforce an idle timeout: if no refresh call is made within the configured idle window (default 15 minutes), the session is invalidated and the user must log in again.

Token lifetimes

These values are controlled by environment variables and default to the values shown below.
SettingEnvironment variableDefault
Access token TTLJWT_ACCESS_TOKEN_EXPIRES_MINUTES4 minutes
Refresh token TTLJWT_REFRESH_TOKEN_EXPIRES_DAYS30 days
Admin idle timeoutADMIN_SESSION_IDLE_TIMEOUT_MINUTES15 minutes
The JWT_ACCESS_TOKEN_EXPIRES_MINUTES default of 4 minutes is intentionally short. Clients must call POST /api/v1/auth/refresh before the access token expires to maintain a continuous session. The refresh endpoint checks activity within ADMIN_SESSION_IDLE_TIMEOUT_MINUTES (default 15 minutes) — if the session has been idle beyond that window, the server rejects the refresh even though the refresh token itself has not yet expired.

Authorization header

Authorization: Bearer <access_token>
All endpoints marked requires auth or requires permission must include this header.

Admin / platform endpoints

POST /api/v1/auth/login

Authenticates a platform administrator (database admin or environment-seed admin) and issues an access/refresh token pair.
curl -X POST https://api.zippi.app/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "admin@zippi.app",
    "password": "s3cur3P@ss"
  }'
Request body
email
string
required
The admin’s email address. Case-insensitive; trimmed and lowercased before lookup.
password
string
required
The admin’s password. Must be non-empty.
Response 200 OK
{
  "success": true,
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "token_type": "Bearer",
    "expires_at": "2024-11-15T12:04:00+00:00",
    "access_expires_at": "2024-11-15T12:04:00+00:00",
    "refresh_expires_at": "2024-12-15T12:00:00+00:00",
    "idle_timeout_minutes": 15,
    "access_ttl_minutes": 4,
    "user": {
      "id": 1,
      "name": "Ana García",
      "email": "admin@zippi.app",
      "role": "city_admin",
      "role_label": "Administrador ciudad",
      "surface": "admin_panel",
      "home_route": "/app/admin/city",
      "permissions": ["dashboard.read", "orders.read", "orders.manage"],
      "modules": ["dashboard", "orders", "clients"],
      "scope_type": "city",
      "scope_id": 3,
      "scope_label": "Bogotá",
      "token_version": 1,
      "source": "database"
    }
  }
}
access_token
string
Short-lived JWT to pass in the Authorization: Bearer header.
refresh_token
string
Long-lived JWT used to obtain a new access token via the refresh endpoint.
token_type
string
Always "Bearer".
access_expires_at
string
ISO 8601 UTC timestamp when the access token expires.
refresh_expires_at
string
ISO 8601 UTC timestamp when the refresh token expires.
idle_timeout_minutes
integer
Maximum inactivity window in minutes before the session is invalidated.
access_ttl_minutes
integer
Configured lifetime of the access token in minutes.
user
object
The authenticated admin’s access profile. See Access profile object below.

POST /api/v1/auth/refresh

Exchanges a valid, non-idle refresh token for a new access token. The session last_seen timestamp is updated on each successful call, keeping the session alive as long as calls occur within ADMIN_SESSION_IDLE_TIMEOUT_MINUTES.
curl -X POST https://api.zippi.app/api/v1/auth/refresh \
  -H "Content-Type: application/json" \
  -d '{
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
  }'
Request body
refresh_token
string
required
The refresh token issued at login or from a previous refresh call.
Response 200 OK
{
  "success": true,
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "token_type": "Bearer",
    "expires_at": "2024-11-15T12:08:00+00:00",
    "access_expires_at": "2024-11-15T12:08:00+00:00",
    "refresh_expires_at": "2024-12-15T12:00:00+00:00",
    "idle_timeout_minutes": 15,
    "access_ttl_minutes": 4,
    "user": { "...": "same shape as login response" }
  }
}
access_token
string
New short-lived access token.
refresh_token
string
Rotated refresh token. The previous refresh token is invalidated. Sending the old token again after rotation results in a 401 and destroys the session (theft-detection).

POST /api/v1/auth/logout

Invalidates the server-side refresh session associated with the provided refresh token. No Authorization header is required — the refresh token in the request body is sufficient to identify the session. The access token remains cryptographically valid until it expires naturally, but the session will no longer issue new tokens.
curl -X POST https://api.zippi.app/api/v1/auth/logout \
  -H "Content-Type: application/json" \
  -d '{
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
  }'
Request body
refresh_token
string
The refresh token to invalidate. If omitted or invalid, the call still succeeds (logout is always safe).
Response 200 OK
{
  "success": true,
  "data": {
    "closed": true,
    "closed_at": "2024-11-15T12:01:00+00:00"
  }
}
closed
boolean
Always true on a successful logout.
closed_at
string
ISO 8601 UTC timestamp of when the session was closed.

GET /api/v1/auth/me

Requires authentication. Returns the current user’s full access profile, freshly resolved from the database. Useful for verifying token validity and refreshing the client-side permission set.
curl https://api.zippi.app/api/v1/auth/me \
  -H "Authorization: Bearer <access_token>"
Response 200 OK
{
  "success": true,
  "data": {
    "user": {
      "id": 1,
      "name": "Ana García",
      "email": "admin@zippi.app",
      "role": "city_admin",
      "role_label": "Administrador ciudad",
      "role_description": "Gestiona la operacion, negocios, domiciliarios, soporte y finanzas de una ciudad.",
      "surface": "admin_panel",
      "home_route": "/app/admin/city",
      "permissions": ["dashboard.read", "orders.read", "orders.manage"],
      "modules": ["dashboard", "orders", "clients"],
      "scope_type": "city",
      "scope_id": 3,
      "scope_label": "Bogotá",
      "business_id": null,
      "branch_id": null,
      "token_version": 1,
      "source": "database"
    }
  }
}
user
object
Full access profile. See Access profile object below.

POST /api/v1/auth/actions/log

Requires authentication. Records a client-side UI action for audit and analytics purposes. This endpoint is fire-and-forget; the response does not block the UI action.
curl -X POST https://api.zippi.app/api/v1/auth/actions/log \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "click",
    "label": "Export orders CSV",
    "path": "/reports/orders"
  }'
Request body
action
string
A short string identifying the action type (e.g., "click", "view", "submit"). Defaults to "click" if omitted.
label
string
Human-readable label for the action. Truncated to 120 characters.
path
string
The current frontend route or URL path. Truncated to 240 characters. Falls back to the Referer header if omitted.
Response 200 OK
{
  "success": true,
  "data": { "logged": true }
}

GET /api/v1/auth/audit-events

Requires audit.read permission. Returns a paginated list of administrative audit events, with filtering by event type, actor, target, and date range.
curl "https://api.zippi.app/api/v1/auth/audit-events?page=1&page_size=25&event_type=login_success" \
  -H "Authorization: Bearer <access_token>"
Query parameters
page
integer
default:"1"
Page number (1-based).
page_size
integer
default:"25"
Items per page. Maximum 100.
Full-text filter across description, event type, actor name/email, and target name/email.
event_type
string
Filter by exact event type (e.g., login_success, admin_created, admin_deactivated, sessions_revoked, audit_exported).
actor_id
integer
Filter events where this admin ID is the actor.
target_id
integer
Filter events where this admin ID is the target/subject.
start_date
string
ISO date string (YYYY-MM-DD) for the beginning of the date range.
end_date
string
ISO date string (YYYY-MM-DD) for the end of the date range.
Response 200 OK
{
  "success": true,
  "data": {
    "items": [
      {
        "id_evento": 42,
        "tipo_evento": "login_success",
        "descripcion": "Inicio de sesion exitoso de Ana García",
        "actor": {
          "id_admin": 1,
          "tipo": "database",
          "nombre": "Ana García",
          "email": "admin@zippi.app"
        },
        "objetivo": {
          "id_admin": 1,
          "nombre": "Ana García",
          "email": "admin@zippi.app"
        },
        "payload": { "source": "database" },
        "fecha_evento": "2024-11-15T12:00:00"
      }
    ],
    "pagination": {
      "page": 1,
      "page_size": 25,
      "total": 120
    },
    "filters": {
      "search": "",
      "event_type": "login_success",
      "actor_id": null,
      "target_id": null,
      "start_date": null,
      "end_date": null
    },
    "summary": {
      "total_events": 120,
      "logins": 80,
      "exports": 5,
      "revocations": 2,
      "changes": 12,
      "last_event_at": "2024-11-15T12:00:00",
      "event_types": [
        { "event_type": "login_success", "count": 80 }
      ]
    }
  }
}

GET /api/v1/auth/audit-events/export

Requires audit.export permission. Streams the filtered audit event log as a UTF-8 CSV file. Accepts the same filter query parameters as the list endpoint. An audit_exported event is recorded for the requesting admin upon every successful export.
curl "https://api.zippi.app/api/v1/auth/audit-events/export?start_date=2024-11-01&end_date=2024-11-15" \
  -H "Authorization: Bearer <access_token>" \
  -o audit.csv
Query parameters Identical to GET /api/v1/auth/audit-eventssearch, event_type, actor_id, target_id, start_date, end_date. Responsetext/csv; charset=utf-8 The file is returned as an attachment. The filename follows the pattern rapi-turbo-auditoria-{scope_label}-{date}.csv. Columns: fecha, evento, descripcion, actor, actor_email, objetivo, objetivo_email, detalle.

GET /api/v1/auth/access-catalog

Requires admins.read permission. Returns all role definitions and scope types registered on the platform. Use this endpoint to populate role/scope dropdowns when creating or editing admin users.
curl https://api.zippi.app/api/v1/auth/access-catalog \
  -H "Authorization: Bearer <access_token>"
Response 200 OK
{
  "success": true,
  "data": {
    "roles": [
      {
        "key": "city_admin",
        "label": "Administrador ciudad",
        "description": "Gestiona la operacion, negocios, domiciliarios, soporte y finanzas de una ciudad.",
        "surface": "admin_panel",
        "console_access": true,
        "default_scope_type": "city",
        "home_route": "/app/admin/city",
        "modules": ["dashboard", "orders"],
        "permissions": ["dashboard.read", "orders.read"]
      }
    ],
    "scope_types": [
      { "key": "global", "label": "Global" },
      { "key": "country", "label": "Pais" },
      { "key": "city", "label": "Ciudad" },
      { "key": "zippi_branch", "label": "Sucursal Zippi" },
      { "key": "business_group", "label": "Grupo empresarial" },
      { "key": "business", "label": "Negocio / marca" },
      { "key": "business_branch", "label": "Sucursal de negocio" },
      { "key": "self", "label": "Propio" }
    ]
  }
}
roles
array
Full definitions for all console roles. Each entry includes key, label, description, surface, console_access, default_scope_type, home_route, modules, and permissions.
scope_types
array
All valid scope type identifiers with their human-readable labels.

Customer endpoints

POST /api/v1/auth/customer/login

Authenticates an end customer by phone number and password. Returns an access token valid for the standard access TTL and a refresh token, plus the customer’s profile.
Customer login accepts phone (not email) as the primary identifier. The phone number is normalized by stripping all non-digit characters before lookup, so +57 310 123 4567, 573101234567, and 3101234567 all resolve to the same account.
curl -X POST https://api.zippi.app/api/v1/auth/customer/login \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "3101234567",
    "password": "myP@ssw0rd"
  }'
Request body
phone
string
required
The customer’s phone number. Non-digit characters are stripped automatically.
password
string
required
The customer’s account password.
Response 200 OK
{
  "success": true,
  "data": {
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "expires_at": "2024-11-15T12:04:00+00:00",
    "user": {
      "id": "101",
      "name": "Carlos Pérez",
      "phone": "3101234567",
      "email": null,
      "role": "customer",
      "role_label": "Cliente",
      "scope_type": "self",
      "scope_id": 101,
      "scope_label": "Carlos Pérez",
      "home_route": "/app/cliente",
      "permissions": ["orders.read", "clients.read"],
      "modules": ["client_app"],
      "token_version": 1,
      "source": "customer"
    }
  }
}
token
string
Alias for access_token. Provided for backwards compatibility with older clients.
access_token
string
Short-lived JWT for authenticating customer requests.
refresh_token
string
Long-lived JWT to obtain a new access token.
expires_at
string
ISO 8601 UTC expiry of the access token.
user
object
Customer profile with role "customer", scope "self", and limited permissions (orders.read, clients.read).

POST /api/v1/auth/customer/register

Creates a new customer account and immediately returns a session. The phone number must be unique across all customers.
curl -X POST https://api.zippi.app/api/v1/auth/customer/register \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Carlos Pérez",
    "phone": "3101234567",
    "email": "carlos@example.com",
    "password": "myP@ssw0rd"
  }'
Request body
name
string
required
Customer’s display name.
phone
string
required
Customer’s phone number. Normalized to digits only. Must be unique.
email
string
Optional email address. Stored as-is; not used for authentication.
password
string
required
Password for the new account. Minimum 6 characters.
Response 201 Created
{
  "success": true,
  "data": {
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "expires_at": "2024-11-15T12:04:00+00:00",
    "user": {
      "id": "102",
      "name": "Carlos Pérez",
      "phone": "3101234567",
      "email": "carlos@example.com",
      "role": "customer",
      "role_label": "Cliente",
      "scope_type": "self",
      "scope_id": 102,
      "home_route": "/app/cliente",
      "permissions": ["orders.read", "clients.read"],
      "modules": ["client_app"],
      "token_version": 1,
      "source": "customer"
    }
  }
}
Returns 409 Conflict if a customer with the same phone number already exists.

Access profile object

The user object returned by login, refresh, and /me contains a fully-resolved access profile built by build_access_profile(). The fields are consistent across all admin roles.
id
string | integer
Admin database ID, or "env-admin" for the environment-seed administrator.
name
string
Admin’s display name.
email
string
Admin’s email address.
role
string
Normalized role key (e.g., city_admin, super_admin). See the role keys in Admin Users.
role_label
string
Human-readable role name (e.g., "Administrador ciudad").
role_description
string
One-sentence description of what the role can do.
surface
string
UI surface identifier (e.g., superadmin_panel, admin_panel, business_portal).
home_route
string
The default redirect route after login (e.g., "/app/admin/city").
permissions
array
Expanded list of permission strings granted to this role. Umbrella permissions like catalog.manage are automatically expanded to their individual action permissions.
modules
array
List of module keys accessible to this role (e.g., "dashboard", "orders", "audit").
scope_type
string
The operational scope level: global, country, city, zippi_branch, business_group, business, business_branch, or self.
scope_id
integer | null
The database ID of the scoped entity. null for global scope.
scope_label
string | null
Human-readable label for the scope (e.g., "Bogotá", "Operacion global").
token_version
integer
Monotonically increasing integer. Incremented when a password changes or sessions are manually revoked. Tokens carrying an outdated version are rejected.
source
string
Token origin: "database" for DB admins, "environment" for the seed admin, "customer" for customer tokens.

Build docs developers (and LLMs) love