Saltar al contenido principal

Menú de comandos

Ve a una página o busca en el catálogo

API

Documentación de la API

Referencia completa de la API para desarrolladores de Getly v1

Autenticación

Todas las solicitudes a la API deben incluir tu clave de API en el encabezado Authorization con el esquema de token Bearer.

HTTP header
Authorization: Bearer gk_your_api_key_here

Alcances disponibles

Las claves de API están asociadas a una tienda concreta y tienen permisos detallados. Crea claves en /dashboard/developer/keys.

read:productswrite:productsread:ordersread:storewrite:storeread:analyticswebhooks:manageread:postswrite:postsread:couponswrite:couponsread:licenseswrite:licensescheckout:createread:billingwrite:billing

Límites de uso

Las solicitudes a la API tienen un límite de 100 requests per minute por clave de API. Si lo superas, recibirás una respuesta 429: espera un momento y vuelve a intentarlo.

Planifica tus integraciones para mantenerte dentro de estos límites. Agrupa las operaciones cuando puedas y guarda las respuestas en caché por tu lado.

Gestión de errores

Todas las respuestas de la API siguen un formato coherente. Los errores incluyen un mensaje descriptivo.

application/json
// Success
{ "success": true, "data": { ... } }

// Error
{
  "success": false,
  "error": "Description of what went wrong",
  "errorDetail": {
    "code": "validation_failed",   // stable, safe to branch on
    "message": "price must be a positive integer in cents",
    "hint": "Fix the field named in `param` and retry the same request.",
    "param": "price",              // omitted when no single field is at fault
    "docsUrl": "https://www.getly.store/developers/docs#errors"
  }
}

Códigos de estado HTTP

200 - Correcto

201 - Creado

400 - Solicitud incorrecta (datos no válidos)

401 - No autorizado (clave de API ausente o no válida)

403 - Prohibido (falta el alcance o el recurso no es tuyo)

404 - No encontrado

500 - Error interno del servidor

Endpoints

URL base: https://www.getly.store. Todos los precios están en centavos (p. ej., 1999 = $19.99).

GET/api/v1/productsread:products

Lista los productos de tu tienda

bash
curl -X GET "https://www.getly.store/api/v1/products?page=1&limit=20" \
  -H "Authorization: Bearer gk_your_api_key"
Respuesta · application/json
{
  "success": true,
  "data": [
    {
      "id": "uuid",
      "name": "Premium Icon Pack",
      "slug": "premium-icon-pack-abc123",
      "price": 1999,
      "status": "active",
      "category": { "id": "uuid", "name": "Design", "slug": "design" },
      "images": [{ "url": "...", "altText": "..." }]
    }
  ],
  "total": 42,
  "page": 1,
  "limit": 20,
  "hasMore": true
}
POST/api/v1/productswrite:products

Crea un producto nuevo en tu tienda

bash
curl -X POST "https://www.getly.store/api/v1/products" \
  -H "Authorization: Bearer gk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My New Product",
    "description": "A great digital product",
    "price": 29.99,
    "categoryId": "uuid",
    "status": "active",
    "tags": ["design", "icons"],
    "images": [{ "url": "https://cdn.getly.store/...png", "altText": "cover" }],
    "files": [{ "fileUrl": "https://cdn.getly.store/files/.../abc.zip", "fileName": "pack.zip", "fileSize": 10485760, "fileType": "application/zip" }]
  }'
Respuesta · application/json
{
  "success": true,
  "data": {
    "id": "uuid",
    "name": "My New Product",
    "slug": "my-new-product-abc123",
    "price": 2999,
    "status": "active",
    "createdAt": "2025-01-15T10:30:00Z"
  }
}
GET/api/v1/products/:idread:products

Obtén los detalles de un producto por ID

bash
curl -X GET "https://www.getly.store/api/v1/products/{id}" \
  -H "Authorization: Bearer gk_your_api_key"
Respuesta · application/json
{
  "success": true,
  "data": {
    "id": "uuid",
    "name": "Premium Icon Pack",
    "price": 1999,
    "images": [...],
    "files": [...],
    "reviews": [...]
  }
}
PATCH/api/v1/products/:idwrite:products

