Generar token de acceso JWT
POST /api/auth/token
POST https://api.fypay.me/api/auth/tokenAutentíquese con el certificado de cliente X.509 + credenciales (clientId/clientSecret) y reciba un token JWT. La validez del token viene en el campo expires_in (en segundos): use ese valor para renovar el token antes de que expire, sin asumir un tiempo fijo.
Autenticación (mTLS)
Esta ruta exige mTLS: el certificado de cliente emitido por FyPay se presenta en el handshake TLS, no en un header HTTP. Use el mecanismo nativo de certificado de cliente de su biblioteca HTTP (por ejemplo, curl --cert client.crt --key client.key).
- El certificado es PEM, RSA 2048, válido por 2 años y vinculado a su cuenta.
- El mTLS se exige solo en esta ruta. Las demás rutas usan
Authorization: Bearer <token>, sin certificado.
No envíe el certificado en headers HTTP: ese modelo no se acepta. Sin el certificado en el handshake, la API responde 400 con PUB_CERT_HEADER_MISSING.
Cuerpo de la solicitud
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
clientId | string (UUID v4) | Sí | Client ID generado en el panel (https://banking.fypay.me), en Configuración → Credenciales |
clientSecret | string | Sí | Client secret generado junto con el clientId. Se muestra una única vez en el panel. No puede estar vacío |
{
"clientId": "6967c0a0-3566-48d0-8c13-717038b52279",
"clientSecret": "SU_CLIENT_SECRET"
}Ejemplo con cURL
curl -X POST https://api.fypay.me/api/auth/token \
--cert ./client.crt \
--key ./client.key \
-H "Content-Type: application/json" \
-d '{
"clientId": "SU_CLIENT_ID",
"clientSecret": "SU_CLIENT_SECRET"
}'Ejemplos de Código
const https = require('https');
const fs = require('fs');
const axios = require('axios');
const httpsAgent = new https.Agent({
cert: fs.readFileSync('./client.crt'),
key: fs.readFileSync('./client.key'),
});
const response = await axios.post(
'https://api.fypay.me/api/auth/token',
{
clientId: process.env.FYPAY_CLIENT_ID,
clientSecret: process.env.FYPAY_CLIENT_SECRET,
},
{ httpsAgent },
);
console.log('Token:', response.data.access_token);
console.log('Expira en:', response.data.expires_in, 'segundos');import os
import requests
response = requests.post(
'https://api.fypay.me/api/auth/token',
json={
'clientId': os.environ['FYPAY_CLIENT_ID'],
'clientSecret': os.environ['FYPAY_CLIENT_SECRET'],
},
cert=('client.crt', 'client.key'),
)
response.raise_for_status()
data = response.json()
print(f"Token: {data['access_token']}")
print(f"Expira en: {data['expires_in']} segundos")<?php
$ch = curl_init('https://api.fypay.me/api/auth/token');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSLCERT => __DIR__ . '/client.crt',
CURLOPT_SSLKEY => __DIR__ . '/client.key',
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'clientId' => getenv('FYPAY_CLIENT_ID'),
'clientSecret' => getenv('FYPAY_CLIENT_SECRET'),
]),
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
echo "Token: " . $data['access_token'] . "\n";
echo "Expira en: " . $data['expires_in'] . " segundos\n";using System.Net.Http.Json;
using System.Security.Cryptography.X509Certificates;
var certificate = X509Certificate2.CreateFromPemFile("client.crt", "client.key");
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(certificate);
using var client = new HttpClient(handler);
var response = await client.PostAsJsonAsync(
"https://api.fypay.me/api/auth/token",
new
{
clientId = Environment.GetEnvironmentVariable("FYPAY_CLIENT_ID"),
clientSecret = Environment.GetEnvironmentVariable("FYPAY_CLIENT_SECRET"),
});
response.EnsureSuccessStatusCode();
Console.WriteLine(await response.Content.ReadAsStringAsync());package main
import (
"bytes"
"crypto/tls"
"encoding/json"
"fmt"
"net/http"
"os"
)
func main() {
cert, err := tls.LoadX509KeyPair("client.crt", "client.key")
if err != nil {
panic(err)
}
client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{Certificates: []tls.Certificate{cert}},
},
}
body, _ := json.Marshal(map[string]string{
"clientId": os.Getenv("FYPAY_CLIENT_ID"),
"clientSecret": os.Getenv("FYPAY_CLIENT_SECRET"),
})
resp, err := client.Post("https://api.fypay.me/api/auth/token", "application/json", bytes.NewReader(body))
if err != nil {
panic(err)
}
defer resp.Body.Close()
var data map[string]any
json.NewDecoder(resp.Body).Decode(&data)
fmt.Println("Token:", data["access_token"])
fmt.Println("Expira en:", data["expires_in"], "segundos")
}import java.io.FileInputStream;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.security.KeyStore;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
char[] password = System.getenv("FYPAY_KEYSTORE_PASSWORD").toCharArray();
KeyStore keyStore = KeyStore.getInstance("PKCS12");
try (FileInputStream in = new FileInputStream("client.p12")) {
keyStore.load(in, password);
}
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, password);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), null, null);
String body = String.format(
"{\"clientId\":\"%s\",\"clientSecret\":\"%s\"}",
System.getenv("FYPAY_CLIENT_ID"),
System.getenv("FYPAY_CLIENT_SECRET")
);
HttpClient client = HttpClient.newBuilder().sslContext(sslContext).build();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.fypay.me/api/auth/token"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());FyPay entrega el certificado en PEM (client.crt + client.key). Si su plataforma exige un archivo .pfx/.p12 (común en Java y en algunos entornos Windows/.NET), conviértalo localmente:
openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12La conversión se hace en su máquina; FyPay no proporciona archivos PFX.
Respuesta (201)
| Campo | Tipo | Descripción |
|---|---|---|
access_token | string | Token JWT para el header Authorization: Bearer <token> |
token_type | string | Siempre Bearer |
expires_in | number | Validez del token en segundos. Renueve antes de que expire según este valor |
scope | string | Alcance del token |
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 600,
"scope": "email profile"
}Errores
| Status | Código | Descripción |
|---|---|---|
| 400 | PUB_CERT_HEADER_MISSING | Certificado de cliente no presentado en el handshake TLS |
| 400 | PUB_CERT_MALFORMED_PEM | Certificado en formato PEM inválido |
| 400 | PUB_REQUEST_BODY_INVALID | Body inválido (ej.: clientId no es UUID v4, clientSecret vacío, campos extra). Los campos con problemas vienen en details.violations |
| 401 | PUB_INVALID_CREDENTIALS | clientId/clientSecret inválidos |
| 401 | PUB_CERT_NOT_VERIFIED | El certificado no pudo verificarse en la conexión |
| 401 | PUB_CERT_NOT_REGISTERED | Certificado no registrado |
| 401 | PUB_CERT_EXPIRED | Certificado expirado |
| 401 | PUB_CERT_NOT_YET_VALID | El certificado aún no está en su período de validez |
| 403 | PUB_CERT_NOT_AUTHORIZED_FOR_ACCOUNT | El certificado no está vinculado a la cuenta de las credenciales |
| 502 | PUB_AUTH_UPSTREAM_ERROR | Error inesperado en el servicio de autenticación |
| 503 | PUB_AUTH_UPSTREAM_UNAVAILABLE | Servicio de autenticación temporalmente no disponible. Intente nuevamente |
{
"statusCode": 401,
"timestamp": "2026-04-17T15:24:28.809Z",
"path": "/api/auth/token",
"method": "POST",
"code": "PUB_INVALID_CREDENTIALS",
"message": "Invalid credentials provided",
"userMessage": "Invalid credentials.",
"errorId": "75d7999d6d7656b737e83435ced86ec6"
}Para una guía completa de autenticación con patrones de renovación de token, vea Guía de Autenticación.