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. |
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:
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.
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.
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.
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:
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.
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:
POST
en HTTPS).GET
en HTTPS).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.
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 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.
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 |
---|---|
| La cadena " |
| Una cadena aleatoria. |
| El valor |
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.
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.
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:
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:
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:
initiated
, puedes emitir la divisa o el elemento virtual asociado al cliente para completarlo. A continuación, puedes marcar este pago como completado.También recibirás actualizaciones de los pagos que tengan el estado "status": "failed"
. No los completes.
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.
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.
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.