Saltar a contenido

Autenticación

Descripción General

La API Pontotel utiliza Autenticación Bearer Token (JWT) para autenticar solicitudes.

Flujo de Autenticación

  1. Enviar credenciales al endpoint /login/
  2. Recibir access_token en la respuesta
  3. Incluir token en el encabezado Authorization: Bearer {token}
  4. El token expira en 1 hora

Endpoint de Login

POST /api/v4/login/

Solicitud

JSON
1
2
3
4
{
  "username": "tu_usuario",
  "password": "tu_contraseña"
}

Respuesta (200 OK)

JSON
{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "user": {
    "id": 123,
    "username": "tu_usuario",
    "email": "tu@email.com"
  }
}

Ejemplos de Código

Python
import requests
from datetime import datetime, timedelta

class PontotelAuth:
    def __init__(self, username, password, base_url):
        self.username = username
        self.password = password
        self.base_url = base_url
        self.token = None
        self.token_expires_at = None

    def login(self):
        """Realiza login y obtiene token"""
        url = f"{self.base_url}/login/"
        payload = {
            "username": self.username,
            "password": self.password
        }

        response = requests.post(url, json=payload)
        response.raise_for_status()

        data = response.json()
        self.token = data["access_token"]
        self.token_expires_at = datetime.now() + timedelta(seconds=data["expires_in"])

        return self.token

    def get_token(self):
        """Retorna token válido, renovando si es necesario"""
        if not self.token or datetime.now() >= self.token_expires_at:
            self.login()
        return self.token

    def get_headers(self):
        """Retorna encabezados con autenticación"""
        return {
            "Authorization": f"Bearer {self.get_token()}",
            "Content-Type": "application/json"
        }

# Uso
auth = PontotelAuth(
    username="tu_usuario",
    password="tu_contraseña",
    base_url="https://apis.pontotel.com.br/pontotel/api/v4"
)

# Hacer solicitudes
headers = auth.get_headers()
response = requests.get(
    "https://apis.pontotel.com.br/pontotel/api/v4/usuarios/",
    headers=headers
)
JavaScript
class PontotelAuth {
  constructor(username, password, baseUrl) {
    this.username = username;
    this.password = password;
    this.baseUrl = baseUrl;
    this.token = null;
    this.tokenExpiresAt = null;
  }

  async login() {
    const url = `${this.baseUrl}/login/`;
    const response = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        username: this.username,
        password: this.password
      })
    });

    if (!response.ok) {
      throw new Error(`Login fallido: ${response.status}`);
    }

    const data = await response.json();
    this.token = data.access_token;
    this.tokenExpiresAt = Date.now() + (data.expires_in * 1000);

    return this.token;
  }

  async getToken() {
    if (!this.token || Date.now() >= this.tokenExpiresAt) {
      await this.login();
    }
    return this.token;
  }

  async getHeaders() {
    const token = await this.getToken();
    return {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json'
    };
  }
}

// Uso
const auth = new PontotelAuth(
  'tu_usuario',
  'tu_contraseña',
  'https://apis.pontotel.com.br/pontotel/api/v4'
);

// Hacer solicitudes
const headers = await auth.getHeaders();
const response = await fetch(
  'https://apis.pontotel.com.br/pontotel/api/v4/usuarios/',
  { headers }
);
Bash
# 1. Login
curl -X POST "https://apis.pontotel.com.br/pontotel/api/v4/login/" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "tu_usuario",
    "password": "tu_contraseña"
  }' \
  | jq -r '.access_token' > token.txt

# 2. Usar token
TOKEN=$(cat token.txt)

curl -X GET "https://apis.pontotel.com.br/pontotel/api/v4/usuarios/" \
  -H "Authorization: Bearer $TOKEN"

Seguridad

Prácticas Importantes

  • Nunca compartas credenciales o tokens
  • Almacena tokens en variables de entorno o gestores de secretos
  • Rota las credenciales regularmente
  • Usa HTTPS siempre (obligatorio)
  • No hagas commit de tokens en Git

Almacenamiento Seguro

Python
# .env
PONTOTEL_USERNAME=tu_usuario
PONTOTEL_PASSWORD=tu_contraseña

# código
from dotenv import load_dotenv
import os

load_dotenv()

auth = PontotelAuth(
    username=os.getenv("PONTOTEL_USERNAME"),
    password=os.getenv("PONTOTEL_PASSWORD"),
    base_url="https://apis.pontotel.com.br/pontotel/api/v4"
)
JavaScript
// .env
PONTOTEL_USERNAME=tu_usuario
PONTOTEL_PASSWORD=tu_contraseña

// código
require('dotenv').config();

const auth = new PontotelAuth(
  process.env.PONTOTEL_USERNAME,
  process.env.PONTOTEL_PASSWORD,
  'https://apis.pontotel.com.br/pontotel/api/v4'
);

Expiración y Renovación

  • Los tokens expiran en 1 hora (3600 segundos)
  • Implementa lógica de renovación automática
  • Maneja errores 401 Unauthorized re-autenticando

Ejemplo de Lógica de Reintento

Python
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

def requests_retry_session(retries=3):
    session = requests.Session()
    retry = Retry(
        total=retries,
        read=retries,
        connect=retries,
        backoff_factor=0.3,
        status_forcelist=(401, 500, 502, 504),
    )
    adapter = HTTPAdapter(max_retries=retry)
    session.mount('http://', adapter)
    session.mount('https://', adapter)
    return session

# Uso
session = requests_retry_session()
response = session.get(url, headers=headers)

Errores Comunes

Código Error Solución
400 Bad Request Verificar formato del payload
401 Unauthorized Credenciales inválidas o token expirado
403 Forbidden Sin permiso para el recurso
429 Too Many Requests Esperar límite de tasa

Próximos Pasos