Actualiza un producto existente

bash
curl -X PATCH "https://www.getly.store/api/v1/products/{id}" \
  -H "Authorization: Bearer gk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Updated Name", "price": 39.99 }'
Respuesta · application/json
{
  "success": true,
  "data": { "id": "uuid", "name": "Updated Name", "price": 3999 }
}
DELETE/api/v1/products/:idwrite:products

Archiva (borrado lógico) un producto. Deja de aparecer públicamente; los pedidos y las descargas existentes siguen funcionando.

bash
curl -X DELETE "https://www.getly.store/api/v1/products/{id}" \
  -H "Authorization: Bearer gk_your_api_key"
Respuesta · application/json
{
  "success": true,
  "data": { "id": "uuid", "status": "archived" },
  "message": "Product archived"
}
POST/api/v1/products/:id/fileswrite:products

Adjunta un archivo descargable a un producto. Usa multipart para archivos pequeños, o la subruta presign + un PUT directo a R2 para archivos de hasta 2 GB. También puedes pasar un array files[] a POST /api/v1/products para adjuntarlos al crear el producto.

bash
# Direct upload (multipart) - best for files under ~4MB:
curl -X POST "https://www.getly.store/api/v1/products/{id}/files" \
  -H "Authorization: Bearer gk_your_api_key" \
  -F "file=@/path/to/your-file.zip"

# Large files (up to 2GB) - 3 steps:
# 1) get a presigned upload URL
curl -X POST "https://www.getly.store/api/v1/products/{id}/files/presign" \
  -H "Authorization: Bearer gk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "fileName": "pack.zip", "fileSize": 524288000, "fileType": "application/zip" }'
# 2) PUT the bytes straight to R2 (use the returned uploadUrl)
curl -X PUT "<uploadUrl>" --data-binary "@/path/to/pack.zip" \
  -H "Content-Length: 524288000"
# 3) attach the uploaded object (use the returned fileUrl)
curl -X POST "https://www.getly.store/api/v1/products/{id}/files" \
  -H "Authorization: Bearer gk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "fileUrl": "<fileUrl>", "fileName": "pack.zip", "fileSize": 524288000, "fileType": "application/zip" }'
Respuesta · application/json
{
  "success": true,
  "data": {
    "id": "uuid",
    "fileName": "pack.zip",
    "fileUrl": "https://cdn.getly.store/files/.../abc.zip",
    "fileSize": 524288000,
    "fileType": "application/zip",
    "version": "1.0",
    "isLatest": true,
    "createdAt": "2026-06-02T10:30:00Z"
  }
}
POST/api/v1/uploads/images/presignwrite:products

Obtén una URL prefirmada para subir la imagen de un producto (máx. 10 MB; png, jpeg, webp, gif, avif). Obligatoria antes de que un producto pueda publicarse.

bash
# Images are uploaded in 3 steps - there is no direct multipart route.
# 1) ask for a presigned URL (max 10MB; png, jpeg, webp, gif or avif)
curl -X POST "https://www.getly.store/api/v1/uploads/images/presign" \
  -H "Authorization: Bearer gk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "fileName": "cover.png", "fileSize": 184320, "contentType": "image/png" }'

# 2) PUT the raw bytes to the returned uploadUrl (expires in 1h) with the
#    returned uploadHeaders. Content-Length MUST equal the fileSize you declared.
#    Send Content-Type equal to the declared type (curl --data-binary alone sends
#    a form type; Getly corrects it when the image is attached, but send it anyway).
curl -X PUT "<uploadUrl>" --data-binary "@/path/to/cover.png" \
  -H "Content-Type: image/png" -H "Content-Length: 184320"

# 3) reference the returned publicUrl when you create or update the product.
#    An image is REQUIRED before a product can go live.
curl -X PATCH "https://www.getly.store/api/v1/products/{id}" \
  -H "Authorization: Bearer gk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "images": ["<publicUrl>"] }'
Respuesta · application/json
{
  "success": true,
  "data": {
    "uploadUrl": "https://<bucket>.r2.cloudflarestorage.com/...",
    "uploadHeaders": { "Content-Type": "image/png" },
    "publicUrl": "https://cdn.getly.store/images/.../abc.png",
    "expiresIn": 3600
  }
}
GET/api/v1/products/:id/keysread:products

