Webhooks para pagos

Actualizaciones en tiempo real sobre tus transacciones.

Los webhooks para pagos (anteriormente, actualizaciones en tiempo real) son fundamentales para mantenerse al día sobre los cambios que se realizan en los pedidos efectuados en tu aplicación a través de los pagos de Facebook.

Información general

Los webhooks son un sistema basado en suscripciones entre Facebook y tu servidor. Tu aplicación se suscribe para recibir actualizaciones de Facebook mediante un extremo HTTPS específico. Cuando se actualiza un pedido realizado en tu aplicación, enviamos una solicitud POST en HTTPS a ese extremo en la que se notifica el cambio al servidor.

Existen tres casos principales en los que enviamos actualizaciones a tu servidor de desarrollador:

Suscribirse a los webhooks

Para suscribirte a los webhooks de los pagos, primero debes crear una dirección URL con extremo público que reciba GET en HTTPS para la verificación de la suscripción y POST para las solicitudes de cambio de datos. Más adelante, se describe la estructura de estos dos tipos de solicitudes. A continuación, configura las suscripciones al objeto payment de la aplicación. Existen dos formas de hacerlo:

En ambos casos, el extremo recibirá los mismos datos de la misma forma. Consulta Tu servidor de devolución de llamada para obtener más información acerca de lo que recibirá el servidor.

Suscribirse desde el panel de aplicaciones

La forma más sencilla de configurar la aplicación para que reciba actualizaciones de webhooks es usar la ventana de pagos del panel de aplicaciones. Busca la aplicación en el panel y haz clic en la pestaña Payments. La sección Webhooks estará justo debajo de la sección Configuración de la empresa.

Webhooks para pagos

En esta pantalla se indicará el estado de suscripción de la aplicación, ya se haya añadido mediante esta ventana o mediante la API. Desde aquí, puedes cambiar la dirección URL de devolución de llamada de la suscripción y probarla.

En el campo "Devolución de llamada" debes proporcionar un extremo de servidor al que se pueda acceder públicamente. Esta es la dirección que usaremos para verificar la suscripción y enviar las actualizaciones, y debe responder tal y como se describe en Tu servidor de devolución de llamada.

Por último, proporciona un "Identificador de verificación". Este identificador solo se enviará durante la fase de inscripción para verificar que la suscripción procede de una ubicación segura. No se enviará en las actualizaciones de webhook periódicas.

Probar la configuración

Prueba la configuración de devolución de llamada antes de guardar la suscripción. Esta acción enviará una solicitud GET de verificación al extremo con los parámetros hub.mode, hub.challenge y hub.verify_token, y se comprobará que se gestionan correctamente. Por ejemplo, debes asegurarte de que el extremo devuelve hub.challenge a Facebook:

Probar la configuración

Cuando hayas introducido los datos de la suscripción, asegúrate de hacer clic en el botón "Guardar cambios" en la parte inferior de la página. Editar una suscripción consiste simplemente en modificar el contenido de los campos, volver a probarlos y guardar el formulario de nuevo.

Suscribirse desde la API Graph

También se pueden configurar e incluir las suscripciones mediante programación en la API Graph. Necesitarás el valor access token de la aplicación, que está disponible en la herramienta de identificadores de acceso o mediante el extremo /oauth de la API Graph.

La API de suscripción está disponible en el extremo https://graph.facebook.com/[APP_ID]/subscriptions.

Esta API te permite llevar a cabo tres acciones:

  • Añadir o modificar una suscripción (enviando una solicitud POST en HTTPS).
  • Consultar todas las suscripciones existentes (enviando una solicitud GET en HTTPS).

Añadir y modificar suscripciones

Para configurar una suscripción, envía una solicitud POST con los parámetros siguientes. Ten en cuenta que estos parámetros corresponden a los campos del formulario que hemos descrito anteriormente:

  • object: como se ha descrito anteriormente, el tipo de objeto sobre el que quieres recibir actualizaciones. Especifica payments.
  • fields: lista separada por comas de las propiedades del tipo de objeto del que quieras recibir actualizaciones cuando se produzcan cambios. Especifica "actions" y "disputes".
  • callback_url: extremo de servidor válido y al que se pueda acceder públicamente.
  • verify_token: cadena arbitraria que se envía a tu extremo cuando se verifica la suscripción.

Cuando recibimos esta solicitud, igual que con la configuración del formulario anterior, enviamos una solicitud GET a tu devolución de llamada para asegurarnos de que es válida y de que está lista para recibir actualizaciones. En concreto, debes asegurarte de que el extremo devuelve hub.challenge a Facebook.

Ten en cuenta que, si ya existe una suscripción para este tipo de objeto, los datos recién publicados sustituirán los datos existentes, ya que una aplicación solo puede tener una suscripción para cada tipo de objeto.

Consultar las suscripciones

Si envías una solicitud GET en HTTPS a la API de suscripciones, esta devolverá contenido codificado en JSON con una lista de las suscripciones. Por ejemplo:

[
  {
    "object": "payments",
    "callback_url": "https://www.friendsmash.com/rtu.php",
    "fields": ["actions", "disputes"],
    "active": true
  }
]

