Saltar al contenido
Developer Docs

Autenticación

Autenticación OAuth2 Client Credentials con Basic Auth. Obtienes un access_token de corta duración que viaja en cada llamada.

La autenticación en la API de Zertiban se basa en el estándar OAuth2 Client Credentials, utilizando Basic Auth para la obtención del token. Este mecanismo está diseñado para integraciones server-to-server seguras, en las que el cliente intercambia sus credenciales por un access_token de corta duración que se utiliza en todas las llamadas posteriores a la API.

Las credenciales (clientId y clientSecret) no se envían en el cuerpo de la petición, sino en el header mediante Basic Auth. Esto significa que deben incluirse en el encabezado Authorization, codificadas automáticamente por los clientes HTTP estándar.

Endpoint

POST/idp/oauth2/token con grant_type=client_credentials.

Las credenciales van en el header

Authorization como Basic Auth, no en el cuerpo de la petición.

La opción -u clientId:clientSecret de curl, auth=(id, secret) de Python requests y auth: { username, password } de axios construyen este header automáticamente.

Nota histórica: scope no es necesario

En documentación previa de PagaFactu se añadía también --data-urlencode 'scope=openid profile api'. No es necesario.

Pide el token

shell
curl -X POST https://nc-api-sandbox.zertiban.com/idp/oauth2/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -u '{clientId}:{clientSecret}' \
  --data-urlencode 'grant_type=client_credentials'
python
import requests

response = requests.post(
    "https://nc-api-sandbox.zertiban.com/idp/oauth2/token",
    auth=(CLIENT_ID, CLIENT_SECRET),
    data={"grant_type": "client_credentials"}
)
token = response.json()["access_token"]
expires_in = response.json()["expires_in"]
javascript
const credentials = Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString('base64');
const response = await fetch('https://nc-api-sandbox.zertiban.com/idp/oauth2/token', {
  method: 'POST',
  headers: {
    Authorization: `Basic ${credentials}`,
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  body: 'grant_type=client_credentials'
});

const { access_token, expires_in } = await response.json();
javascript
const response = await axios.post(
  'https://nc-api-sandbox.zertiban.com/idp/oauth2/token',
  'grant_type=client_credentials',
  {
    auth: { username: CLIENT_ID, password: CLIENT_SECRET },
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
  }
);
const { access_token, expires_in } = response.data;
java
TokenResponse token = WebClient.create("https://nc-api-sandbox.zertiban.com")
    .post().uri("/idp/oauth2/token")
    .headers(h -> h.setBasicAuth(clientId, clientSecret))
    .contentType(MediaType.APPLICATION_FORM_URLENCODED)
    .body(BodyInserters.fromFormData("grant_type", "client_credentials"))
    .retrieve()
    .bodyToMono(TokenResponse.class)
    .block();

String accessToken = token.getAccessToken();
int expiresIn = token.getExpiresIn();

Recibe el access_token

json
{
  "access_token": "eyJraWQiOiJ...",
  "token_type": "Bearer",
  "expires_in": 300
}

Renueva antes de que caduque

El token dura 300 segundos (5 minutos) por defecto. Usa siempre el valor de expires_in de la respuesta, no lo pongas fijo en tu código, ya que puede variar. Renuévalo antes de que caduque para evitar errores 401.

Usa el token en cada llamada

A partir de aquí, todas las llamadas llevan estos dos headers:

http
Authorization: Bearer {access_token}
x-tenant-id: {businessUuid}
HeaderDescripción
AuthorizationToken devuelto en el paso 2, con prefijo Bearer
x-tenant-idTu businessUuid, identifica el negocio sobre el que operas