POST/api/v6/urlshortener/links/batch

Crear enlaces cortos en lote

Hasta 1.000 enlaces en una petición, con un resultado por enlace y un solo cobro por lo que se creó.

Alcance y límites

Alcance

API key con el servicio urlshortener habilitado y la capacidad urlshortener.write concedida

Límite de uso

35 solicitudes por segundo

Idempotencia

Admite Idempotency-Key

  • Las 35 solicitudes por segundo son las mismas del alta de un enlace: las dos rutas gastan un solo cupo.
  • Además, hasta 2.100 enlaces por minuto por organización entre todos sus lotes. Un lote que no cabe se rechaza entero.
  • Hasta 1.000 enlaces por petición; el cuerpo, hasta 3 MiB; cada destino, hasta 2048 caracteres.
  • Con plan: los enlaces del lote cuentan en el cupo diario de altas (100.000 por día de Colombia).

Crea hasta 1.000 enlaces en una petición. Cada enlace del lote lleva los mismos cuatro campos que el alta de un enlace y pasa exactamente por las mismas comprobaciones: el destino, el alias, el dominio y el vencimiento.

Un enlace inválido no tumba el lote: la respuesta es 200 con un resultado por enlace, en el orden del cuerpo —created, replayed o failed—, y cada fallido trae en error.code el mismo código que devolvería el alta de ese enlace sola. Lo que sí es del lote entero se contesta sin crear nada: un cuerpo inválido o con más de 1.000 enlaces (400), la llave usada con otro cuerpo (422), el saldo o un tope de gasto (402), la falta de precio o de moneda (409) y los límites de uso (429).

Un solo cobro por lo que se creó. Se reserva de tu saldo el precio de todos los enlaces válidos a la vez y se cobra solo por los que de verdad se crearon: si de 1.000 se crean 998, se cobran 998. Sin saldo para todos, 402 y no se crea ninguno; manda un lote más pequeño. Con un plan mensual del acortador vigente no se cobra, y los enlaces del lote cuentan en el cupo diario de altas: un lote que no cabe entero se rechaza entero con 429 URLSHORTENER_LINK_QUOTA_EXCEEDED, y el mensaje dice cuántos te quedan hoy.

Reintenta sin duplicar con `Idempotency-Key`. La llave es del lote: si una petición se corta y la repites con la misma llave y el mismo cuerpo, los enlaces que ya se crearon vuelven como replayed —los mismos, sin crear otros ni cobrarlos dos veces, aunque la primera todavía se esté procesando— y los que fallaron se vuelven a intentar. Lo ya creado nunca se esconde: si lo que faltaba choca con el saldo, un límite o un fallo nuestro, la respuesta sigue siendo 200 con los replayed, y cada enlace pendiente sale failed con el código de ese rechazo. Con la llave y otro cuerpo, 422 IDEMPOTENCY_KEY_REUSED. Sin llave, cada reintento crea y cobra otro lote.

El límite cuenta enlaces, no peticiones. Además del cupo de solicitudes, que comparte con el alta de un enlace, tu organización puede crear en lote hasta 2.100 enlaces por minuto (35 por segundo, el mismo ritmo del alta de uno). Caben dos lotes de 1.000 seguidos; un lote que no cabe se rechaza entero con 429 RATE_TPS_EXCEEDED y Retry-After, sin crear ni cobrar nada. El alta de un enlace no gasta este límite.

Pide una key que pueda escribir

Además del servicio urlshortener, la API key necesita la capacidad urlshortener.write, y solo la concede un propietario o un administrador de tu organización al crear la key. Sin ella, la key lista y consulta enlaces, estadísticas, el resumen, los dominios y la tarifa, y aquí recibe 403 AUTH_CAPABILITY_NOT_ALLOWED.

Cabeceras

Idempotency-Key
stringopcional
Llave de idempotencia opcional del lote (1 a 255 caracteres de A-Za-z0-9_-), única por organización. Si repites el lote con la misma llave y el mismo cuerpo, recibes los enlaces que ya se crearon —replayed— sin crearlos ni cobrarlos otra vez, y lo que no se creó la primera vez se vuelve a intentar. Con otro cuerpo, 422 IDEMPOTENCY_KEY_REUSED. Es independiente de las llaves del alta de un enlace. Ver la guía de idempotencia.

Cuerpo de la petición

