Skip to main content

Overview

Tresa Contafy uses JWT (JSON Web Tokens) for authentication. The API provides two types of tokens:
  • Access Token: Short-lived token (15 minutes) used to authorize API requests
  • Refresh Token: Long-lived token (7 days) used to obtain new access tokens

Authentication Flow

1

Register or Login

Obtain your initial tokens by registering a new account or logging in with existing credentials.
2

Include Access Token in Requests

Add the access token to the Authorization header of all API requests.
3

Refresh When Expired

When the access token expires (after 15 minutes), use the refresh token to get a new one.

Registration

Create a new account to get started.

Endpoint

POST /api/auth/register

Request Body

{
  "email": "[email protected]",
  "password": "securePassword123",
  "nombre": "Juan",
  "apellido": "Pérez",
  "telefono": "+52 55 1234 5678"
}
email
string
required
Valid email address (validated)
password
string
required
Password with minimum 8 characters
nombre
string
User’s first name
apellido
string
User’s last name
telefono
string
Contact phone number

Response

{
  "message": "Usuario registrado correctamente. Por favor verifica tu email.",
  "user": {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "email": "[email protected]",
    "nombre": "Juan",
    "apellido": "Pérez",
    "telefono": "+52 55 1234 5678",
    "email_verified": false
  }
}
After registration, a verification email is sent. You can still use the API without verifying your email, but some features may be restricted.

Login

Authenticate with your credentials to receive JWT tokens.

Endpoint

POST /api/auth/login

Request Body

{
  "email": "[email protected]",
  "password": "securePassword123"
}

Response

{
  "message": "Login exitoso",
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMjNlNDU2Ny1lODliLTEyZDMtYTQ1Ni00MjY2MTQxNzQwMDAiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJpYXQiOjE3MTA0MjA4MDAsImV4cCI6MTcxMDQyMTcwMH0.signature",
  "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMjNlNDU2Ny1lODliLTEyZDMtYTQ1Ni00MjY2MTQxNzQwMDAiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJpYXQiOjE3MTA0MjA4MDAsImV4cCI6MTcxMTAyNTYwMH0.signature",
  "user": {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "email": "[email protected]",
    "nombre": "Juan",
    "apellido": "Pérez",
    "telefono": "+52 55 1234 5678",
    "email_verified": true
  }
}

Error Responses

{
  "error": "Credenciales inválidas",
  "message": "El email o la contraseña son incorrectos"
}

Google Authentication

Authenticate using Google Sign-In with Firebase.

Endpoint

POST /api/auth/google

Request Body

{
  "idToken": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ..."
}
idToken
string
required
Firebase ID token obtained from Google Sign-In client

Response

Returns the same format as standard login:
{
  "message": "Login exitoso",
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user": {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "email": "[email protected]",
    "nombre": "Juan",
    "apellido": null,
    "telefono": null,
    "email_verified": true
  }
}
If this is the first time signing in with Google, a new account is automatically created with a FREE subscription plan.

Using Access Tokens

Include the access token in the Authorization header using the Bearer scheme.

Header Format

Authorization: Bearer YOUR_ACCESS_TOKEN

Example Request

curl -X GET https://api.contafy.com/api/auth/me \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

Response

{
  "user": {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "email": "[email protected]",
    "nombre": "Juan",
    "apellido": "Pérez",
    "telefono": "+52 55 1234 5678",
    "email_verified": true,
    "logo_url": null,
    "nombre_comercial": null
  }
}

Token Expiration and Refresh

Access tokens expire after 15 minutes. When you receive a 403 error with message “Token inválido o expirado”, use your refresh token to obtain a new access token.

Endpoint

POST /api/auth/refresh

Request Body

