Obtener · Token — Autenticación
Obtén un token de Shopently API válido durante 900 segundos. Consulta la cabecera ApiKey, la respuesta y el uso de Bearer en solicitudes posteriores.
POST/api/v1/auth/token
- Autenticación
ApiKey- Disponible desde
- BASIC
- Permisos necesarios
- No aplicable
Ejemplos de código
Ejemplo de solicitud
cURL
: "${SHOPENTLY_SHOP_URL:?}"
curl --disable --globoff --fail-with-body --silent --show-error \
--proto '=https' --connect-timeout 5 --max-time 30 \
--request POST \
--header "Authorization: ApiKey ${SHOPENTLY_API_KEY:?}" \
--header 'Content-Type: application/json' \
--data-raw '{}' \
--url "${SHOPENTLY_SHOP_URL%/}"/api/v1/auth/token
PHP
<?php
declare(strict_types=1);
$baseUrl = rtrim(getenv('SHOPENTLY_SHOP_URL') ?: '', '/');
$origin = parse_url($baseUrl);
if (!$origin || ($origin['scheme'] ?? '') !== 'https' || empty($origin['host']) ||
isset($origin['user'], $origin['pass']) || isset($origin['user']) || isset($origin['path']) ||
isset($origin['query']) || isset($origin['fragment'])) {
throw new RuntimeException('SHOPENTLY_SHOP_URL must be an HTTPS origin');
}
$credential = getenv('SHOPENTLY_API_KEY') ?: '';
if ($credential === '' || strpbrk($credential, "\r\n") !== false) {
throw new RuntimeException('Invalid credential');
}
$headers = ['Content-Type: application/json'];
$headers[] = 'Authorization: ApiKey ' . $credential;
$responseHeaders = [];
$handle = curl_init($baseUrl . '/api/v1/auth/token');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => $headers,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => false,
CURLOPT_PROTOCOLS => CURLPROTO_HTTPS,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_TIMEOUT => 30,
CURLOPT_HEADERFUNCTION => static function ($handle, string $line) use (&$responseHeaders): int {
if (str_contains($line, ':')) {
[$name, $value] = explode(':', $line, 2);
$responseHeaders[strtolower(trim($name))] = trim($value);
}
return strlen($line);
},
]);
curl_setopt($handle, CURLOPT_POSTFIELDS, '{}');
$raw = curl_exec($handle);
$status = curl_getinfo($handle, CURLINFO_RESPONSE_CODE);
$error = curl_error($handle);
curl_close($handle);
if ($raw === false) {
throw new RuntimeException('Transport error: ' . $error);
}
if ($status < 200 || $status >= 300) {
throw new RuntimeException('HTTP ' . $status . '; request_id=' .
($responseHeaders['x-request-id'] ?? '') . '; retry_after=' . ($responseHeaders['retry-after'] ?? ''));
}
$result = $raw === '' ? null : json_decode($raw, true, 512, JSON_THROW_ON_ERROR | JSON_BIGINT_AS_STRING);
echo json_encode($result, JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), PHP_EOL;
Python
from contextlib import ExitStack
import json
import os
from urllib.parse import urlsplit
import requests # python -m pip install requests
base_url = os.environ["SHOPENTLY_SHOP_URL"].rstrip("/")
origin = urlsplit(base_url)
if origin.scheme != "https" or not origin.hostname or origin.username or origin.password or origin.path or origin.query or origin.fragment:
raise ValueError("SHOPENTLY_SHOP_URL must be an HTTPS origin")
credential = os.environ['SHOPENTLY_API_KEY']
if not credential or "\r" in credential or "\n" in credential:
raise ValueError("Invalid credential")
headers = {}
headers["Authorization"] = 'ApiKey' + " " + credential
body = '{}'
if body is not None:
headers["Content-Type"] = "application/json"
with ExitStack() as stack:
session = stack.enter_context(requests.Session())
files = None
if False:
image = stack.enter_context(open(os.environ["SHOPENTLY_IMAGE_FILE"], "rb"))
if os.fstat(image.fileno()).st_size > 5242880:
raise ValueError("Image exceeds 5 MiB")
files = {"file": ("article.png", image, "image/png")}
response = session.request(
'POST', base_url + '/api/v1/auth/token', headers=headers,
data=body.encode("utf-8") if body is not None else None, files=files,
timeout=(5, 30), allow_redirects=False,
)
if not 200 <= response.status_code < 300:
raise RuntimeError(f"HTTP {response.status_code}; request_id={response.headers.get('X-Request-ID', '')}; retry_after={response.headers.get('Retry-After', '')}")
if False:
if response.headers.get("Content-Type") != "image/webp" or len(response.content) > 5242880:
raise ValueError("Unexpected image response")
with open(os.environ["SHOPENTLY_OUTPUT_FILE"], "xb") as output:
output.write(response.content)
else:
result = response.json() if response.content else None
print(json.dumps(result, ensure_ascii=False, indent=2))
Ejemplo de respuesta 200
{
"data": {
"access_token": "EXAMPLE_ACCESS_TOKEN",
"expires_at": "2026-01-01T12:00:00Z",
"expires_in": 900,
"rate_limits": {
"auth_per_minute": 10,
"read_per_minute": 60,
"write_per_minute": 10
},
"token_type": "Bearer"
},
"meta": {
"request_id": "example"
}
}
Autenticación
- La clave API se envía exclusivamente en la cabecera Authorization de POST /api/v1/auth/token.
- No la incluyas en JSON, una URL ni parámetros de consulta.
- Utiliza el token devuelto para las solicitudes de recursos y renuévalo según expires_at; expires_in se expresa en segundos.
- Un token de acceso no evita la comprobación de los permisos actuales de la clave, los derechos de la tienda, la revocación ni las restricciones IP.
¿Cuánto dura un token?
- expires_in: 900 segundos, es decir, 15 minutos desde su emisión. Las solicitudes no prolongan su validez.
- expires_at: Fecha y hora de caducidad en UTC. Las restricciones de acceso vigentes pueden bloquear el token antes.
Reutiliza el token en varias solicitudes y obtén otro antes de expires_at. No solicites uno nuevo antes de cada operación. Usa la clave API para obtener el nuevo token.
Límites de solicitudes
Engine ≥ 4.143.0. Cada respuesta de token incluye data.rate_limits de la política de la tienda vigente al emitirlo. Todas las claves comparten estos presupuestos; un token nuevo no los reinicia. Un cambio de plan puede aplicarse antes de que caduque el token.
Parámetros
No hay parámetros de ruta, consulta ni cabeceras adicionales.
Cuerpo de la solicitud
application/json · Opcional
TokenRequest
null
Respuestas
Respuesta 200
Modelo completo: ApiResponse_TokenData_
dataTokenDataObligatorioContenido de una respuesta correcta.
Campos ·
dataaccess_tokenCadena de textoObligatorioCredencial Bearer de corta duración.
expires_atCadena de textoObligatorioFecha y hora de caducidad de la credencial.
format:"date-time"expires_inNúmero enteroOpcionalDuración de la credencial en segundos.
rate_limitsTokenRateLimitsDataObligatorioCada respuesta de token incluye data.rate_limits de la política de la tienda vigente al emitirlo. Todas las claves comparten estos presupuestos; un token nuevo no los reinicia. Un cambio de plan puede aplicarse antes de que caduque el token.
Campos ·
rate_limitsModelo completo:
TokenRateLimitsDataauth_per_minuteNúmero enteroObligatorioSolicitudes de token por minuto, incluidos los intentos de autenticación fallidos.
minimum:0maximum:1000000read_per_minuteNúmero enteroObligatorioSolicitudes de lectura por minuto.
minimum:0maximum:1000000write_per_minuteNúmero enteroObligatorioSolicitudes de escritura por minuto; este valor no concede permisos de escritura.
minimum:0maximum:1000000
token_typeCadena de textoOpcionalEsquema de autenticación del token devuelto.
const:"Bearer"
metaContextPageMetaContextMetaPageMetaRequestMetaObligatorioMetadatos de la respuesta.
Campos ·
metaModelo completo:
ContextPageMetalocaleCadena de textoObligatorioIdioma seleccionado para esta solicitud.
market_codeCadena de textoObligatorioCódigo del mercado devuelto por el endpoint de contexto.
market_idCadena de textoObligatorioIdentificador del mercado devuelto por el endpoint de contexto.
paginationPaginationObligatorioMetadatos de la paginación por cursor.
request_idCadena de textoObligatorioIdentificador de la solicitud; en los metadatos de respuesta identifica la solicitud HTTP.
minLength:1maxLength:100
localeCadena de textoObligatorioIdioma seleccionado para esta solicitud.
market_codeCadena de textoObligatorioCódigo del mercado devuelto por el endpoint de contexto.
market_idCadena de textoObligatorioIdentificador del mercado devuelto por el endpoint de contexto.
request_idCadena de textoObligatorioIdentificador de la solicitud; en los metadatos de respuesta identifica la solicitud HTTP.
minLength:1maxLength:100
paginationPaginationObligatorioMetadatos de la paginación por cursor.
request_idCadena de textoObligatorioIdentificador de la solicitud; en los metadatos de respuesta identifica la solicitud HTTP.
minLength:1maxLength:100
request_idCadena de textoObligatorioIdentificador de la solicitud; en los metadatos de respuesta identifica la solicitud HTTP.
minLength:1maxLength:100
Estado HTTP
200- Respuesta correcta Esquema
400- Solicitud no válida
401- Autenticación necesaria
403- Permiso denegado
404- Recurso no encontrado
409- Conflicto de versión
422- Error de validación
429- Límite de solicitudes excedido
Otros estados HTTP (7)
405- Método no permitido
413- Solicitud demasiado grande
415- Formato no compatible
500- Error del servidor
502- Error de la pasarela API
503- Servicio no disponible
504- Tiempo de espera agotado
Catálogo de errores: ErrorResponse
Cabeceras
401
WWW-AuthenticateCadena de textoOpcionalEsquema de autenticación exigido por el servidor.
405
AllowCadena de textoOpcionalMétodos HTTP admitidos por este recurso.
429, 503
Retry-AfterNúmero enteroOpcionalEspera mínima antes de reintentar, en segundos.
minimum:0.0