Lista el pool de claves de licencia de un producto: contadores (disponibles/emitidas/en espera) y una lista paginada y enmascarada. La clave en texto plano nunca se devuelve.

bash
curl -X GET "https://www.getly.store/api/v1/products/{id}/keys?limit=50&offset=0" \
  -H "Authorization: Bearer gk_your_api_key"
Respuesta · application/json
{
  "success": true,
  "data": {
    "keyPoolEnabled": true,
    "keyPoolLowThreshold": 5,
    "counts": { "available": 12, "issued": 40, "waiting": 0 },
    "keys": [
      { "id": "uuid", "masked": "ABCD…WXYZ", "status": "available", "issuedAt": null, "orderItemId": null, "refunded": false }
    ],
    "limit": 50,
    "offset": 0,
    "total": 52
  }
}
POST/api/v1/products/:id/keyswrite:products

Pega tus propias claves, vales o URL únicas en el pool de un producto, una por elemento del array. Los duplicados y los vacíos se informan, no se descartan en silencio; los compradores que estaban esperando reciben una clave de inmediato.

bash
curl -X POST "https://www.getly.store/api/v1/products/{id}/keys" \
  -H "Authorization: Bearer gk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "keys": ["ABCD-1234-EFGH-5678", "IJKL-9012-MNOP-3456"] }'
Respuesta · application/json
{
  "success": true,
  "data": {
    "added": 2,
    "duplicates": 0,
    "duplicatesInInput": 0,
    "tooLong": 0,
    "blank": 0,
    "filled": 1
  }
}
DELETE/api/v1/products/:id/keys/:keyIdwrite:products

Elimina una clave sin vender del pool. Una clave emitida es un registro de venta y no se puede eliminar: 409 key_not_available.

bash
curl -X DELETE "https://www.getly.store/api/v1/products/{id}/keys/{keyId}" \
  -H "Authorization: Bearer gk_your_api_key"
Respuesta · application/json
{
  "success": true,
  "data": { "id": "uuid", "removed": true }
}
GET/api/v1/ordersread:orders

Lista los pedidos que incluyen artículos de tu tienda

bash
curl -X GET "https://www.getly.store/api/v1/orders?page=1&limit=20" \
  -H "Authorization: Bearer gk_your_api_key"
Respuesta · application/json
{
  "success": true,
  "data": [
    {
      "id": "uuid",
      "orderId": "uuid",
      "price": 2999,
      "order": { "status": "completed", "buyer": { "name": "John" } },
      "product": { "name": "Premium Pack" }
    }
  ],
  "total": 156,
  "page": 1
}
GET/api/v1/orders/:idread:orders

Obtén los detalles de un pedido (solo los artículos de tu tienda)

bash
curl -X GET "https://www.getly.store/api/v1/orders/{id}" \
  -H "Authorization: Bearer gk_your_api_key"
Respuesta · application/json
{
  "success": true,
  "data": {
    "id": "uuid",
    "status": "completed",
    "total": 5999,
    "buyer": { "name": "John", "email": "[email protected]" },
    "items": [...]
  }
}
GET/api/v1/storeread:store

Obtén la información de tu tienda

bash
curl -X GET "https://www.getly.store/api/v1/store" \
  -H "Authorization: Bearer gk_your_api_key"
Respuesta · application/json
{
  "success": true,
  "data": {
    "id": "uuid",
    "name": "My Store",
    "slug": "my-store",
    "description": "...",
    "totalSales": 250,
    "totalRevenue": 450000,
    "badges": [...]
  }
}
PATCH/api/v1/storewrite:store

Actualiza el nombre de la tienda, la descripción, el sitio web y socialLinks

bash
curl -X PATCH "https://www.getly.store/api/v1/store" \
  -H "Authorization: Bearer gk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "description": "Updated store description" }'
Respuesta · application/json
{
  "success": true,
  "data": { "id": "uuid", "name": "My Store", "description": "Updated store description" }
}
GET/api/v1/analyticsread:analytics