application/jsonSolo se acepta `links`, y en cada enlace solo sus cuatro campos. Uno que no existe se rechaza con `400` nombrando el campo, y el lote no se atiende.
links
arrayobligatorio
Los enlaces a crear, de 1 a 1.000. La posición de cada uno es su index en la respuesta.
longUrl
stringobligatorio
URL de destino, con las mismas reglas del alta de un enlace.
domain
stringopcional
Dominio donde publicarlo. Si lo omites, el predeterminado de tu organización.
code
stringopcional
Alias opcional, con las mismas reglas del alta de un enlace. Dos enlaces del mismo lote con el mismo alias en el mismo dominio: el primero se lo queda y el otro sale failed con ALIAS_TAKEN.
expiresAt
stringopcional
Vencimiento opcional, siempre futuro. Sin zona horaria se interpreta en hora de Colombia (-05:00).
{
  "links": [
    { "longUrl": "https://example.com/landing?utm_source=sms&c=1" },
    { "longUrl": "https://example.com/landing?utm_source=sms&c=2", "code": "promo-octubre" },
    { "longUrl": "https://example.com/landing?utm_source=sms&c=3", "expiresAt": "2026-12-31T23:59:59-05:00" }
  ]
}

Respuestas

200

El lote se atendió: los totales y un resultado por enlace, en el orden del cuerpo. Con Idempotency-Key, la cabecera Idempotency-Status dice replayed si esta petición no creó nada nuevo y devolvió lo de antes, y created si creó algo. Cuando la llave devuelve enlaces de antes, los rechazos del lote entero (402, 409, 429, 5xx) no se contestan como error: van en cada enlace pendiente, con su código, y los replayed llegan igual.

{
  "success": true,
  "data": {
    "created": 2,
    "replayed": 0,
    "failed": 1,
    "items": [
      {
        "index": 0,
        "status": "created",
        "link": {
          "domain": "h0b.co",
          "code": "a1b2c3d",
          "shortUrl": "https://h0b.co/a1b2c3d",
          "longUrl": "https://example.com/landing?utm_source=sms&c=1",
          "isAlias": false,
          "status": "active",
          "domainStatus": "active",
          "expiresAt": null,
          "createdAt": "2026-09-30T15:04:05Z",
          "clicks": 0,
          "uniqueClicks": 0,
          "firstClickAt": null,
          "lastClickAt": null
        }
      },
      {
        "index": 1,
        "status": "failed",
        "error": { "code": "ALIAS_TAKEN", "message": "Ese código ya se usó en el dominio y no se puede volver a usar." }
      },
      {
        "index": 2,
        "status": "created",
        "link": {
          "domain": "h0b.co",
          "code": "k9x8w7v",
          "shortUrl": "https://h0b.co/k9x8w7v",
          "longUrl": "https://example.com/landing?utm_source=sms&c=3",
          "isAlias": false,
          "status": "active",
          "domainStatus": "active",
          "expiresAt": "2027-01-01T04:59:59Z",
          "createdAt": "2026-09-30T15:04:05Z",
          "clicks": 0,
          "uniqueClicks": 0,
          "firstClickAt": null,
          "lastClickAt": null
        }
      }
    ]
  },
  "meta": {
    "requestId": "8f0c0e2a4b1d4c8fae2b7a91e0c5d3f6",
    "timestamp": "2026-09-23T18:30:00+00:00",
    "responseTimeMs": 7.2
  }
}
400

El cuerpo no se puede leer, no trae enlaces, trae más de 1.000 (URLSHORTENER_BATCH_TOO_LARGE) o un campo que no existe, o la Idempotency-Key tiene otra forma. No se creó nada.

401

Credenciales inválidas o faltantes.

402

Tu organización no tiene saldo para todos los enlaces válidos del lote (o no tiene cuenta de facturación activa), o crearlos superaría un tope de gasto que ella misma configuró. No se creó ninguno.

403

La API key no tiene habilitado el acortador (o está apagado para tu organización), no tiene la capacidad urlshortener.write para crear y editar enlaces, no se puede usar desde la red de la petición, o la organización no está activa.

409

El acortador no tiene precio para la moneda de tu organización, o tu organización todavía no tiene moneda. No se arregla reintentando.

422

La Idempotency-Key ya creó enlaces con otro cuerpo. Usa una llave nueva para un lote nuevo.

429

Se excedió el límite de solicitudes, el de enlaces por minuto de los lotes, o —con plan— el cupo diario de altas. El lote entero se rechaza sin crear nada; Retry-After dice cuánto esperar.

500

Error interno. Reintenta con la misma Idempotency-Key: lo que ya se hubiera creado vuelve como replayed.

503

No se pudo comprobar el saldo en este momento. No se creó nada; puedes reintentar (mejor con Idempotency-Key).

