Saltar al contenido principal

Documentation Index

Fetch the complete documentation index at: https://docs.dodopayments.com/llms.txt

Use this file to discover all available pages before exploring further.

Eventos de Webhook para Concesión de Derechos

Estos eventos se activan cada vez que cambia el estado de la concesión de derechos de un cliente, por ejemplo, cuando se genera una clave de licencia, se asigna un rol de Discord, se proporciona un enlace de descarga, o se revoca el acceso. Suscríbase a estos eventos para mantener su aplicación sincronizada con lo que cada cliente puede acceder.
EventoDescripción
entitlement_grant.createdSe creó una nueva fila de concesión. El estado es delivered inmediatamente para claves de licencia, e pending para todas las demás integraciones.
entitlement_grant.deliveredLa concesión pasa a estar entregada. El cliente ahora tiene acceso a la plataforma, archivo o clave de licencia atribuidos.
entitlement_grant.failedLa entrega falló y no se está reintentando. Inspeccione error_code y error_message.
entitlement_grant.revokedSe retiró el acceso. Inspeccione revocation_reason para entender por qué.
Los cuatro eventos comparten la misma carga útil EntitlementGrantResponse documentada en el esquema a continuación.

Desencadenantes de Eventos

entitlement_grant.created

Se acaba de insertar una fila de concesión. La concesión siempre tiene un id estable desde este punto en adelante, incluso si su estado cambia. Use este evento para registrar que el cumplimiento está en progreso. Para claves de licencia la fila se inserta directamente con status: "delivered" y delivered_at poblados, de modo que un solo evento created es seguido por ningún cambio de estado adicional, a menos que la concesión sea revocada más tarde. Para todas las demás integraciones la fila llega con status: "pending". Un evento delivered o failed sigue una vez finalizada la entrega:
  • Integraciones basadas en OAuth (Discord, GitHub, Notion) incluyen un oauth_url que el cliente debe visitar para completar el consentimiento. La concesión permanece pending hasta que el cliente autorice.
  • Integraciones directas de plataforma (Telegram, Framer, Archivos Digitales) permanecen pending solo brevemente mientras se ejecuta la llamada de plataforma, luego pasan a delivered.

entitlement_grant.delivered

La concesión pasó de pending a delivered. El cliente ahora tiene el acceso descrito por el derecho. Use este evento para desbloquear funciones dependientes en sus propios sistemas, por ejemplo, para proporcionar un espacio de trabajo, enviar un correo electrónico de bienvenida personalizado o marcar una bandera de “cumplido”. El campo delivered_at de la carga útil captura cuándo se completó la entrega. Para las concesiones que llegaron delivered al momento de la creación, recibirá eventos created e delivered de manera consecutiva.

entitlement_grant.failed

Se intentó la entrega y falló con un error no recuperable. Los campos error_code e error_message explican la falla. Las causas comunes incluyen un token OAuth revocado, un permiso de plataforma denegado, o un destino faltante (por ejemplo, una guild de Discord eliminada).
Trate entitlement_grant.failed como accionable. El cliente pagó pero no obtuvo acceso. Haga visibles las fallas a su equipo de soporte o inicie una nueva concesión una vez que se resuelva el problema subyacente.

entitlement_grant.revoked

Se retiró el acceso a nivel de plataforma: se eliminó el rol de Discord, se eliminó el colaborador de GitHub, se desactivó la clave de licencia, las URL de descarga de archivos ya no se emiten. El campo revocation_reason registra el desencadenante.
revocation_reasonDesencadenante
subscription_cancelledSe canceló la suscripción del cliente (evento subscription.cancelled).
subscription_on_holdLa suscripción está en espera debido a la falla en la renovación (subscription.on_hold). Recuperable: un reintento exitoso produce una nueva concesión.
subscription_expiredLa suscripción alcanzó el final de su término (subscription.expired).
plan_changedEl plan cambió; las concesiones antiguas se revocan antes de emitir nuevas (subscription.plan_changed).
refundSe procesó un reembolso para el pago único original (refund.succeeded).
manualUn comerciante revocó la concesión a través de la API o el panel de control. Las revocaciones manuales no se otorgan nuevamente automáticamente en la renovación de la suscripción.
license_key_disabledLa clave de licencia detrás de una concesión de clave de licencia fue deshabilitada. La concesión se re-activa automáticamente si la clave es re-habilitada.
platform_externalEl lado de la plataforma de una integración se desincronizó (por ejemplo, se eliminó un rol de Discord manualmente, la App de GitHub perdió acceso al repositorio, o un pase de reconciliación detectó un objetivo faltante). La concesión no se otorga automáticamente en la renovación de la suscripción hasta que se solucione el problema subyacente de la plataforma.

Variantes de Carga Útil

El campo data siempre es un objeto EntitlementGrantResponse. Dos tipos de integraciones incluyen objetos anidados adicionales:
  • license_key se incluye cuando el tipo de integración de derechos es license_key. Contiene la clave generada, la expiración y el uso de activación.
  • digital_product_delivery se incluye cuando el tipo de integración es digital_files. Contiene URLs de descarga prefirmadas, el opcional instructions, y el opcional external_url.