{
  "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Response

{
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Error Responses

{
  "error": "Refresh token expirado",
  "message": "Tu sesión ha expirado. Por favor inicia sesión nuevamente."
}
Refresh tokens expire after 7 days. After expiration, users must log in again to obtain new tokens.

Token Payload

Both access and refresh tokens contain the following payload:
{
  "userId": "123e4567-e89b-12d3-a456-426614174000",
  "email": "[email protected]",
  "iat": 1710420800,
  "exp": 1710421700
}
  • userId: Unique user identifier
  • email: User’s email address
  • iat: Issued at timestamp
  • exp: Expiration timestamp

Logout

Invalidate the current session.

Endpoint

POST /api/auth/logout

Request Headers

Authorization: Bearer YOUR_ACCESS_TOKEN

Response

{
  "message": "Logout exitoso"
}
Currently, logout is client-side. After logout, discard both access and refresh tokens. Server-side token invalidation is planned for future releases.

Email Verification

Verify Email

POST /api/auth/verify-email
Request:
{
  "token": "verification-token-from-email"
}
Response:
{
  "message": "Email verificado correctamente"
}

Resend Verification Email

POST /api/auth/resend-verification-email
Request:
{
  "email": "[email protected]"
}
Response:
{
  "message": "Email de verificación reenviado correctamente. Por favor revisa tu bandeja de entrada."
}
Verification tokens expire after 24 hours. If your token expires, request a new verification email.

Password Reset

Request Password Reset

POST /api/auth/forgot-password
Request:
{
  "email": "[email protected]"
}
Response:
{
  "message": "Si el email está registrado, se enviará un correo con las instrucciones para restablecer tu contraseña."
}

Reset Password

POST /api/auth/reset-password
Request:
{
  "token": "reset-token-from-email",
  "password": "newSecurePassword123"
}
Response:
{
  "message": "Contraseña restablecida correctamente. Ya puedes iniciar sesión con tu nueva contraseña."
}
Password reset tokens expire after 1 hour. The new password must be at least 8 characters long.

Security Best Practices

Store Tokens Securely

Never expose tokens in URLs or logs. Store them securely using environment variables or secure storage.

Use HTTPS Only

Always use HTTPS in production to prevent token interception.

Implement Token Refresh

Automatically refresh access tokens before they expire to maintain seamless user experience.

Handle Expiration Gracefully

Implement proper error handling for expired tokens and redirect users to login when refresh fails.

Rate Limiting

Authentication endpoints are protected by rate limiting:
  • Registration/Login: 10 requests per 15 minutes per IP
  • Refresh Token: 20 requests per 15 minutes per user
Exceeding these limits results in a 429 Too Many Requests response.

Error Codes

Status CodeErrorDescription
400Bad RequestMissing or invalid parameters
401UnauthorizedInvalid credentials or missing token
403ForbiddenToken expired or invalid
409ConflictEmail already registered
429Too Many RequestsRate limit exceeded
500Internal Server ErrorServer error during authentication

Example: Complete Authentication Flow

// 1. Login
const loginResponse = await fetch('https://api.contafy.com/api/auth/login', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    email: '[email protected]',
    password: 'securePassword123'
  })
});

const { accessToken, refreshToken } = await loginResponse.json();

// 2. Make authenticated request
const invoicesResponse = await fetch('https://api.contafy.com/api/invoices', {
  headers: {
    'Authorization': `Bearer ${accessToken}`
  }
});

// 3. Handle token expiration
if (invoicesResponse.status === 403) {
  // Refresh access token
  const refreshResponse = await fetch('https://api.contafy.com/api/auth/refresh', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ refreshToken })
  });
  
  const { accessToken: newAccessToken } = await refreshResponse.json();
  
  // Retry original request with new token
  const retryResponse = await fetch('https://api.contafy.com/api/invoices', {
    headers: {
      'Authorization': `Bearer ${newAccessToken}`
    }
  });
}

Next Steps

Quickstart Guide

Complete end-to-end tutorial for your first API integration

User Profile

Manage user profile and account settings

Profiles API

Create and manage fiscal profiles for invoice processing

Error Handling

Learn how to handle API errors effectively

Build docs developers (and LLMs) love