Errores posibles

Códigos que este endpoint puede devolver en error.code. El detalle completo está en el catálogo.

401AUTH_REQUIREDNo se envió un token Bearer y cada llamada lo requiere.401AUTH_INVALID_KEYLa API key no se reconoce: formato equivocado, revocada o vencida.403AUTH_SERVICE_NOT_ALLOWEDLa key no tiene permitido el servicio detrás de este endpoint.403AUTH_IP_NOT_ALLOWEDLa key solo funciona desde ciertas redes y tu IP no está entre ellas.403ACCOUNT_NOT_ACTIVETu organización está suspendida o cerrada.403AUTH_CAPABILITY_NOT_ALLOWEDLa key tiene el servicio, pero no la capacidad que exige este endpoint.400VALIDATION_INVALID_PARAMETERUn parámetro o un campo del cuerpo no es válido.400URLSHORTENER_BATCH_TOO_LARGEEl lote trae más enlaces de los que admite una petición.400IDEMPOTENCY_KEY_INVALIDLa llave de idempotencia no cumple el formato.422IDEMPOTENCY_KEY_REUSEDLa llave ya existe, pero con un cuerpo distinto.400URL_INVALIDLa URL de destino está mal formada.400URL_SCHEME_NOT_ALLOWEDSolo se admiten destinos http y https.400URL_TOO_LONGLa URL de destino supera el largo máximo.400URL_BLOCKED_HOSTEl host de destino es privado o reservado.400ALIAS_INVALIDEl alias no cumple el formato permitido.409ALIAS_TAKENEl alias ya se usó en este dominio.409ALIAS_RESERVEDEl alias es una palabra reservada.409ALIAS_RETIREDEl alias es de un enlace tuyo que eliminaste.400EXPIRES_AT_INVALID`expiresAt` debe ser una fecha ISO futura.400DOMAIN_NOT_ALLOWEDEl dominio elegido no está disponible para tu cuenta.409DOMAIN_NOT_VERIFIEDTu dominio todavía no está verificado.402URLSHORTENER_INSUFFICIENT_FUNDSTu organización no tiene saldo para crear el enlace.402URLSHORTENER_SPEND_LIMIT_REACHEDSe alcanzó un tope de gasto que tu organización configuró.403ACCOUNT_CONFIG_NOT_FOUNDNo pudimos cargar la organización de tu key.409URLSHORTENER_NOT_PRICEDEl acortador no tiene precio configurado para tu moneda.409URLSHORTENER_CURRENCY_UNDEFINEDTu organización todavía no tiene moneda definida.429URLSHORTENER_LINK_QUOTA_EXCEEDEDTu organización llegó al cupo diario de enlaces de su plan.429RATE_TPS_EXCEEDEDExcediste el cupo de tu organización para este endpoint.500INTERNAL_SERVER_ERRORAlgo salió mal de nuestro lado.503SERVICE_UNAVAILABLE503 genérico: un servicio del que dependemos no responde.
Ver el catálogo completo
POST /api/v6/urlshortener/links/batch
curl -X POST 'https://developers.hablame.co/api/v6/urlshortener/links/batch' \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer hk_TU_API_KEY' \
  -H 'Content-Type: application/json' \
  --data '{"links":[{"longUrl":"https://example.com/landing?utm_source=sms&c=1"},{"longUrl":"https://example.com/landing?utm_source=sms&c=2","code":"promo-octubre"},{"longUrl":"https://example.com/landing?utm_source=sms&c=3","expiresAt":"2026-12-31T23:59:59-05:00"}]}'

Try-It

Ejecuta la petición contra la API real con tu propia API key.

La key se usa solo en tu navegador para esta petición. No se guarda ni se envía a ningún otro lado.

Parámetros

Llave de idempotencia opcional del lote (1 a 255 caracteres de A-Za-z0-9_-), única por organización. Si repites el lote con la misma llave y el mismo cuerpo, recibes los enlaces que ya se crearon —replayed— sin crearlos ni cobrarlos otra vez, y lo que no se creó la primera vez se vuelve a intentar. Con otro cuerpo, 422 IDEMPOTENCY_KEY_REUSED. Es independiente de las llaves del alta de un enlace. Ver la guía de idempotencia.

Cuerpo de la petición

Los enlaces a crear, de 1 a 1.000. La posición de cada uno es su index en la respuesta.

POST https://developers.hablame.co/api/v6/urlshortener/links/batch

Respuesta

Todavía no has enviado ninguna petición.