Primera solicitud
Comprueba la conexión con tu tienda. Crea una clave API, obtén un token y envía tu primera petición, paso a paso.
Primeros pasos
- Crear una clave
- Obtener un token
- Comprobar la conexión
Primeros pasos
-
Crear una clave API
Abre los ajustes de API en el panel de administración de tu tienda y crea una clave.
Guarda la clave en un lugar seguro. No podrás volver a verla después de cerrar la ventana.
Crear una clave API
SHOPENTLY_SHOP_URL- La dirección HTTPS de tu tienda, sin /api/v1. Sustituye el ejemplo por tu propia dirección.
https://twoj-sklep.exampleSHOPENTLY_API_KEY- La clave generada en el panel de la tienda.
Autenticación
Los ejemplos cURL utilizan SHOPENTLY_SHOP_URL, SHOPENTLY_API_KEY y SHOPENTLY_ACCESS_TOKEN como variables locales de ejemplo. Configúralas de forma privada en el servidor de integración; nunca publiques credenciales reales en código fuente, páginas del navegador, capturas de pantalla o registros.
-
Obtener · Token
POST/api/v1/auth/tokenUsa tu clave para obtener un token. Lo enviarás con tus siguientes peticiones.
Ejemplos
Ejemplo de solicitud
cURL
: "${SHOPENTLY_SHOP_URL:?}" response=$(curl --disable --globoff --fail-with-body --silent --show-error \ --proto '=https' --connect-timeout 5 --max-time 30 \ --write-out '\n%{http_code}' \ --request POST \ --header "Authorization: ApiKey ${SHOPENTLY_API_KEY:?}" \ --header 'Content-Type: application/json' \ --data-raw '{}' \ --url "${SHOPENTLY_SHOP_URL%/}"/api/v1/auth/token) || exit 1 status=$(printf '%s' "$response" | tail -n 1) case "$status" in 2??) printf '%s\n' "$response" | sed '$d' ;; *) printf 'HTTP %s\n' "$status" >&2; exit 1 ;; esacPHP
<?php $base = rtrim(getenv('SHOPENTLY_SHOP_URL') ?: '', '/'); $origin = parse_url($base); if (!$origin || ($origin['scheme'] ?? '') !== 'https' || empty($origin['host']) || array_intersect(['user', 'pass', 'path', 'query', 'fragment'], array_keys($origin))) { throw new RuntimeException('SHOPENTLY_SHOP_URL must be an HTTPS origin'); } $credential = getenv('SHOPENTLY_API_KEY') ?: ''; if ($credential === '' || preg_match('/\s/', $credential)) { throw new RuntimeException('Invalid credential'); } $curl = curl_init($base . '/api/v1/auth/token'); curl_setopt_array($curl, [ CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_HTTPHEADER => ['Authorization: ApiKey ' . $credential, 'Content-Type: application/json'], CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => false, CURLOPT_PROTOCOLS => CURLPROTO_HTTPS, CURLOPT_CONNECTTIMEOUT => 5, CURLOPT_TIMEOUT => 30, CURLOPT_POSTFIELDS => '{}', ]); $raw = curl_exec($curl); $status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE); curl_close($curl); if ($raw === false || $status < 200 || $status >= 300) { throw new RuntimeException('Request failed; HTTP ' . $status); } $result = json_decode($raw, true, 512, JSON_THROW_ON_ERROR | JSON_BIGINT_AS_STRING); echo json_encode($result, JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT), PHP_EOL;Python
import json import os from urllib.parse import urlsplit import requests base = os.environ["SHOPENTLY_SHOP_URL"].rstrip("/") origin = urlsplit(base) if (origin.scheme != "https" or not origin.hostname or origin.username is not None 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 any(c.isspace() for c in credential): raise ValueError("Invalid credential") response = requests.request( "POST", base + "/api/v1/auth/token", headers={"Authorization": "ApiKey " + credential}, timeout=(5, 30), allow_redirects=False, json={}, ) if not 200 <= response.status_code < 300: raise RuntimeError(f"HTTP {response.status_code}") result = response.json() print(json.dumps(result, ensure_ascii=False, indent=2))Ejemplo de respuesta · HTTP 200
JSON { "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" } }Respuesta
data.access_token- Token para la cabecera Authorization: Bearer. Define SHOPENTLY_ACCESS_TOKEN antes de ejecutar el ejemplo por separado.
data.expires_in- 900 segundos, es decir, 15 minutos desde su emisión. Las solicitudes no prolongan su validez.
data.expires_at- Fecha y hora de caducidad en UTC. Las restricciones de acceso vigentes pueden bloquear el token antes.
data.rate_limits- 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.
-
Comprobar la conexión con tu tienda
GET/api/v1/contextEnvía una petición con el token. La respuesta muestra los idiomas y mercados disponibles en tu tienda.
Ejemplo de solicitud
cURL
: "${SHOPENTLY_SHOP_URL:?}" response=$(curl --disable --globoff --fail-with-body --silent --show-error \ --proto '=https' --connect-timeout 5 --max-time 30 \ --write-out '\n%{http_code}' \ --request GET \ --header "Authorization: Bearer ${SHOPENTLY_ACCESS_TOKEN:?}" \ --url "${SHOPENTLY_SHOP_URL%/}"/api/v1/context) || exit 1 status=$(printf '%s' "$response" | tail -n 1) case "$status" in 2??) printf '%s\n' "$response" | sed '$d' ;; *) printf 'HTTP %s\n' "$status" >&2; exit 1 ;; esacPHP
<?php $base = rtrim(getenv('SHOPENTLY_SHOP_URL') ?: '', '/'); $origin = parse_url($base); if (!$origin || ($origin['scheme'] ?? '') !== 'https' || empty($origin['host']) || array_intersect(['user', 'pass', 'path', 'query', 'fragment'], array_keys($origin))) { throw new RuntimeException('SHOPENTLY_SHOP_URL must be an HTTPS origin'); } $credential = getenv('SHOPENTLY_ACCESS_TOKEN') ?: ''; if ($credential === '' || preg_match('/\s/', $credential)) { throw new RuntimeException('Invalid credential'); } $curl = curl_init($base . '/api/v1/context'); curl_setopt_array($curl, [ CURLOPT_CUSTOMREQUEST => 'GET', CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $credential], CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => false, CURLOPT_PROTOCOLS => CURLPROTO_HTTPS, CURLOPT_CONNECTTIMEOUT => 5, CURLOPT_TIMEOUT => 30, ]); $raw = curl_exec($curl); $status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE); curl_close($curl); if ($raw === false || $status < 200 || $status >= 300) { throw new RuntimeException('Request failed; HTTP ' . $status); } $result = json_decode($raw, true, 512, JSON_THROW_ON_ERROR | JSON_BIGINT_AS_STRING); echo json_encode($result, JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT), PHP_EOL;Python
import json import os from urllib.parse import urlsplit import requests base = os.environ["SHOPENTLY_SHOP_URL"].rstrip("/") origin = urlsplit(base) if (origin.scheme != "https" or not origin.hostname or origin.username is not None or origin.path or origin.query or origin.fragment): raise ValueError("SHOPENTLY_SHOP_URL must be an HTTPS origin") credential = os.environ["SHOPENTLY_ACCESS_TOKEN"] if not credential or any(c.isspace() for c in credential): raise ValueError("Invalid credential") response = requests.request( "GET", base + "/api/v1/context", headers={"Authorization": "Bearer " + credential}, timeout=(5, 30), allow_redirects=False, ) if not 200 <= response.status_code < 300: raise RuntimeError(f"HTTP {response.status_code}") result = response.json() print(json.dumps(result, ensure_ascii=False, indent=2))Ejemplo de respuesta · HTTP 200
JSON { "data": { "base_market_id": "example", "default_locale": "en", "global_enabled": false, "languages": [ { "code": "en", "direction": "ltr", "is_default": true, "name": "English", "native_name": "English", "status": "draft" } ], "markets": [ { "code": "PL", "currency": { "code": "PLN", "minor_units": 2 }, "id": "example", "is_default": true, "name": "Poland", "price_list": null, "status": "draft" } ], "multilingual_enabled": false }, "meta": { "locale": "en", "market_code": "PL", "market_id": "example", "request_id": "example" } }Respuesta
Utiliza los identificadores de idiomas y mercados devueltos en las siguientes solicitudes.
¿Cómo reconocer una conexión correcta?
Una respuesta HTTP 200 con los datos de tu tienda confirma que la conexión funciona.
El programa completo obtiene un token y consulta el contexto en una sola ejecución. El código adicional comprueba la configuración y gestiona el transporte y los errores.
Ejemplo completo
Ejecutar el ejemplo
Ejecuta el ejemplo completo en el terminal, en PHP o en Python.
PHP 8.3 (64-bit, ext-curl, JSON) · Python 3.12 + requests · cURL 8 + jq 1.7.
cURL
#!/bin/sh
# POSIX shell, curl 8+, jq 1.7. Credentials stay in environment variables.
set -eu
: "${SHOPENTLY_SHOP_URL:?}"
base=${SHOPENTLY_SHOP_URL%/}
case "$base" in https://*) ;; *) echo 'Use an HTTPS origin' >&2; exit 1;; esac
authority=${base#https://}
case "$authority" in ''|*/*|*\?*|*\#*|*@*) echo 'Use an HTTPS origin' >&2; exit 1;; esac
work=$(mktemp -d)
trap 'rm -rf "$work"' EXIT HUP INT TERM
chmod 700 "$work"
encode() { printf '%s' "$1" | jq -sRr @uri; }
api() {
method=$1; path=$2; body=${3-}; key=${4-}
scheme=Bearer; credential=${SHOPENTLY_ACCESS_TOKEN-}
if [ "$path" = /api/v1/auth/token ]; then scheme=ApiKey; credential=${SHOPENTLY_API_KEY-}; fi
[ -n "$credential" ] || { echo 'Missing credential' >&2; return 1; }
set -- --disable --globoff --silent --show-error --proto '=https' --connect-timeout 5 --max-time 30 \
--request "$method" --header "Authorization: $scheme $credential" \
--dump-header "$work/headers" --output "$work/body" --write-out '%{http_code}'
if [ -n "$key" ]; then set -- "$@" --header "Idempotency-Key: $key"; fi
if [ -n "$body" ]; then set -- "$@" --header 'Content-Type: application/json' --data-raw "$body"; fi
status=$(curl "$@" --url "$base$path") || return 1
case "$status" in
2??) if [ -s "$work/body" ]; then jq -e . "$work/body"; else printf 'null\n'; fi ;;
*) printf 'HTTP %s\n' "$status" >&2
jq -c '.error | {code, fields}' "$work/body" >&2 2>/dev/null || true
return 1 ;;
esac
}
token=$(api POST /api/v1/auth/token '{}')
SHOPENTLY_ACCESS_TOKEN=$(printf '%s' "$token" | jq -er '.data.access_token')
export SHOPENTLY_ACCESS_TOKEN
api GET /api/v1/context
PHP
<?php
declare(strict_types=1);
// PHP 8.3+, 64-bit, ext-curl. Credentials stay in environment variables.
function env(string $name): string {
$value = getenv($name);
if ($value === false || $value === '' || strpbrk($value, "\r\n") !== false) {
throw new RuntimeException('Invalid environment variable: ' . $name);
}
return $value;
}
$base = rtrim(env('SHOPENTLY_SHOP_URL'), '/');
$origin = parse_url($base);
if (!$origin || ($origin['scheme'] ?? '') !== 'https' || empty($origin['host']) ||
isset($origin['user']) || isset($origin['pass']) || isset($origin['path']) ||
isset($origin['query']) || isset($origin['fragment']) || PHP_INT_SIZE !== 8) {
throw new RuntimeException('Use a 64-bit PHP runtime and an HTTPS origin');
}
class ApiError extends RuntimeException {
public function __construct(public int $status, public array $headers, public array $error) {
parent::__construct('HTTP ' . $status . '; code=' . ($error['code'] ?? '') .
'; request_id=' . ($headers['x-request-id'] ?? ''));
}
}
function api(string $method, string $path, array $query = [], ?array $body = null, ?string $key = null, bool $apiKey = false): ?array {
global $base;
$credential = env($apiKey ? 'SHOPENTLY_API_KEY' : 'SHOPENTLY_ACCESS_TOKEN');
$headers = ['Authorization: ' . ($apiKey ? 'ApiKey ' : 'Bearer ') . $credential];
if ($key !== null) $headers[] = 'Idempotency-Key: ' . $key;
if ($body !== null) $headers[] = 'Content-Type: application/json';
$url = $base . $path . ($query ? '?' . http_build_query($query, '', '&', PHP_QUERY_RFC3986) : '');
$responseHeaders = [];
$h = curl_init($url);
curl_setopt_array($h, [
CURLOPT_CUSTOMREQUEST => $method, 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 ($h, string $line) use (&$responseHeaders): int {
if (str_contains($line, ':')) {
[$name, $value] = explode(':', $line, 2);
$responseHeaders[strtolower(trim($name))] = trim($value);
}
return strlen($line);
},
]);
if ($body !== null) {
$json = $apiKey && $body === [] ? '{}' : json_encode($body, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);
curl_setopt($h, CURLOPT_POSTFIELDS, $json);
}
$raw = curl_exec($h);
$status = curl_getinfo($h, CURLINFO_RESPONSE_CODE);
$error = curl_error($h);
curl_close($h);
if ($raw === false) throw new RuntimeException('Transport error: ' . $error);
if ($status < 200 || $status >= 300) {
$data = json_decode($raw, true);
throw new ApiError($status, $responseHeaders, is_array($data) ? ($data['error'] ?? []) : []);
}
return $raw === '' ? null : json_decode($raw, true, 512, JSON_THROW_ON_ERROR | JSON_BIGINT_AS_STRING);
}
function output(mixed $value): void {
echo json_encode($value, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE), PHP_EOL;
}
$token = api('POST', '/api/v1/auth/token', body: [], apiKey: true)['data'];
putenv('SHOPENTLY_ACCESS_TOKEN=' . $token['access_token']);
output(api('GET', '/api/v1/context'));
Python
"""Run with Python 3.12 and requests. Credentials stay in environment variables."""
import json
import os
import random
import time
from urllib.parse import quote, urlencode, urlsplit
import requests
def env(name):
value = os.environ[name]
if not value or "\r" in value or "\n" in value:
raise ValueError("Invalid environment variable: " + name)
return value
base = env("SHOPENTLY_SHOP_URL").rstrip("/")
origin = urlsplit(base)
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")
class ApiError(RuntimeError):
def __init__(self, response):
self.status = response.status_code
self.request_id = response.headers.get("X-Request-ID", "")
self.retry_after = response.headers.get("Retry-After", "")
try:
self.error = response.json().get("error", {})
except (ValueError, AttributeError):
self.error = {}
super().__init__(f"HTTP {self.status}; code={self.error.get('code', '')}; request_id={self.request_id}")
def api(method, path, *, query=None, body=None, key=None, api_key=False):
credential = env("SHOPENTLY_API_KEY" if api_key else "SHOPENTLY_ACCESS_TOKEN")
headers = {"Authorization": ("ApiKey " if api_key else "Bearer ") + credential}
if key:
headers["Idempotency-Key"] = key
if body is not None:
headers["Content-Type"] = "application/json"
response = requests.request(method, base + path, params=query, headers=headers,
data=json.dumps(body, ensure_ascii=False, allow_nan=False).encode() if body is not None else None,
timeout=(5, 30), allow_redirects=False)
if not 200 <= response.status_code < 300:
raise ApiError(response)
return response.json() if response.content else None
def segment(value):
return quote(value, safe="")
token = api("POST", "/api/v1/auth/token", body={}, api_key=True)["data"]
os.environ["SHOPENTLY_ACCESS_TOKEN"] = token["access_token"]
print(json.dumps(api("GET", "/api/v1/context"), ensure_ascii=False, indent=2))