Obtén las analíticas de ventas de tu tienda

bash
curl -X GET "https://www.getly.store/api/v1/analytics" \
  -H "Authorization: Bearer gk_your_api_key"
Respuesta · application/json
{
  "success": true,
  "data": {
    "totalSales": 250,
    "totalRevenue": 450000,
    "monthlySales": 42,
    "monthlyRevenue": 75000,
    "averageOrderValue": 1800,
    "productCount": 15,
    "totalDownloads": 1200,
    "salesByMonth": [
      { "month": "2025-01", "sales": 38, "revenue": 68000 }
    ]
  }
}
GET/api/v1/webhook-endpointswebhooks:manage

Lista los endpoints de webhook de tu tienda

bash
curl -X GET "https://www.getly.store/api/v1/webhook-endpoints" \
  -H "Authorization: Bearer gk_your_api_key"
Respuesta · application/json
{
  "success": true,
  "data": {
    "items": [
      {
        "id": "uuid",
        "url": "https://example.com/webhooks",
        "events": ["sale.completed"],
        "isActive": true
      }
    ],
    "nextCursor": null
  }
}
POST/api/v1/webhook-endpointswebhooks:manage

Registra un nuevo endpoint de webhook

bash
curl -X POST "https://www.getly.store/api/v1/webhook-endpoints" \
  -H "Authorization: Bearer gk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/webhooks",
    "events": ["sale.completed", "product.updated"]
  }'
Respuesta · application/json
{
  "success": true,
  "data": {
    "id": "uuid",
    "url": "https://example.com/webhooks",
    "events": ["sale.completed", "product.updated"],
    "secret": "abcdef1234567890..."
  }
}
POST/api/v1/postswrite:posts

Crea una entrada del blog de creador a partir de Markdown. Pon crosspostMuhamor en true para mostrarla también en la comunidad Getly Creators de Muhamor: la copia enlaza a tu entrada como original, y una entrada solo para suscriptores se publica allí únicamente como adelanto.

bash
curl -X POST "https://www.getly.store/api/v1/posts" \
  -H "Authorization: Bearer gk_your_api_key" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7b1f0c2e-post-1" \
  -d '{
    "title": "How I made my icon pack",
    "contentMarkdown": "## The idea\n\nIt started with...",
    "status": "published",
    "crosspostMuhamor": true
  }'
Respuesta · application/json
{
  "success": true,
  "data": {
    "id": "uuid",
    "title": "How I made my icon pack",
    "slug": "how-i-made-my-icon-pack",
    "status": "published",
    "crosspostMuhamor": true
  }
}
GET/api/v1/public/products/{slug}public

Público, sin clave de API: la ficha de un producto activo por su slug (nombre, precio en centavos con cualquier oferta vigente, imagen de portada, tienda). 404 para todo lo que no esté a la venta. 60 solicitudes por minuto por IP.

bash
curl "https://www.getly.store/api/v1/public/products/premium-icon-pack-abc123"
Respuesta · application/json
{
  "success": true,
  "data": {
    "slug": "premium-icon-pack-abc123",
    "name": "Premium Icon Pack",
    "shortDescription": "120 line icons",
    "priceCents": 1999,
    "currency": "USD",
    "avgRating": 4.8,
    "reviewCount": 12,
    "imageUrl": "https://cdn.getly.store/images/.../cover.webp",
    "store": { "name": "Pixel Studio", "slug": "pixel-studio" },
    "urls": { "product": "https://www.getly.store/product/premium-icon-pack-abc123" }
  }
}
POST/api/v1/billing/planswrite:billing

Crea un plan recurrente para tu PROPIO producto (Getly Billing). amount en centavos enteros (mín. 50), intervalUnit day/week/month/year, intervalCount 1–52. Requiere una solicitud de Billing aprobada: 403 billing_not_approved hasta entonces. GET lista los planes; GET/PATCH /{id} lee y edita uno.

bash
curl -X POST "https://www.getly.store/api/v1/billing/plans" \
  -H "Authorization: Bearer gk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Pro", "amount": 1900, "intervalUnit": "month", "externalId": "pro-monthly" }'
