Drop · API de Integraciones

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

HeaderContenido
X-Drop-KeyTu keyId
X-Drop-TimestampUnix epoch en segundos
X-Drop-NonceÚnico por petición. 8–128 caracteres [A-Za-z0-9_.-] (un UUID sirve)
X-Drop-SignatureLa 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:

  1. Método en mayúsculas.
  2. Ruta tal cual, incluyendo el prefijo /integrations/v1. Sin la URL base.
  3. 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.
  4. 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, donde ids[]=a se convierte en la clave ids: si firmás ids[] la verificación falla aunque todo lo demás esté bien. Es la causa menos evidente de INVALID_SIGNATURE.
  5. 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
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

Con 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)

sign.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"
  }
}
CampoNotas
partnerNombre con el que estás dado de alta
slugIdentificador corto de tu integración
scopesLos permisos de esta credencial. Si falta alguno que esperabas, avisanos antes de seguir
serverTimeHora 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.

En esta página