Gerenciando postbacks
Para utilizar os postbacks, é necessário aprender o que fazer e como fazê-lo. No próximos passos aprenderemos:
- Como utilizar;
- Formato do postback;
- Como validar o postback;
- Como verificar os postbacks;
- Como reenviar um postback.
1. Usando os postbacks
Os postbacks podem ser configurados no momento da criação de transações (transactions) e de assinaturas (subscriptions) através do parâmetro postback_url
como mostram os exemplos abaixo:
curl -X POST https://api.pagar.me/1/transactions -H 'content-type: application/json' -d '{
"amount": "100",
"api_key": "SUA_API_KEY",
"card_id": "card_ci6l9fx8f0042rt16rtb477gj",
"customer": {
"address": {
"neighborhood": "Jardim Paulistano",
"street": "Avenida Brigadeiro Faria Lima",
"street_number": "1811",
"zipcode": "01451001"
},
"document_number": "18152564000105",
"email": "[email protected]",
"name": "Aardvark Silva",
"phone": {
"ddd": "11",
"ddi": "55",
"number": "99999999"
}
},
"metadata": {
"idProduto": "13933139"
},
"postback_url": "http://requestb.in/pkt7pgpk"
}'
import java.util.HashMap;
import java.util.Map;
import me.pagar.model.Address;
import me.pagar.model.Customer;
import me.pagar.model.PagarMe;
import me.pagar.model.PagarMeException;
import me.pagar.model.Phone;
import me.pagar.model.Transaction;
import me.pagar.model.Transaction.PaymentMethod;
PagarMe.init("SUA_API_KEY");
Phone phone = new Phone();
phone.setDdd("11");
phone.setDdi("55");
phone.setNumber("99999999");
String street = "Avenida Brigadeiro Faria Lima";
String streetNumber = "1811";
String neighborhood = "Jardim Paulistano";
String zipcode = "01451001";
Address address = new Address(street, streetNumber, neighborhood, zipcode);
String name = "Aardvark Silva";
String email = "[email protected]";
String documentNumber = "18152564000105";
Customer customer = new Customer(name, email);
customer.setAddress(address);
customer.setPhone(phone);
customer.setDocumentNumber(documentNumber);
Map<String, Object> metadata = new HashMap<String, Object>();
metadata.put("IdProduto", 13933139);
Transaction tx = new Transaction();
tx.setCustomer(customer);
tx.setAmount(100);
tx.setCardId("card_ci6l9fx8f0042rt16rtb477gj");
tx.setPaymentMethod(PaymentMethod.CREDIT_CARD);
tx.setMetadata(metadata);
tx.setPostbackUrl("http://requestb.in/pkt7pgpk");
tx.save();
require 'pagarme'
PagarMe.api_key = "SUA_API_KEY";
transaction = PagarMe::Transaction.new({
amount: 100,
payment_method: "credit_card",
card_id: "card_ci6l9fx8f0042rt16rtb477gj",
postback_url: "http://requestb.in/pkt7pgpk",
customer: {
name: "Aardvark Silva",
email: "[email protected]",
document_number: "18152564000105",
address: {
street: "Avenida Brigadeiro Faria Lima",
street_number: "1811",
neighborhood: "Jardim Paulistano",
zipcode: "01451001"
},
phone: {
ddi: "55",
ddd: "11",
number: "99999999"
}
},
metadata: {
idProduto: "13933139"
}
})
transaction.charge
<?php
require("vendor/autoload.php");
$pagarme = new PagarMe\Client('SUA_CHAVE_DE_API');
$transaction = $pagarme->transactions()->create([
"amount" => 100,
"card_id" => "card_ci6l9fx8f0042rt16rtb477gj",
"payment_method" => "credit_card",
"postback_url" => "http://requestb.in/pkt7pgpk",
"customer" => [
"name" => "Aardvark Silva",
"document_number" => "18152564000105",
"email" => "[email protected]",
"address" => [
"street" => "Avenida Brigadeiro Faria Lima",
"street_number" => "1811",
"neighborhood" => "Jardim Paulistano",
"zipcode" => "01451001"
],
"phone" => [
"ddi" => "55"
"ddd" => "11",
"number" => "99999999"
]
]
]);
PagarMeService.DefaultApiKey = "SUA_API_KEY";
Transaction transaction = new Transaction();
transaction.Amount = 100;
transaction.Card = new Card() {
Id = "card_ci6l9fx8f0042rt16rtb477gj"
};
transaction.Customer = new Customer () {
Name = "Aardvark Silva",
Email = "[email protected]",
DocumentNumber = "18152564000105",
Address = new Address () {
Street = "Avenida Brigadeiro Faria Lima",
StreetNumber = "123",
Neighborhood = "Jardim Paulistano",
Zipcode = "01451001"
},
Phone = new Phone () {
Ddi = "55",
Ddd = "11",
Number = "23456789"
}
};
transaction.PostbackUrl = "http://requestb.in/pkt7pgpk";
transaction.Metadata = new Metadata() {
IdProduto = 13933139
};
transaction.Save();
import pagarme
pagarme.authentication_key('SUA_API_KEY')
params = {
'card_hash': 'CARD_HASH_GERADO',
'customer': {
'email': '[email protected]',
'name': 'Daenerys Targaryen',
'document_number': '18152564000105',
'address': {
'zipcode': '04571020',
'neighborhood': 'Dragon Village',
'street': 'Rua Drogon',
'street_number': '240'
},
'phone': {
'number': '987654321',
'ddd': '11'
}
} ,
"capture": "true",
"async": "false",
"installments": "1",
"payment_method":"credit_card",
"amount": "1000",
"postback_url": "SUA_POSTBACK_URL"
}
trx = pagarme.transaction.create(params)
print(trx)
Veja o postback em assinaturas:
curl -X POST https://api.pagar.me/1/subscriptions -H 'content-type: application/json' -d '{
"api_key": "SUA_API_KEY",
"card_id": "card_ci234fx8rr649rt16rtb11132",
"customer": {
"email": "[email protected]"
},
"payment_method": "credit_card",
"plan_id": "12783",
"postback_url": "http://requestb.in/zyn5obzy"
}'
No momento não temos essa funcionalidade :(
require 'pagarme'
PagarMe.api_key = "SUA_API_KEY"
plan = PagarMe::Plan.find_by_id("12783")
subscription = PagarMe::Subscription.new({
:payment_method => 'credit_card',
:card_number => "4901720080344448",
:card_holder_name => "Jose da Silva",
:card_expiration_month => "10",
:card_expiration_year => "15",
:card_cvv => "314",
:postback_url => "http://test.com/postback",
:customer => {
email: '[email protected]'
})
subscription.plan = plan
subscription.create
<?php
require("vendor/autoload.php");
$pagarme = new PagarMe\Client('SUA_CHAVE_DE_API');
$subscription = $pagarme->subscriptions()->create([
"plan_id" => "13850",
"payment_method" => "credit_card",
"card_number" => "4901720080344448",
"postback_url" => "http://requestb.in/pkt7pgpk",
"card_holder_name" => "Jose da Silva",
"card_expiration_month" => 12,
"card_expiration_year" => 15,
"card_cvv" => "123",
'customer' => [
'email' => '[email protected]'
]
]);
PagarMeService.DefaultApiKey = "SUA_API_KEY";
Subscription subscription = new Subscription();
subscription.PaymentMethod = PaymentMethod.CreditCard;
subscription.CardNumber = "4901720080344448";
subscription.CardHolderName = "Jose da Silva";
subscription.CardExpirationDate = "1215";
subscription.CardCvv = "123";
subscription.PosbackUrl= "http://requestb.in/pkt7pgpk";
Customer customer = new Customer();
customer.Email = "[email protected]";
subscription.Customer = customer;
subscription.Save();
import pagarme
pagarme.authentication_key('SUA_API_KEY')
params = {
'card_hash': 'CARD_HASH_GERADO',
'customer': {
'email': '[email protected]',
'name': 'Daenerys Targaryen',
'document_number': '18152564000105',
'address': {
'zipcode': '04571020',
'neighborhood': 'Dragon Village',
'street': 'Rua Drogon',
'street_number': '240'
},
'phone': {
'number': '987654321',
'ddd': '11'
}
} ,
"capture": "true",
"async": "false",
"installments": "1",
"payment_method":"credit_card",
"amount": "1000",
"postback_url": "SUA_POSTBACK_URL"
}
subscription = pagarme.subscription.create(params)
print(subscription)
Postback em localhost?
Para realizar testes, é possível utilizar o site requestBin para gerar uma URL temporária e analisar os postbacks enviados ou o programa ngrok para gerar e vincular uma URL temporária ao IP da máquina de teste / desenvolvimento. Essa URL pode ser utilizada no parâmetro postback_url.
Temporal
Partindo do primeiro postback, os próximos são enviados com o seguinte padrão de intervalo de tempo, em minutos: 1 (três vezes), 5 (três vezes), 60 (25 vezes)
Postback de transações de assinaturas
Você pode configurar em sua Dashboard se gostaria de receber postbacks quando uma transação pertencente a uma assinatura acaba de ser criada.
2. Formato dos postbacks
Quando a postback_url
é passada, a transação é retornada com status processing
, e as mudanças de status são enviadas para o seu servidor na URL de postback. Isso é feito através de um request HTTP POST
com os seguintes parâmetros:
Parâmetro | Descrição | Observação |
---|---|---|
id | ID da transação. | |
event | A qual evento o postback se refere. | Transações: transaction_status_changed .Assinatura: subscription_status_changed Link de Pagamento: order_status_changed Recebedor: recipient_status_changed |
old_status | Status anterior da transação. | |
desired_status | Status ideal para objetos deste tipo, em um fluxo normal, onde autorização e captura são feitos com sucesso, por exemplo. | |
current_status | Status para o qual efetivamente mudou. | |
object | Qual o tipo do objeto referido. | Transações: transaction Assinaturas: subscription Link de Pagamento: order Recebedor: recipient |
transaction | Possui todas as informações do objeto. Para acessar objetos internos basta acessar a chave transaction[objeto1][objeto2]. Ex: para acessar o ddd: transaction[phone][ddd] |
Payload
Para ver os exemplos de Payload, clique aqui para ver em nossa página de referência
Current transaction
Retorna a última transação relacionada à respectiva subscription. Para cartão de crédito, retorna a última cobrança feita, e para boleto, retorna o último boleto gerado.
Formato
Diferentemente das respostas da API Pagar.me, o postback sempre terá seus parâmetros em
application/x-www-form-urlencoded
3. Como validar um postback
A validação do postback serve para verificar se realmente ele foi enviado pela Pagar.me, e é de extrema importância a sua utilização para que suas transações estejam seguras.
Para fazer a validação, são necessárias duas informações de nosso postback:
- Valor do header 'X-Hub-Signature'. Vamos chamar esse valor de "assinatura do postback";
- Corpo da requisição (no mesmo formato mostrado na seção anterior).
Com esses dois valores, basta realizar o HMAC-SHA1 do corpo da requisição utilizando a sua API Key e comparar com a assinatura do postback. Se os valores forem iguais, excelente. Caso contrário, não fomos nós que enviamos essa requisição!
EXPECTED_SIGNATURE=`cat postback_body | openssl dgst -sha1 -hmac "SUA_API_KEY"`
SIGNATURE=1213e67a3b34c2848f8317d29bcb8cbc9e0979b8
if [ "$SIGNATURE" = "$EXPECTED_SIGNATURE" ]; then
echo "Valid Signature"
fi
PagarMe.api_key = 'SUA_API_KEY';
if PagarMe::PostBack.valid_request_signature?(postback_body, '1213e67a3b34c2848f8317d29bcb8cbc9e0979b8')
puts "Valid Signature"
end
<?php
require("vendor/autoload.php");
$pagarme = new PagarMe\Client('SUA_CHAVE_DE_API');
$requestBody = file_get_contents("php://input");
$signature = $_SERVER['HTTP_X_HUB_SIGNATURE'];
$isValidPostback = $pagarme->postbacks()->validate($requestBody, $signature);
if ($isValidPostback) {
echo "Postback válido";
} else {
echo "Postback inválido";
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
var _apiKey = "SUA_API_KEY";
var signature = Request.Headers("X-Hub-Signature");
var rawBody = "rawBody";
var isValid = false;
byte[] apiKeyBytes = Encoding.ASCII.GetBytes(_apiKey);
byte[] rawBodyBytes = Encoding.ASCII.GetBytes(rawBody);
string cleanedSignature = signature.Split('=')[1];
using (HMACSHA1 hmac = new HMACSHA1(apiKeyBytes))
{
byte[] rawBodyHashBytes = hmac.ComputeHash(rawBodyBytes);
String rawBodyHash = BitConverter.ToString(rawBodyHashBytes).Replace("-", String.Empty).ToLower();
isValid = rawBodyHash.Equals(cleanedSignature);
}
Console.WriteLine (isValid);
Não possuimos esta funcionalidade no momento :(
4. Verificando os postbacks
Após um postback ser enviado, existem duas situações que podem ocorrer:
- Recebemos um retorno com status code 2xx do postback;
- Ocorre algum erro no recebimento do postback e recebemos um status code diferente de 2xx (ou até não recebemos uma resposta).
No primeiro caso, nada mais ocorre. Já no segundo caso, começaremos então a fazer tentativas de reenvio do postback. Por padrão, são feitas até 31 novas tentativas.
Se existir algo estranho com sua integração com os nossos postbacks, você consegue monitorar isso do lado da sua aplicação:
curl -X GET 'https://api.pagar.me/1/transactions/:transaction_id/postbacks?api_key=SUA_API_KEY'
import me.pagar.model.PagarMe;
import me.pagar.model.Postback;
import me.pagar.model.Transaction;
PagarMe.init("SUA_API_KEY");
Transaction transaction = new Transaction().find(1550691);
Collection<Postback> postbacks = transaction.postbacks();
System.out.print(postbacks);
require 'pagarme'
PagarMe.api_key = 'SUA_API_KEY'
transaction = PagarMe::Transaction.find("1550691")
postbacks = transaction.postbacks
p postbacks
<?php
require("vendor/autoload.php");
$pagarme = new PagarMe\Client('SUA_CHAVE_DE_API');
$postbacks = $pagarme->postbacks()->getList([
'model' => 'subscription', //pode ser transaction ou subscription
'model_id' => 'ID_DA_ASSINATURA_OU_TRANSACAO'
]);
using PagarMe;
using PagarMe.Model;
PagarMeService.DefaultApiKey = "SUA_API_KEY";
PagarMeService.DefaultEncryptionKey = "SUA_ENCRYPTION_KEY";
Transaction transaction = PagarMeService.GetDefaultService().Transactions.Find("1550691");
Postback[] postbacks = transaction.Postbacks.FindAll(new Postback()).ToArray();
import pagarme
pagarme.authentication_key('SUA_API_KEY')
#transaction postbacks
postback = pagarme.transaction.postbacks("TRANSACTION_ID")
print (postback)
#subscription postbacks
postback = pagarme.subscription.postbacks("SUBSCRIPTION_ID")
print (postback)
Na lista de postbacks é possível visualizar as informações essenciais do postback enviado:
{
"object": "postback",
"status": "success",
"model": "transaction",
"model_id": "762919",
"headers": "{\"Content-Type\":\"application/x-www-form-urlencoded\",\"X-PagarMe-Event\":\"transaction_status_changed\",\"X-Hub-Signature\":\"sha1=709355e496ca88b86652c52c543fc7f62a0a4b36\",\"User-Agent\":\"PagarMe-Hookshot/1.0\"}",
"payload": "",
"retries": 0,
"next_retry": null,
"deliveries": [
{
"object": "postback_delivery",
"status": "success",
"status_reason": "http_status_code",
"status_code": "200",
"response_time": 26,
"response_headers": "{\"date\":\"Fri, 07 Oct 2016 11:34:13 GMT\",\"content-type\":\"text/html; charset=utf-8\",\"transfer-encoding\":\"chunked\",\"connection\":\"close\",\"set-cookie\":[\"__cfduid=d25dce8bbb2ddb97c62b11e4ddf69780f1475840053; expires=Sat, 07-Oct-17 11:34:13 GMT; path=/; domain=.requestb.in; HttpOnly\"],\"sponsored-by\":\"https://www.runscope.com\",\"via\":\"1.1 vegur\",\"server\":\"cloudflare-nginx\",\"cf-ray\":\"2ee10aeea5e32408-IAD\"}",
"response_body": "ok",
"date_created": "2016-10-07T11:34:13.535Z",
"date_updated": "2016-10-07T11:34:13.569Z",
"id": "pd_citzp29en015ka373bf04s3fr"
}
],
"date_created": "2016-10-07T11:34:13.509Z",
"date_updated": "2016-10-07T11:34:13.577Z",
"signature": "sha1=709355e496ca88b86652c52c543fc7f62a0a4b36",
"id": "po_citzp29dx015ja373tk2cno13"
}
Dessas informações, os mais importantes são:
- deliveries: lista da tentativas de (re)envio do postback relacionado;
- response_body: qual foi a resposta de sua aplicação ao postback.
5. Reenvio de postbacks
Se necessário, há uma rota que força o reenvio de um postback. Isso para casos em que não foi possível completar o processo, ou por quaisquer outros motivos ligados à sua aplicação.
curl -X POST "https://api.pagar.me/1/transactions/:transaction_id/postbacks/:postback_id/redeliver?api_key=SUA_API_KEY"
import me.pagar.model.PagarMe;
import me.pagar.model.Postback;
import me.pagar.model.Transaction;
PagarMe.init("SUA_API_KEY");
Transaction transaction = new Transaction().find(1550696);
Postback po = transaction.postbackRedeliver("po_cj2wiybvm0cydx67347eai7h4");
Ainda não temos essa feature implementada :(
<?php
require("vendor/autoload.php");
$pagarme = new PagarMe\Client('SUA_CHAVE_DE_API');
$postbackRedeliver = $pagarme->postbacks()->redeliver([
'model' => 'subscription',
'model_id' => 'ID_DA_ASSINATURA',
'postback_id' => 'po_cjlzhftd2006xg573fwelfg9y'
]);
using System;
using PagarMe;
using PagarMe.Model;
using PagarMe.Enumeration;
using System.Collections.Generic;
PagarMe.PagarMeService.DefaultApiKey = "SUA_API_KEY";
transaction = PagarMeService.GetDefaultService ().Transactions.Find ("");
var a = transaction.Postbacks.FindAll (new Postback ()).GetEnumerator();
a.MoveNext ();
Postback postback = a.Current;
postback.Redeliver ();
import pagarme
pagarme.authentication_key('SUA_API_KEY')
redeliver = pagarme.transaction.postback_redeliver("transaction_id", "postback_id")
print (redeliver)
Vale ressaltar
A chamada à rota de reenvio implica na pausa de possíveis reenvios futuros. Ou seja, se for feito um reenvio antes da 31a tentativa, não completaremos as 31 retentativas.
Updated about 3 years ago
Bom trabalho, o postback é uma excelente ferramenta para controlar as suas transações. A partir desse ponto você vai aprender a integrar o Pagar.me com uma maquininha ou com plataformas de e-commerce.