Respuesta · application/json
{
  "success": true,
  "data": {
    "id": "uuid",
    "name": "Pro",
    "amount": 1900,
    "currency": "usd",
    "interval": { "unit": "month", "count": 1 },
    "externalId": "pro-monthly",
    "isActive": true
  }
}
POST/api/v1/billing/checkoutwrite:billing

Genera una página de suscripción alojada para un cliente, válida 24 horas. customerRef es tu propio id del cliente y vuelve en cada webhook billing.* como externalCustomerRef. El cliente paga con tarjeta (se renueva solo) o con cripto (un periodo cada vez).

bash
curl -X POST "https://www.getly.store/api/v1/billing/checkout" \
  -H "Authorization: Bearer gk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "planId": "uuid", "customerRef": "user_8841",
        "successUrl": "https://your-app.com/welcome",
        "cancelUrl": "https://your-app.com/pricing" }'
Respuesta · application/json
{
  "success": true,
  "data": {
    "url": "https://www.getly.store/billing/subscribe/uuid?t=…",
    "expiresAt": "2026-09-09T09:00:00.000Z"
  }
}
GET/api/v1/billing/subscriptions/{id}read:billing

La comprobación de estado que hace tu backend antes de dar acceso. status: active, past_due (falló la renovación con tarjeta, el procesador reintenta), canceled, expired (se acabó el periodo pagado con cripto). Trata active y past_due como con derecho de acceso hasta currentPeriodEnd. El endpoint de lista filtra por status, customerRef y planId.

bash
curl "https://www.getly.store/api/v1/billing/subscriptions/uuid" \
  -H "Authorization: Bearer gk_your_api_key"
Respuesta · application/json
{
  "success": true,
  "data": {
    "id": "uuid",
    "customerRef": "user_8841",
    "status": "active",
    "paymentMethod": "stripe",
    "currentPeriodEnd": "2026-10-08T09:14:00.000Z",
    "cancelAtPeriodEnd": false,
    "plan": { "name": "Pro", "amount": 1900, "interval": { "unit": "month", "count": 1 } }
  }
}
POST/api/v1/billing/subscriptions/{id}/cancelwrite:billing

Detiene la renovación al final del periodo pagado, nunca un corte inmediato. Recibes billing.subscription.canceled cuando termina (tarjeta) o billing.subscription.expired (cripto). 409 subscription_not_cancellable si ya terminó.

bash
curl -X POST "https://www.getly.store/api/v1/billing/subscriptions/uuid/cancel" \
  -H "Authorization: Bearer gk_your_api_key"
Respuesta · application/json
{
  "success": true,
  "data": { "id": "uuid", "status": "active", "cancelAtPeriodEnd": true, "currentPeriodEnd": "2026-10-08T09:14:00.000Z" }
}

Getly Billing

Planes recurrentes para un producto que gestionas tú: un SaaS, una comunidad, una herramienta. Los planes viven en la API, la página de suscripción vive en getly.store, y tu backend da acceso a partir de cinco webhooks que llevan todos tu propia referencia de cliente.

El acceso es por solicitud: cuéntanos el sitio web y qué vendes en /dashboard/billing. Hasta la aprobación, las llamadas de escritura responden 403 billing_not_approved y las de lectura funcionan.

  • billing.subscription.created
  • billing.subscription.renewed
  • billing.payment_failed
  • billing.subscription.canceled
  • billing.subscription.expired
Cómo funciona Getly Billing

Entrega tus propias claves de licencia

Un producto puede entregar las claves que tú ya generaste (claves de registro, códigos de vale o URL únicas) en lugar de una que genera Getly. Getly entrega la siguiente clave en cada venta, la primera pegada es la primera vendida, y nunca bloquea una venta por un pool vacío: se avisa al comprador por correo de que su clave va en camino y la recibe en cuanto se añaden más.

  • Panel: edición del producto → paso Precio → "Entregar mis propias claves de licencia" (el pool necesita el id del producto, por eso no se ofrece al crearlo). Una clave por línea, hasta 5,000 por cada adición; no se puede combinar con las claves generadas por Getly en el mismo producto.
  • API: GET/POST /api/v1/products/{id}/keys lista y añade claves; DELETE /api/v1/products/{id}/keys/{keyId} elimina una sin vender. keyPoolEnabled y keyPoolLowThreshold viven en el propio producto, y se establecen con POST/PATCH /api/v1/products.