Puedes usar el explorador de la API Graph para hacer pruebas con esta API directamente, pero recuerda usar el identificador de acceso de la aplicación.

Tu servidor de devolución de llamada

Tu servidor de devolución de llamada debe gestionar dos tipos de solicitudes. Asegúrate de que está en una dirección URL pública para que podamos realizar estas solicitudes correctamente.

Verificación de suscripciones

En primer lugar, los servidores de Facebook realizarán una única solicitud GET en HTTPS a tu dirección URL de devolución de llamada cuando intentes añadir o modificar una suscripción. Se anexará una cadena de consulta a la URL de devolución de llamada con los parámetros siguientes:

Parámetro Descripción

hub.mode

La cadena "subscribe" se pasa en este parámetro.

hub.challenge

Una cadena aleatoria.

hub.verify_token

El valor verify_token que especificaste al crear la suscripción.

El extremo debe comprobar el valor hub.verify_token primero. De este modo, el servidor sabe que la solicitud procede de Facebook y la relaciona con la suscripción que acabas de configurar.

A continuación, debe devolver únicamente el valor hub.challenge, que confirmará a Facebook que este servidor está configurado para aceptar devoluciones de llamada y evitará vulnerabilidades por denegación de servicio (DDoS).

Nota para los desarrolladores de PHP: En PHP, los puntos y los espacios en los nombres de los parámetros de consulta se convierten en guiones bajos de forma automática. Por este motivo, si vas a escribir el extremo de devolución de llamada en PHP, deberías acceder a estos parámetros con $_GET['hub_mode'], $_GET['hub_challenge'] y $_GET['hub_verify_token']. Para obtener más información, consulta esta nota del manual sobre lenguaje PHP.

Recibir actualizaciones

Si la suscripción es correcta, enviamos una solicitud POST en HTTPS al extremo del servidor cada vez que se produzcan cambios (en los campos o conexiones que elijas). Debes responder a esta solicitud con el código HTTP 200.

Nota: Consideramos un error cualquier respuesta en HTTP que no sea 200. En tal caso, seguiremos intentando enviar la actualización de los webhooks. Por lo tanto, si no respondes correctamente, es posible que recibas la misma actualización varias veces.

La solicitud tendrá el tipo de contenido de application/json y el cuerpo estará formado por una cadena codificada en JSON con uno o varios cambios.

Nota para los desarrolladores en PHP: en PHP, debes usar el código siguiente para obtener los datos codificados:

$data = file_get_contents("php://input");
$json = json_decode($data);`

Ten en cuenta que los parámetros hub.mode, hub.challenge y hub.verify_token no se vuelven a enviar una vez confirmada la suscripción.

A continuación se incluye un ejemplo típico de una devolución de llamada realizada para una suscripción al objeto payments:

{
  "object": "payments",
  "entry": [
    {
      "id": "296989303750203",
      "time": 1347996346,
      "changed_fields": [
        "actions"
      ]
    }
  ]
}

Es importante tener en cuenta que las actualizaciones de webhooks solo informan de que un pago determinado, identificado con el campo id, ha cambiado. Cuando recibas la actualización, deberás enviar una consulta a la API Graph relativa a la información de la transacción para realizar el cambio debidamente.

Nota: Aunque se pueden agrupar los webhooks para otro tipo de objetos, las actualizaciones de pagos no se agrupan nunca.

Te aseguramos que recibirás una nueva actualización cada vez que se actualice una transacción, ya sea por parte del usuario o del desarrollador.

Si se produce un error al enviar una actualización al servidor, lo volveremos a intentar de inmediato y, a continuación, lo intentaremos más veces con una frecuencia cada vez menor durante las siguientes 24 horas.

Con cada solicitud, enviamos un encabezado X-Hub-Signature-256 en HTTP con la firma SHA256 de la carga útil de la solicitud. Para ello, utilizamos la clave secreta de la aplicación como clave, precedida de sha256=. Tu extremo de devolución de llamada puede verificar esta firma para validar la integridad y el origen de la carga útil.

Responder a las actualizaciones

Cuando tu servidor recibe una actualización, debes consultar la API Graph con el campo id para obtener información sobre el nuevo estado de la transacción. A continuación, debes proceder en función del estado.

En las siguientes secciones se indican todos los posibles cambios de estado que activan el envío de una actualización. En términos generales, se dividen en:

  • Cambios en la matriz actions, que se producen cuando se completa un pago de forma asíncrona, se emite un reembolso (emitido por ti o por Facebook) o cuando se produce un contracargo.
  • Cambios en la matriz disputes, que se producen cuando el consumidor inicia una disputa por el pedido.

Acciones

Cada objeto payment contiene una matriz denominada actions, que incluye el historial de cambios de estado por los que ha pasado la transacción. Cada entrada de la matriz actions tiene una propiedad denominada type, que describe el tipo de acción que se ha producido. type puede tener los valores siguientes: charge, refund, chargeback, chargeback_reversal y decline, que se describen aquí.

A continuación, se muestra un ejemplo de respuesta de la API Graph para un objeto de pago con acciones asociadas:

{
   "id": "3603105474213890",
   "user": {
      "name": "Marco Alvarez",
      "id": "500535225"
   },
   "application": {
      "name": "Friend Smash",
      "namespace": "friendsmashsample",
      "id": "241431489326925"
   },
   "actions": [
      {
         "type": "charge",
         "status": "completed",
         "currency": "USD",
         "amount": "0.99",
         "time_created": "2013-03-22T21:18:54+0000",
         "time_updated": "2013-03-22T21:18:55+0000"
      },
      {
         "type": "refund",
         "status": "completed",
         "currency": "USD",
         "amount": "0.99",
         "time_created": "2013-03-23T21:18:54+0000",
         "time_updated": "2013-03-23T21:18:55+0000"
      }
   ],
   "refundable_amount": {
      "currency": "USD",
      "amount": "0.00"
   },
   "items": [
      {
         "type": "IN_APP_PURCHASE",
         "product": "https://www.friendsmash.com/og/friend_smash_bomb.html",
         "quantity": 1
      }
   ],
   "country": "US",
   "created_time": "2013-03-22T21:18:54+0000",
   "payout_foreign_exchange_rate": 1,}`

