Os Webhooks para Pagamentos (antigamente chamados de Atualizações em tempo real) são um método essencial que informa sobre alterações nos pedidos feitos por pagamentos do Facebook no seu app. |
Os Webhooks são um sistema baseado em assinatura entre o Facebook e o seu servidor. Seu app assina o recebimento de atualizações do Facebook por meio de um ponto de extremidade HTTPS específico. Quando um pedido feito no app é atualizado, emitimos uma solicitação POST
de HTTPS para o ponto de extremidade, notificando o servidor sobre a alteração.
Estes são os 3 cenários principais em que as atualizações são enviadas para o servidor do seu desenvolvedor:
Para assinar Webhooks para Pagamentos, primeiro crie uma URL de ponto de extremidade pública que receba GET
de HTTPS para verificação da assinatura e POST
para solicitações de alteração de dados. Veja abaixo a descrição da estrutura desses dois tipos de solicitações. Depois, configure as assinaturas para o objeto payment
do app. Estas são as duas maneiras de fazer isso:
Em ambos os casos, o ponto de extremidade receberá os mesmos dados da mesma maneira. Consulte Servidor de retorno de chamada para ver mais informações sobre o que o servidor receberá.
A forma mais fácil de configurar o app para receber atualizações de Webhooks é por meio do painel Pagamentos no Painel de Aplicativos. Encontre o app no painel e clique na aba Payments
. A seção Webhooks estará abaixo da seção Configurações da empresa.
O status de assinatura do app será listado nessa tela, independentemente de ter sido adicionado pelo painel ou pela API. Nessa área, é possível alterar e testar a URL de retorno de chamada para a assinatura.
No campo "Retorno de chamada", forneça um ponto de extremidade de servidor válido e de acesso público. Esse é o endereço que usaremos para verificar a assinatura e enviar as atualizações. É necessário que ele responda de acordo com o que está descrito em Servidor de retorno de chamada.
Por fim, forneça um "Token de verificação". O token será enviado somente durante a fase de inscrição para verificar se a assinatura tem origem em uma localização segura. Ele não será enviado em atualizações regulares de Webhooks.
É preciso testar as configurações de retorno de chamada antes de salvar a assinatura. Assim, uma verificação de solicitação GET será emitida para o ponto de extremidade, com os parâmetros hub.mode
, hub.challenge
e hub.verify_token
, assegurando o gerenciamento correto deles. Por exemplo, é preciso garantir que o ponto de extremidade ecoe hub.challenge
de volta ao Facebook:
Depois de inserir os detalhes da assinatura, clique no botão "Salvar alterações" na parte inferior da página. Para editar uma assinatura, basta alterar os conteúdos dos campos, refazer o teste e salvar o formulário novamente.
Também é possível configurar e listar assinaturas de forma programática por meio da Graph API. Você precisará do access token
do app, disponível na ferramenta Token de Acesso ou por meio do ponto de extremidade /oauth
da Graph API.
A API de Assinatura está disponível no ponto de extremidade https://graph.facebook.com/[APP_ID]/subscriptions
.
É possível realizar estas 3 tarefas com ele:
POST
de HTTPS)GET
de HTTPS)Para configurar uma assinatura, envie um POST
com os seguintes parâmetros (correspondentes a campos do formulário descrito acima):
object
: como descrito acima, o tipo de objeto cujas atualizações você quer receber. Especifique payments
.fields
: a lista de propriedades, separadas por vírgula, do objeto cujas atualizações sobre alterações você quer receber. Especifique "actions" e "disputes".callback_url
: um ponto de extremidade de servidor válido e de acesso público.verify_token
: uma string arbitrária, enviada para o ponto de extremidade quando a assinatura é verificada.Ao receber a solicitação, assim como na configuração do formulário acima, faremos um GET
para o retorno de chamada. Assim, verificaremos se ele é válido e se está pronto para receber atualizações. Em especial, é preciso garantir que o ponto de extremidade ecoe hub.challenge
de volta ao Facebook.
O app só pode ter uma assinatura para cada tipo de objeto. Portanto, se existir uma assinatura para determinado tipo de objeto, os novos dados publicados substituirão os anteriores.
Emitir um GET
de HTTP para a API de Assinatura retorna o conteúdo codificado em JSON que lista as assinaturas. Por exemplo:
[ { "object": "payments", "callback_url": "https://www.friendsmash.com/rtu.php", "fields": ["actions", "disputes"], "active": true } ]
É possível usar o Explorador da Graph API para testá-la usando o token de acesso do app.
O servidor de retorno de chamada deve gerenciar 2 tipos de solicitações. Verifique se ele está em uma URL pública, para que possamos fazer as solicitações.
Para começar, os servidores do Facebook farão um GET
único de HTTPS para a URL de retorno de chamada quando você tentar adicionar ou modificar uma assinatura. Uma string de consulta será adicionada à URL de retorno de chamada com os parâmetros a seguir:
Parâmetro | Descrição |
---|---|
| A string |
| Uma string aleatória. |
| O valor |
O ponto de extremidade verificará primeiro o hub.verify_token
. Com isso, o servidor saberá que a solicitação foi feita pelo Facebook e está relacionada à assinatura que você acabou de configurar.
Então, ele deve ecoar de volta apenas o valor hub.challenge
que confirma para o Facebook que o servidor está configurado para aceitar retornos de chamada e previne vulnerabilidades de negação de serviço (DDoS, pelas iniciais em inglês).
Observação para desenvolvedores de PHP: pontos e espaços em nomes de parâmetro de consulta são automaticamente convertidos em sublinhados em PHP. Portanto, se você estiver escrevendo o ponto de extremidade de retorno de chamada nessa linguagem, os parâmetros devem ser acessados usando $_GET['hub_mode']
, $_GET['hub_challenge']
e $_GET['hub_verify_token']
. Para ver mais detalhes, consulte esta nota do manual de linguagem.
Depois da assinatura, emitiremos um POST
de HTTPS para o ponto de extremidade do servidor sempre que ocorrerem alterações (em conexões ou campos escolhidos). É preciso responder à solicitação com o código 200
de HTTP.
Observação: todas as respostas de HTTP diferentes de 200
serão consideradas erros. Nesses casos, continuaremos tentando enviar a atualização de webhooks. Portanto, se você não responder corretamente, receberá a mesma atualização diversas vezes.
A solicitação terá o tipo de conteúdo application/json
. Já o corpo incluirá uma string codificada em JSON com uma ou mais alterações.
Observação para desenvolvedores de PHP: para obter os dados codificados em PHP, use o seguinte código:
$data = file_get_contents("php://input"); $json = json_decode($data);`
Os parâmetros hub.mode
, hub.challenge
e hub.verify_token
não são reenviados depois que a assinatura é confirmada.
Veja um exemplo típico de um retorno de chamada feito para a assinatura do objeto payments
:
{ "object": "payments", "entry": [ { "id": "296989303750203", "time": 1347996346, "changed_fields": [ "actions" ] } ] }
É importante observar que as atualizações de Webhook informam apenas que um pagamento específico identificado pelo campo id
foi alterado. Após receber a atualização, é preciso que você faça uma consulta da Graph API para obter os detalhes da transação, a fim de responder à alteração de forma adequada.
Observação: as atualizações de pagamento nunca são agrupadas em lote, embora isso possa ser feito com Webhooks em outros tipos de objeto.
Você receberá uma nova atualização sempre que uma transação for atualizada por ação do usuário ou do desenvolvedor.
Se uma atualização enviada para o servidor falhar, tentaremos outra vez imediatamente e depois mais algumas vezes, diminuindo a frequência nas 24 horas seguintes.
A cada solicitação, enviamos um cabeçalho HTTP X-Hub-Signature-256
com a assinatura SHA256 da carga da solicitação, usando a chave secreta do app como a chave, além do prefixo sha256=
. O ponto de extremidade de retorno de chamada pode verificar essa assinatura para validar a integridade e a origem da carga.
Depois que o servidor receber uma atualização, faça uma consulta da Graph API usando o campo id
para obter detalhes sobre o novo status da transação. Em seguida, tome medidas de acordo com o status.
As seções a seguir listam as possíveis alterações de estado que acionam o envio de uma atualização. Elas podem ser destes dois tipos:
Cada objeto payment
contém uma matriz intitulada actions
com a coleção de alterações de estado pelas quais a transação passou. Cada entrada na matriz actions
tem uma propriedade chamada type
que descreve o tipo de ação que ocorreu. type
pode ter os valores charge
, refund
, chargeback
, chargeback_reversal
e decline
, que estão explicados aqui.
Este é um exemplo de resposta da Graph API para um objeto de pagamento com as ações associadas:
{ "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,}`
Como você assinou os campos de ação quando fez o registro para Webhooks, emitiremos uma atualização quando a matriz for alterada da seguinte maneira:
Inicialmente, todos os pedidos contêm uma entrada de cobrança com "status": "initiated"
. Os pagamentos em estado iniciado ainda não foram concluídos. Não enviaremos atualizações para pagamentos nesse estado.
Quando o pagamento for concluído, "status": "initiated"
será alterado para "status": "completed"
, e emitiremos uma atualização. Quando você receber essa alteração, confira os registros de pagamento para verificar se a transação é nova ou não e responda da seguinte maneira:
initiated
, você poderá prosseguir com o processamento e encaminhar ao consumidor a moeda ou o item virtual associado. O pagamento poderá então ser marcado como concluído.Você também receberá atualizações de pagamentos com "status": "failed"
, que não devem ser processados.
Sempre que emitir um reembolso pela Graph API, você receberá uma atualização. Da mesma forma que com "type": "charge"
, o reembolso pode apresentar um status variável, do qual você deve estar ciente. É possível que o reembolso falhe, em geral, devido a erros de processamento ou conectividade. Nesse caso, tente emiti-lo novamente.
Assim como acontece com reembolsos, você também receberá uma notificação quando um estorno, uma reversão de estorno ou uma recusa forem emitidos. Um objeto de estorno, reversão de estorno ou recusa será adicionado à matriz de ações dos dados de retorno da Graph API para o pagamento.
Quando uma contestação for iniciada, notificaremos você por meio da emissão de uma atualização. Nesse caso, uma nova matriz "disputes"
aparecerá como parte do objeto payment
. A matriz conterá o horário em que a contestação foi iniciada, o motivo de o consumidor ter iniciado a resposta e o endereço de email do consumidor, pelo qual você poderá entrar em contato para resolver a contestação.
Veja um exemplo de resposta da Graph API para uma transação contestada:
{ "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 ver mais informações sobre como responder a contestações e emitir reembolsos, consulte Payments How-to: Handling Disputes and Refunds.