¿Prefieres usar tu propio backend? Cada elemento de sale.completed ahora lleva licenseKey (la clave ya emitida para ese elemento, del pool o generada por Getly, o null mientras sigue en espera) junto con buyerEmail, así puedes reenviarla o enviar la tuya.

Webhooks

Los webhooks permiten que tu aplicación reciba avisos en tiempo real cuando ocurren eventos en tu tienda. Registra endpoints en /dashboard/developer/webhooks o mediante la API.

Tipos de evento

sale.completed - Se completó una venta de uno de tus productos. Incluye el email del comprador, para que puedas enviar tu propia clave de licencia.

product.created - Se creó un producto en tu tienda

product.updated - Se actualizó un producto de tu tienda

review.created - Se dejó una nueva reseña en uno de tus productos

download.completed - Un comprador descargó uno de tus productos

refund.created - Un comprador solicitó un reembolso (la decisión llega después como order.refunded)

order.refunded - Se registró un reembolso en uno de tus pedidos

dispute.created - Un comprador abrió una disputa

dispute.resolved - Se resolvió una disputa

checkout_link.completed - Se pagó un enlace de pago

license.activated - Se activó una clave de licencia

access.expiring - Una compra con acceso por tiempo caduca en 7 días

access.expired - Una compra con acceso por tiempo caducó

billing.subscription.created - Getly Billing: un cliente se suscribió a uno de tus planes

billing.subscription.renewed - Getly Billing: una suscripción se renovó y se pagó

billing.payment_failed - Getly Billing: falló el pago de una renovación

billing.subscription.canceled - Getly Billing: se canceló una suscripción

billing.subscription.expired - Getly Billing: una suscripción pagada con cripto caducó sin pagar

* - Suscribirse a todos los eventos

Formato del payload

Cada envío de webhook manda una solicitud POST con JSON con la siguiente estructura:

POST · application/json
POST https://your-endpoint.com/webhooks
Content-Type: application/json
X-Getly-Signature: sha256=<hmac_hex>
X-Getly-Event: sale.completed

{
  "deliveryId": "uuid",
  "event": "sale.completed",
  "data": {
    "orderId": "uuid",
    "buyerId": "uuid",
    "buyerEmail": "[email protected]",
    "items": [
      {
        "orderItemId": "uuid",
        "productId": "uuid",
        "price": 2999,
        "sellerAmount": 2399,
        "isGift": false,
        "licenseKey": null
      }
    ],
    "total": 2999
  },
  "timestamp": "2026-09-23T10:30:00.000Z"
}

Verificación de la firma

Cada envío de webhook incluye un encabezado X-Getly-Signature. Verifica la firma con HMAC-SHA256 y el secreto de tu webhook para asegurarte de que la solicitud viene de Getly.

node.js
const crypto = require('crypto');

function verifyWebhook(body, signature, secret) {
  const expected = 'sha256=' +
    crypto
      .createHmac('sha256', secret)
      .update(body)
      .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// In your webhook handler
app.post('/webhooks', (req, res) => {
  const signature = req.headers['x-getly-signature'];
  const isValid = verifyWebhook(
    JSON.stringify(req.body),
    signature,
    process.env.GETLY_WEBHOOK_SECRET
  );

  if (!isValid) {
    return res.status(401).send('Invalid signature');
  }

  const { event, data } = req.body;
  // Handle the event...

  res.status(200).send('OK');
});

Política de reintentos

Los envíos fallidos (respuesta distinta de 2xx o tiempo agotado) se reintentan automáticamente con retroceso exponencial:

Intento 1: Reintento al cabo de 1 minuto

Intento 2: Reintento al cabo de 5 minutos

Intento 3: Reintento al cabo de 30 minutos

Intento 4: Reintento al cabo de 2 horas

Intento 5: Se abandona (el envío se marca como fallido)

Tu endpoint debe responder en un plazo de 10 segundos. Devuelve un código 2xx para confirmar la recepción.