Dado que te suscribiste al campo de acciones al registrarte en los webhooks, te enviaremos una actualización cuando la matriz cambie como se indica a continuación:

Cobros

En un principio, todos los pedidos contienen una entrada de cobro con "status": "initiated". Un pago iniciado representa un pago que se ha iniciado, pero que no se ha completado. No enviaremos actualizaciones de pagos en este estado.

Cuando un pago se completa correctamente, "status": "initiated" cambia a "status": "completed" y enviaremos una actualización. Cuando observes este cambio, te recomendamos comprobar los registros de pago para verificar si se trata de una transacción nueva o una existente, y responder como se indica a continuación:

  • Si ya estás al corriente del pedido y la devolución de llamada de JavaScript lo ha completado (a ser posible, como primera opción), puedes ignorar la actualización tranquilamente o usarla como confirmación adicional.
  • Si estás al corriente del pedido, pero se encuentra en estado initiated, puedes emitir la divisa o el elemento virtual asociado al cliente para completarlo. A continuación, puedes marcar este pago como completado.
  • Si no estás al corriente del pedido, esto indica que el flujo del cliente no se ha completado, probablemente debido a un problema de conexión o a que el consumidor ha cerrado el navegador durante el proceso de pago. Puedes completar este pedido igualmente de forma segura, porque Facebook sigue siendo la fuente de información definitiva para la facturación de los usuarios.

También recibirás actualizaciones de los pagos que tengan el estado "status": "failed". No los completes.

Reembolsos

Cuando emitas un reembolso a través de la API Graph, recibirás una actualización. Como sucede con "type": "charge", debes tener en cuenta que el estado del reembolso también puede variar. En particular, es posible que no se pueda completar un reembolso, sobre todo debido a un error de procesamiento o de conexión; en tal caso, intenta volver a emitir el reembolso.

Contracargos, anulaciones de contracargos y rechazos

Como sucede con los reembolsos, recibirás una notificación cuando se emita un contracargo, una anulación de contracargo o un rechazo. Se añadirá un objeto de contracargo, anulación de contracargo o rechazo a la matriz de acciones de los datos de pago que devuelve la API Graph.

Disputas

Cuando se inicie una disputa, te enviaremos una actualización para notificarte de ello. En este caso, verás que aparece una matriz "disputes" nueva como parte del objeto payment. La matriz contendrá la hora de inicio de la disputa, el motivo del consumidor para iniciarla y la dirección de correo electrónico del consumidor (que puedes utilizar para contactar con el consumidor directamente para resolver la disputa).

A continuación, se muestra un ejemplo de respuesta completo de la API Graph para una disputa relacionada con una transacción:

{
   "id": "990361254213890",
   "user": {
      "name": "Marco Alvarez",
      "id": "500535225"
   },
   "application": {
      "name": "Friend Smash",
      "namespace": "friendsmashsample",
      "id": "241431489326925"
   },
   "actions": [
      {
         "type": "charge",
         "status": "completed",
         "currency": "USD",
         "amount": "0.99",
         "time_created": "2013-03-22T21:18:54+0000",
         "time_updated": "2013-03-22T21:18:55+0000"
      }
   ],
   "refundable_amount": {
      "currency": "USD",
      "amount": "0.99"
   },
   "items": [
      {
         "type": "IN_APP_PURCHASE",
         "product": "https://www.friendsmash.com/og/friend_smash_bomb.html",
         "quantity": 1
      }
   ],
   "country": "US",
   "created_time": "2013-03-22T21:18:54+0000",
   "payout_foreign_exchange_rate": 1,
   "disputes": [
      {
         "user_comment": "I didn't receive my item! I want a refund, please!",
         "time_created": "2013-03-24T18:21:02+0000",
         "user_email": "email\u0040domain.com",
         "status": "resolved", 
         "reason": "refunded_in_cash"
      }
   ]
}

Para obtener más información acerca de cómo responder a las disputas y emitir reembolsos, consulta Manual de pagos: gestionar disputas y reembolsos.