Autenticación
Cada petición se firma con HMAC-SHA256. Cómo armar la cadena canónica y la firma.
Cada petición se firma con HMAC-SHA256. No hay tokens ni sesiones: la firma se calcula en cada llamada.
Headers obligatorios
| Header | Contenido |
|---|---|
X-Drop-Key | Tu keyId |
X-Drop-Timestamp | Unix epoch en segundos |
X-Drop-Nonce | Único por petición. 8–128 caracteres [A-Za-z0-9_.-] (un UUID sirve) |
X-Drop-Signature | La firma, en hex minúscula |
Cadena canónica
Cinco campos unidos por \n (saltos de línea reales, no la secuencia \n):
MÉTODO EN MAYÚSCULAS
/ruta?query-canónica
timestamp
nonce
sha256_hex(cuerpo_crudo)Reglas a reproducir exactamente:
- Método en mayúsculas.
- Ruta tal cual, incluyendo el prefijo
/integrations/v1. Sin la URL base. - Query canónica. Si no hay query, se omite el
?completo. Si la hay: percent-encodear claves y valores antes de ordenar y de unir con=/&. Ordenar por la clave ya codificada; para claves repetidas, por el valor ya codificado. El orden de la cadena firmada no tiene que coincidir con el orden en que los parámetros viajan en la URL. - Arreglos: mandalos como claves repetidas (
?ids=a&ids=b), no con corchetes (?ids[]=a). Nuestro servidor construye la cadena a partir del query ya interpretado, dondeids[]=ase convierte en la claveids: si firmásids[]la verificación falla aunque todo lo demás esté bien. Es la causa menos evidente deINVALID_SIGNATURE. - Cuerpo: SHA-256 en hex del cuerpo crudo. Sin cuerpo, es el hash de la
cadena vacía:
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855. Se hashea exactamente lo que ponés en el socket, no el JSON re-serializado.
Ejemplo para GET /integrations/v1/ping:
GET
/integrations/v1/ping
1786462395
6a2fb63b-d2f4-4789-a2e7-854b7d6c46e2
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855Con query, la segunda línea sería por ejemplo
/integrations/v1/products?active=true&limit=50&page=1.
Firma
signature = hex( HMAC_SHA256( secreto, cadena_canónica ) )Implementación de referencia (Node.js)
const crypto = require('crypto');
function signedHeaders({ keyId, secret, method, path, query = {}, body = '' }) {
const timestamp = String(Math.floor(Date.now() / 1000));
const nonce = crypto.randomUUID();
const canonicalQuery = Object.entries(query)
.map(([k, v]) => ({
key: encodeURIComponent(k),
values: (Array.isArray(v) ? v : [v]).map(encodeURIComponent).sort(),
}))
.sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0))
.flatMap(({ key, values }) => values.map(v => `${key}=${v}`))
.join('&');
const canonical = [
method.toUpperCase(),
canonicalQuery ? `${path}?${canonicalQuery}` : path,
timestamp,
nonce,
crypto.createHash('sha256').update(body).digest('hex'),
].join('\n');
return {
'X-Drop-Key': keyId,
'X-Drop-Timestamp': timestamp,
'X-Drop-Nonce': nonce,
'X-Drop-Signature': crypto
.createHmac('sha256', secret)
.update(canonical)
.digest('hex'),
};
}Si mandás cuerpo, firmá la misma cadena que enviás. Serializar dos veces, una para firmar y otra para mandar, es el error más común: dos serializaciones del mismo objeto pueden diferir en un espacio o en el orden de las claves, y la firma deja de coincidir.
Reloj
La tolerancia del timestamp es de ±300 segundos. Corré NTP: un reloj
desviado más de 5 minutos rechaza el 100 % de tus peticiones con
TIMESTAMP_OUT_OF_RANGE. GET /ping
devuelve serverTime para que compares.
Nonce
Debe ser único por petición, no por operación. Si reintentás una petición
fallida, generá un nonce nuevo; reutilizarlo devuelve REPLAYED_NONCE.
Tu primera llamada
curl -X GET '{BASE_URL}/integrations/v1/ping' \
-H 'X-Drop-Key: pk_live_3f9a1c02' \
-H 'X-Drop-Timestamp: 1786462395' \
-H 'X-Drop-Nonce: 6a2fb63b-d2f4-4789-a2e7-854b7d6c46e2' \
-H 'X-Drop-Signature: 0aaaca6f924204007d795c12b114c3959cbc77349184c351a612ff25c2e9dfb4'{
"data": {
"partner": "Tu Empresa",
"slug": "tuempresa",
"scopes": ["products:read", "orders:read", "orders:write", "geo:read"],
"serverTime": "2026-08-11T15:33:15.421Z"
}
}| Campo | Notas |
|---|---|
partner | Nombre con el que estás dado de alta |
slug | Identificador corto de tu integración |
scopes | Los permisos de esta credencial. Si falta alguno que esperabas, avisanos antes de seguir |
serverTime | Hora del servidor en ISO 8601 UTC. Compará contra tu reloj: más de 300 s de diferencia y todo lo demás va a fallar |
Empezá por acá: valida tus credenciales, tus permisos y tu implementación de la firma sin tocar datos.
Referencia: GET /ping.