Para todos los demás tipos de integraciones (Discord, GitHub, Telegram, Framer, Notion) ambos campos son null; la configuración relevante se captura en el propio derecho, no en la concesión.

Ejemplos de Carga Útil

Clave de licencia entregada (entitlement_grant.delivered)

{
  "business_id": "bus_H4ekzPSlcg",
  "type": "entitlement_grant.delivered",
  "timestamp": "2026-05-01T10:25:33.000000Z",
  "data": {
    "id": "grant_8VbC6JDZzPEqfBPUdpj0K",
    "business_id": "bus_H4ekzPSlcg",
    "entitlement_id": "ent_9xY2bKwQn5MjRpL8d",
    "customer_id": "cus_abc123",
    "external_id": "lk_AAA111BBB222",
    "payment_id": "pay_a1b2c3d4",
    "subscription_id": null,
    "status": "delivered",
    "license_key": {
      "key": "PRO-AAAA-BBBB-CCCC-DDDD",
      "expires_at": "2027-05-01T00:00:00Z",
      "activations_used": 0,
      "activations_limit": 5
    },
    "digital_product_delivery": null,
    "delivered_at": "2026-05-01T10:25:33Z",
    "revoked_at": null,
    "revocation_reason": null,
    "error_code": null,
    "error_message": null,
    "oauth_url": null,
    "oauth_expires_at": null,
    "metadata": null,
    "created_at": "2026-05-01T10:25:33Z",
    "updated_at": "2026-05-01T10:25:33Z"
  }
}

Archivos digitales entregados (entitlement_grant.delivered)

{
  "business_id": "bus_H4ekzPSlcg",
  "type": "entitlement_grant.delivered",
  "timestamp": "2026-05-01T10:30:12.000000Z",
  "data": {
    "id": "grant_2P9rQwYvMxTnKoCb4",
    "business_id": "bus_H4ekzPSlcg",
    "entitlement_id": "ent_files_J3kLmN4oP5",
    "customer_id": "cus_abc123",
    "external_id": "pay_a1b2c3d4",
    "payment_id": "pay_a1b2c3d4",
    "subscription_id": null,
    "status": "delivered",
    "license_key": null,
    "digital_product_delivery": {
      "files": [
        {
          "file_id": "df_a4f6c1de",
          "download_url": "https://files.dodopayments.com/.../pro-bundle.zip?Signature=...",
          "filename": "pro-bundle.zip",
          "content_type": "application/zip",
          "file_size": 18742390,
          "expires_in": 900
        }
      ],
      "instructions": "Unzip and run setup.sh from the project root.",
      "external_url": null
    },
    "delivered_at": "2026-05-01T10:30:12Z",
    "revoked_at": null,
    "revocation_reason": null,
    "error_code": null,
    "error_message": null,
    "oauth_url": null,
    "oauth_expires_at": null,
    "metadata": null,
    "created_at": "2026-05-01T10:30:12Z",
    "updated_at": "2026-05-01T10:30:12Z"
  }
}

Rol de Discord creado y pendiente (entitlement_grant.created)

{
  "business_id": "bus_H4ekzPSlcg",
  "type": "entitlement_grant.created",
  "timestamp": "2026-05-01T10:31:00.000000Z",
  "data": {
    "id": "grant_DiscordPending5L",
    "business_id": "bus_H4ekzPSlcg",
    "entitlement_id": "ent_discord_patrons",
    "customer_id": "cus_abc123",
    "external_id": "sub_pro_monthly_001",
    "payment_id": null,
    "subscription_id": "sub_pro_monthly_001",
    "status": "pending",
    "license_key": null,
    "digital_product_delivery": null,
    "delivered_at": null,
    "revoked_at": null,
    "revocation_reason": null,
    "error_code": null,
    "error_message": null,
    "oauth_url": "https://discord.com/oauth2/authorize?...",
    "oauth_expires_at": "2026-05-08T10:31:00Z",
    "metadata": null,
    "created_at": "2026-05-01T10:31:00Z",
    "updated_at": "2026-05-01T10:31:00Z"
  }
}

Concesión revocada por cancelación de suscripción (entitlement_grant.revoked)

{
  "business_id": "bus_H4ekzPSlcg",
  "type": "entitlement_grant.revoked",
  "timestamp": "2026-06-15T08:12:44.000000Z",
  "data": {
    "id": "grant_8VbC6JDZzPEqfBPUdpj0K",
    "business_id": "bus_H4ekzPSlcg",
    "entitlement_id": "ent_9xY2bKwQn5MjRpL8d",
    "customer_id": "cus_abc123",
    "external_id": "sub_pro_monthly_001",
    "payment_id": null,
    "subscription_id": "sub_pro_monthly_001",
    "status": "revoked",
    "revocation_reason": "subscription_cancelled",
    "license_key": {
      "key": "PRO-AAAA-BBBB-CCCC-DDDD",
      "expires_at": null,
      "activations_used": 1,
      "activations_limit": 5
    },
    "digital_product_delivery": null,
    "delivered_at": "2026-05-01T10:25:33Z",
    "revoked_at": "2026-06-15T08:12:44Z",
    "error_code": null,
    "error_message": null,
    "oauth_url": null,
    "oauth_expires_at": null,
    "metadata": null,
    "created_at": "2026-05-01T10:25:33Z",
    "updated_at": "2026-06-15T08:12:44Z"
  }
}

Entrega fallida (entitlement_grant.failed)

{
  "business_id": "bus_H4ekzPSlcg",
  "type": "entitlement_grant.failed",
  "timestamp": "2026-05-01T10:36:21.000000Z",
  "data": {
    "id": "grant_GhFailed7Z",
    "business_id": "bus_H4ekzPSlcg",
    "entitlement_id": "ent_github_repo",
    "customer_id": "cus_abc123",
    "external_id": "pay_a1b2c3d4",
    "payment_id": "pay_a1b2c3d4",
    "subscription_id": null,
    "status": "failed",
    "license_key": null,
    "digital_product_delivery": null,
    "delivered_at": null,
    "revoked_at": null,
    "revocation_reason": null,
    "error_code": "github_permission_denied",
    "error_message": "Repository access could not be granted: the GitHub App installation no longer has permission on this repository.",
    "oauth_url": null,
    "oauth_expires_at": null,
    "metadata": null,
    "created_at": "2026-05-01T10:36:00Z",
    "updated_at": "2026-05-01T10:36:21Z"
  }
}

Consejos de Integración

  • Espere entitlement_grant.delivered antes de desbloquear funciones dependientes. Un evento payment.succeeded le indica que el dinero se transfirió; no le indica que el cliente ya tiene el repositorio de GitHub o el rol de Discord. El evento delivered es la fuente de verdad para el cumplimiento.
  • Mapee revocation_reason a flujos de retención. Una revocación subscription_on_hold generalmente significa que la tarjeta del cliente falló y la próxima renovación re-otorgará el acceso. Una revocación manual o subscription_cancelled es intencional. Trátelos de manera diferente en la mensajería al cliente.
  • Utilice la concesión id como su clave de idempotencia. Una sola concesión emite como máximo un evento created y como máximo un evento terminal (delivered o failed), y como máximo un evento revoked. Las re-entregas del sistema de webhook pueden repetir eventos; dedupe en la concesión id más type.
  • Inspeccione license_key e digital_product_delivery para reconocer el tipo de integración. La carga útil de la concesión en sí no lleva el tipo de integración, pero exactamente uno de estos objetos anidados se completa para derechos de clave de licencia y archivos digitales.
  • Para concesiones basadas en OAuth, haga visible oauth_url al cliente. El evento entitlement_grant.created para flujos de suscripción de Discord, GitHub, o Notion incluye un oauth_url e oauth_expires_at. Envíelo por correo electrónico al cliente o muéstrelo en su aplicación para desbloquear la entrega.

Detailed view of a single entitlement grant: who it's for, its lifecycle state, and any integration-specific delivery payload.

business_id
string
requerido

Identifier of the business that owns the grant.

created_at
string<date-time>
requerido

Timestamp when the grant was created.

customer_id
string
requerido

Identifier of the customer the grant was issued to.

entitlement_id
string
requerido

Identifier of the entitlement this grant was issued from.

id
string
requerido

Unique identifier of the grant.

metadata
object
requerido

Arbitrary key-value metadata recorded on the grant.

status
enum<string>
requerido

Lifecycle status of the grant.

Opciones disponibles:
Pending,
Delivered,
Failed,
Revoked
updated_at
string<date-time>
requerido

Timestamp when the grant was last modified.

delivered_at
string<date-time> | null

Timestamp when the grant transitioned to delivered, when applicable.

digital_product_delivery
Digital Product Delivery · object

Digital-product-delivery payload, present when the entitlement integration is digital_files.

error_code
string | null

Machine-readable code reported when delivery failed, when applicable.

error_message
string | null

Human-readable message reported when delivery failed, when applicable.

license_key
object

License-key delivery payload, present when the entitlement integration is license_key.

oauth_expires_at
string<date-time> | null

Timestamp when oauth_url stops being valid, when applicable.

oauth_url
string | null

Customer-facing OAuth URL for OAuth-style integrations. Populated during the customer-portal accept flow; null until the customer completes that step, and on grants for non-OAuth integrations.

payment_id
string | null

Identifier of the payment that triggered this grant, when applicable.

revocation_reason
string | null

Reason recorded when the grant was revoked, when applicable.

revoked_at
string<date-time> | null

Timestamp when the grant transitioned to revoked, when applicable.

subscription_id
string | null

Identifier of the subscription that triggered this grant, when applicable.

Last modified on May 14, 2026