Configurar notificaçÔes de pagamento
As notificaçÔes Webhooks, tambĂ©m conhecidas como retornos de chamada web, sĂŁo um mĂ©todo eficaz que permite aos servidores do Mercado Pago enviar informaçÔes em tempo real quando ocorre um evento especĂfico relacionado Ă sua integração.
Com os Webhooks, o seu sistema nĂŁo precisa realizar consultas contĂnuas para buscar atualizaçÔes. Esse mecanismo transmite dados de maneira passiva e automĂĄtica, utilizando solicitaçÔes HTTP POST. Assim, otimiza a comunicação e reduz a carga nos servidores.
Consulte o fluxo geral de uma notificação no diagrama abaixo.
A seguir, apresentamos um passo a passo para configurar as notificaçÔes de criação e atualização de pagamentos. Depois de configuradas, as notificaçÔes Webhook serão enviadas sempre que um pagamento for criado ou seu estado for modificado (Pendente, Rejeitado ou Aprovado). No processo de integração com o Mercado Pago, as notificaçÔes podem ser configuradas de duas maneiras:
Tipo de Configuração | Descrição | Vantagens | Quando Usar |
Configuração atravĂ©s de Suas integraçÔes | Este mĂ©todo permite configurar notificaçÔes diretamente do seu Painel de Desenvolvedor. VocĂȘ pode configurar notificaçÔes para cada uma de suas aplicaçÔes, identificar contas distintas, se necessĂĄrio, e validar a origem da notificação atravĂ©s de uma assinatura secreta. | - Identificação simples de contas distintas, garantindo uma gestĂŁo adequada em ambientes diversos. - Alta segurança ao validar a origem das notificaçÔes atravĂ©s de uma assinatura secreta, que garante a integridade da informação recebida. - Mais versĂĄtil e eficaz para manter um controle centralizado e gerenciar a comunicação com as aplicaçÔes de maneira eficiente. | Recomendado para a maioria das integraçÔes. |
Configuração durante a criação de pagamentos ou preferĂȘncias | As notificaçÔes sĂŁo configuradas para cada transação individualmente durante a criação do pagamento ou preferĂȘncia. | - Ajustes especĂficos para cada transação. - Flexibilidade em casos de necessidade de parĂąmetros dinĂąmicos obrigatĂłrios. - Ideal para integraçÔes como plataformas de pagamento para mĂșltiplos vendedores. | Conveniente em casos em que seja necessĂĄrio enviar um query parameter dinĂąmico de forma obrigatĂłria, alĂ©m de ser adequado para integraçÔes que funcionam como uma plataforma de pagamento para mĂșltiplos vendedores. |
Configuração através de Suas integraçÔes
VocĂȘ pode configurar notificaçÔes para cada uma de suas aplicaçÔes diretamente em Suas integraçÔes de maneira eficiente e segura. Nesta seção, explicaremos como:
- Indicar as URLs de notificação e configurar eventos
- Validar a origem de uma notificação
- Simular o recebimento de uma notificação
1. Indicar URLs de notificação e configurar o evento
Para configurar notificaçÔes Webhooks, é necessårio indicar as URLs para as quais as notificaçÔes serão enviadas. Para fazer isso, siga o passo a passo abaixo:
- Acesse Suas integraçÔes e selecione a aplicação integrada com o Checkout Pro para a qual vocĂȘ deseja ativar as notificaçÔes.
- No menu Ă esquerda, selecione Webhooks > Configurar notificaçÔes e configure a URL que serĂĄ utilizada para recebĂȘ-las.
- Selecione a aba Modo produtivo e forneça uma
URL HTTPS
para receber notificaçÔes com sua integração produtiva.
- Selecione o evento Pagamentos para receber notificaçÔes, que serão enviadas no formato
JSON
através de umHTTPS POST
para a URL especificada anteriormente.
5.Por fim, clique em Salvar configuração. Isso gerarå uma chave secreta exclusiva para a aplicação, utilizada para validar a autenticidade das notificaçÔes recebidas, assegurando que elas sejam provenientes do Mercado Pago. Vale ressaltar que essa chave não possui prazo de validade, mas recomenda-se sua renovação periódica como medida de segurança. Para renovar a chave, basta clicar no botão Restabelecer.
2. Simular o recebimento da notificação
Para garantir que as notificaçÔes sejam configuradas corretamente, é necessårio simular o recebimento delas. Para isso, siga o passo a passo abaixo:
- Após configurar as URLs e os eventos, clique em Salvar configuração.
- Em seguida, clique em Simular para testar se a URL indicada estå recebendo as notificaçÔes corretamente.
- Na tela de simulação, selecione a URL que serå testada, que pode ser a URL de teste ou a de produção.
- Depois, escolha o tipo de evento e insira a identificação que serå enviada no corpo da notificação (Data ID).
- Por fim, clique em Enviar teste para verificar a solicitação, a resposta fornecida pelo servidor e a descrição do evento. VocĂȘ receberĂĄ uma resposta semelhante ao exemplo abaixo, que representa o
body
da notificação recebida em seu servidor.
plain
{ "action": "payment.updated", "api_version": "v1", "data": { "id": "123456" }, "date_created": "2021-11-01T02:02:02Z", "id": "123456", "live_mode": false, "type": "payment", "user_id": 724484980 }
3. Validar a origem da notificação
A validação da origem de uma notificação Ă© fundamental para assegurar a segurança e a autenticidade das informaçÔes recebidas. Este processo ajuda a prevenir fraudes e garante que apenas notificaçÔes legĂtimas sejam processadas.
O Mercado Pago enviarå ao seu servidor uma notificação semelhante ao exemplo abaixo para um alerta do tópico payment
. Neste exemplo, estĂĄ incluĂda a notificação completa, que contĂ©m os query params
, o body
e o header
da notificação.
- Query params: SĂŁo parĂąmetros de consulta que acompanham a URL. No exemplo, temos
data.id=123456
etype=payment
. - Body: O corpo da notificação contém informaçÔes detalhadas sobre o evento, como
action
,api_version
,data
,date_created
,id
,live_mode
,type
euser_id
. - Header: O cabeçalho contém metadados importantes, incluindo a assinatura secreta da notificação
x-signature
.
plain
POST /test?data.id=123456&type=payment HTTP/1.1 Host: prueba.requestcatcher.com Accept: */* Accept-Encoding: * Connection: keep-alive Content-Length: 177 Content-Type: application/json Newrelic: eyJ2IjpbMCwxXSwiZCI6eyJ0eSI6IkFwcCIsImFjIjoiOTg5NTg2IiwiYXAiOiI5NjA2MzYwOTQiLCJ0eCI6IjU3ZjI4YzNjOWE2ODNlZDYiLCJ0ciI6IjY0NjA0OTM3OWI1ZjA3MzMyZDdhZmQxMjEyM2I5YWE4IiwicHIiOjAuNzk3ODc0LCJzYSI6ZmFsc2UsInRpIjoxNzQyNTA1NjM4Njg0LCJ0ayI6IjE3MDk3MDcifX0= Traceparent: 00-646049379b5f07332d7afd12123b9aa8-e7f77a41f687aecd-00 Tracestate: 1709707@nr=0-0-989586-960636094-e7f77a41f687aecd-57f28c3c9a683ed6-0-0.797874-1742505638684 User-Agent: restclient-node/4.15.3 X-Request-Id: bb56a2f1-6aae-46ac-982e-9dcd3581d08e X-Rest-Pool-Name: /services/webhooks.js X-Retry: 0 X-Signature: ts=1742505638683,v1=ced36ab6d33566bb1e16c125819b8d840d6b8ef136b0b9127c76064466f5229b X-Socket-Timeout: 22000 {"action":"payment.updated","api_version":"v1","data":{"id":"123456"},"date_created":"2021-11-01T02:02:02Z","id":"123456","live_mode":false,"type":"payment","user_id":724484980}
A partir da notificação Webhook recebida, vocĂȘ poderĂĄ validar a autenticidade de sua origem. O Mercado Pago sempre incluirĂĄ a chave secreta nas notificaçÔes Webhooks que serĂŁo recebidas, o que permitirĂĄ validar sua autenticidade. Essa chave serĂĄ enviada no header x-signature
, que serĂĄ semelhante ao exemplo abaixo.
plain
`ts=1742505638683,v1=ced36ab6d33566bb1e16c125819b8d840d6b8ef136b0b9127c76064466f5229b`
Para confirmar a validação, é necessårio extrair a chave contida no header e comparå-la com a chave fornecida para sua aplicação em Suas integraçÔes. Para isso, siga o passo a passo abaixo. Ao final, disponibilizamos nossos SDKs com exemplos de códigos completos para facilitar o processo.
- Para extrair o timestamp (
ts
) e a chave (v1
) do headerx-signature
, divida o conteĂșdo do header pelo caractere â,", o que resultarĂĄ em uma lista de elementos. O valor para o prefixots
é o timestamp (em milissegundos) da notificação e v1 é a chave encriptada. Seguindo o exemplo apresentado anteriormente,ts=1742505638683
ev1=ced36ab6d33566bb1e16c125819b8d840d6b8ef136b0b9127c76064466f5229b
. - Utilizando o template abaixo, substitua os parùmetros com os dados recebidos na sua notificação.
plain
id:[data.id_url];request-id:[x-request-id_header];ts:[ts_header];
- Os parĂąmetros com o sufixo
_url
vĂȘm de query params. Exemplo: [data.id_url] serĂĄ substituĂdo pelo valor correspondente ao ID do evento (data.id
). Este query param pode ser encontrado na notificação recebida. No exemplo de notificação mencionado anteriormente, odata.id_url
Ă©123456
. - [x-request-id_header] deverĂĄ ser substituĂdo pelo valor recebido no header
x-request-id
. No exemplo de notificação mencionado anteriormente, ox-request-id
Ă©bb56a2f1-6aae-46ac-982e-9dcd3581d08e
. - [ts_header] serĂĄ o valor
ts
extraĂdo do headerx-signature
. No exemplo de notificação mencionado anteriormente, ots
Ă©1742505638683
. - ApĂłs aplicar os dados ao template, o resultado seria o seguinte
id:123456;request-id:bb56a2f1-6aae-46ac-982e-9dcd3581d08e;ts:1742505638683;
- Em Suas integraçÔes, selecione a aplicação integrada, clique em Webhooks > Configurar notificação e revele a chave secreta gerada.
- Gere a contrachave para a validação. Para fazer isso, calcule um HMAC com a função de
hash SHA256
em base hexadecimal, utilizando a chave secreta como chave e o template com os valores como mensagem.
$cyphedSignature = hash_hmac('sha256', $data, $key);
const crypto = require('crypto');
const cyphedSignature = crypto
.createHmac('sha256', secret)
.update(signatureTemplateParsed)
.digest('hex');
String cyphedSignature = new HmacUtils("HmacSHA256", secret).hmacHex(signedTemplate);
import hashlib, hmac, binascii
cyphedSignature = binascii.hexlify(hmac_sha256(secret.encode(), signedTemplate.encode()))
- Finalmente, compare a chave gerada com a chave extraĂda do header, certificando-se de que correspondam exatamente. AlĂ©m disso, vocĂȘ pode usar o timestamp extraĂdo do header para comparĂĄ-lo com um timestamp gerado no momento da recepção da notificação, a fim de estabelecer uma tolerĂąncia de atraso na recepção da mensagem.
A seguir, vocĂȘ pode ver exemplos de cĂłdigo completo:
<?php
// Obtain the x-signature value from the header
$xSignature = $_SERVER['HTTP_X_SIGNATURE'];
$xRequestId = $_SERVER['HTTP_X_REQUEST_ID'];
// Obtain Query params related to the request URL
$queryParams = $_GET;
// Extract the "data.id" from the query params
$dataID = isset($queryParams['data.id']) ? $queryParams['data.id'] : '';
// Separating the x-signature into parts
$parts = explode(',', $xSignature);
// Initializing variables to store ts and hash
$ts = null;
$hash = null;
// Iterate over the values to obtain ts and v1
foreach ($parts as $part) {
// Split each part into key and value
$keyValue = explode('=', $part, 2);
if (count($keyValue) == 2) {
$key = trim($keyValue[0]);
$value = trim($keyValue[1]);
if ($key === "ts") {
$ts = $value;
} elseif ($key === "v1") {
$hash = $value;
}
}
}
// Obtain the secret key for the user/application from Mercadopago developers site
$secret = "your_secret_key_here";
// Generate the manifest string
$manifest = "id:$dataID;request-id:$xRequestId;ts:$ts;";
// Create an HMAC signature defining the hash type and the key as a byte array
$sha = hash_hmac('sha256', $manifest, $secret);
if ($sha === $hash) {
// HMAC verification passed
echo "HMAC verification passed";
} else {
// HMAC verification failed
echo "HMAC verification failed";
}
?>
// Obtain the x-signature value from the header
const xSignature = headers['x-signature']; // Assuming headers is an object containing request headers
const xRequestId = headers['x-request-id']; // Assuming headers is an object containing request headers
// Obtain Query params related to the request URL
const urlParams = new URLSearchParams(window.location.search);
const dataID = urlParams.get('data.id');
// Separating the x-signature into parts
const parts = xSignature.split(',');
// Initializing variables to store ts and hash
let ts;
let hash;
// Iterate over the values to obtain ts and v1
parts.forEach(part => {
// Split each part into key and value
const [key, value] = part.split('=');
if (key && value) {
const trimmedKey = key.trim();
const trimmedValue = value.trim();
if (trimmedKey === 'ts') {
ts = trimmedValue;
} else if (trimmedKey === 'v1') {
hash = trimmedValue;
}
}
});
// Obtain the secret key for the user/application from Mercadopago developers site
const secret = 'your_secret_key_here';
// Generate the manifest string
const manifest = `id:${dataID};request-id:${xRequestId};ts:${ts};`;
// Create an HMAC signature
const hmac = crypto.createHmac('sha256', secret);
hmac.update(manifest);
// Obtain the hash result as a hexadecimal string
const sha = hmac.digest('hex');
if (sha === hash) {
// HMAC verification passed
console.log("HMAC verification passed");
} else {
// HMAC verification failed
console.log("HMAC verification failed");
}
import hashlib
import hmac
import urllib.parse
# Obtain the x-signature value from the header
xSignature = request.headers.get("x-signature")
xRequestId = request.headers.get("x-request-id")
# Obtain Query params related to the request URL
queryParams = urllib.parse.parse_qs(request.url.query)
# Extract the "data.id" from the query params
dataID = queryParams.get("data.id", [""])[0]
# Separating the x-signature into parts
parts = xSignature.split(",")
# Initializing variables to store ts and hash
ts = None
hash = None
# Iterate over the values to obtain ts and v1
for part in parts:
# Split each part into key and value
keyValue = part.split("=", 1)
if len(keyValue) == 2:
key = keyValue[0].strip()
value = keyValue[1].strip()
if key == "ts":
ts = value
elif key == "v1":
hash = value
# Obtain the secret key for the user/application from Mercadopago developers site
secret = "your_secret_key_here"
# Generate the manifest string
manifest = f"id:{dataID};request-id:{xRequestId};ts:{ts};"
# Create an HMAC signature defining the hash type and the key as a byte array
hmac_obj = hmac.new(secret.encode(), msg=manifest.encode(), digestmod=hashlib.sha256)
# Obtain the hash result as a hexadecimal string
sha = hmac_obj.hexdigest()
if sha == hash:
# HMAC verification passed
print("HMAC verification passed")
else:
# HMAC verification failed
print("HMAC verification failed")
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"net/http"
"strings"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// Obtain the x-signature value from the header
xSignature := r.Header.Get("x-signature")
xRequestId := r.Header.Get("x-request-id")
// Obtain Query params related to the request URL
queryParams := r.URL.Query()
// Extract the "data.id" from the query params
dataID := queryParams.Get("data.id")
// Separating the x-signature into parts
parts := strings.Split(xSignature, ",")
// Initializing variables to store ts and hash
var ts, hash string
// Iterate over the values to obtain ts and v1
for _, part := range parts {
// Split each part into key and value
keyValue := strings.SplitN(part, "=", 2)
if len(keyValue) == 2 {
key := strings.TrimSpace(keyValue[0])
value := strings.TrimSpace(keyValue[1])
if key == "ts" {
ts = value
} else if key == "v1" {
hash = value
}
}
}
// Get secret key/token for specific user/application from Mercadopago developers site
secret := "your_secret_key_here"
// Generate the manifest string
manifest := fmt.Sprintf("id:%v;request-id:%v;ts:%v;", dataID, xRequestId, ts)
// Create an HMAC signature defining the hash type and the key as a byte array
hmac := hmac.New(sha256.New, []byte(secret))
hmac.Write([]byte(manifest))
// Obtain the hash result as a hexadecimal string
sha := hex.EncodeToString(hmac.Sum(nil))
if sha == hash {
// HMAC verification passed
fmt.Println("HMAC verification passed")
} else {
// HMAC verification failed
fmt.Println("HMAC verification failed")
}
})
}
Após configurar as notificaçÔes, acesse a seção AçÔes necessårias após receber uma notificação para confirmar que elas foram devidamente recebidas.
AçÔes necessårias após receber a notificação
Quando vocĂȘ recebe uma notificação na sua plataforma, o Mercado Pago espera uma resposta para validar que essa recepção foi correta. Para isso, vocĂȘ deve devolver um HTTP STATUS 200 (OK)
ou 201 (CREATED)
.
O tempo de espera para essa confirmação serå de 22 segundos. Se não for enviada essa resposta, o sistema entenderå que a notificação não foi recebida e realizarå uma nova tentativa de envio a cada 15 minutos, até que receba a resposta. Após a terceira tentativa, o prazo serå prorrogado, mas os envios continuarão acontecendo.
ApĂłs responder a notificação, confirmando seu recebimento, vocĂȘ pode obter todas as informaçÔes sobre o evento do tĂłpico payments
notificado fazendo um GET ao endpoint v1/payments/{id}.
Com essas informaçÔes, vocĂȘ poderĂĄ realizar as atualizaçÔes necessĂĄrias na sua plataforma, como por exemplo, atualizar um pagamento aprovado.
AlĂ©m disso, para consultar o status do evento apĂłs a notificação, vocĂȘ pode utilizar os diferentes mĂ©todos dos nossos SDKs para realizar a consulta com o ID que foi enviado na notificação.
MercadoPago.SDK.setAccessToken("ENV_ACCESS_TOKEN");
switch (type) {
case "payment":
Payment payment = Payment.findById(data.id);
break;
case "plan":
Plan plan = Plan.findById(data.id);
break;
case "subscription":
Subscription subscription = Subscription.findById(data.id);
break;
case "invoice":
Invoice invoice = Invoice.findById(data.id);
break;
case "point_integration_wh":
// POST contiene la informaciĂČn relacionada a la notificaciĂČn.
break;
}
mercadopago.configurations.setAccessToken('ENV_ACCESS_TOKEN');
switch (type) {
case 'payment':
const payment = await mercadopago.payment.findById(data.id);
break;
case 'plan':
const plan = await mercadopago.plans.get(data.id);
break;
case 'subscription':
const subscription = await mercadopago.subscriptions.get(data.id);
break;
case 'invoice':
const invoice = await mercadopago.invoices.get(data.id);
break;
case 'point_integration_wh':
// Contiene la informaciĂČn relacionada a la notificaciĂČn.
break;
}
MercadoPago::SDK.configure(access_token: 'ENV_ACCESS_TOKEN')
case payload['type']
when 'payment'
payment = MercadoPago::Payment.search(id: payload['data']['id'])
when 'plan'
plan = MercadoPago::Plan.search(id: payload['data']['id'])
when 'subscription'
subscription = MercadoPago::Subscription.search(id: payload['data']['id'])
when 'invoice'
invoice = MercadoPago::Invoice.search(id: payload['data']['id'])
when 'point_integration_wh'
# Contiene la informaciĂČn relacionada a la notificaciĂČn.
end
MercadoPagoConfig.AccessToken = "ENV_ACCESS_TOKEN";
switch (type)
{
case "payment":
Payment payment = await Payment.FindByIdAsync(payload["data"]["id"].ToString());
break;
case "plan":
Plan plan = await Plan.FindByIdAsync(payload["data"]["id"].ToString());
break;
case "subscription":
Subscription subscription = await Subscription.FindByIdAsync(payload["data"]["id"].ToString());
break;
case "invoice":
Invoice invoice = await Invoice.FindByIdAsync(payload["data"]["id"].ToString());
break;
case "point_integration_wh":
// Contiene la informaciĂČn relacionada a la notificaciĂČn.
break;
}
sdk = mercadopago.SDK("ENV_ACCESS_TOKEN")
notification_type = data["type"]
if notification_type == "payment":
payment = sdk.payment().get(payload["data"]["id"])
elif notification_type == "plan":
plan = sdk.preapproval().get(payload["data"]["id"])
elif notification_type == "subscription":
subscription = sdk.preapproval().get(payload["data"]["id"])
elif notification_type == "invoice":
invoice = sdk.invoice().get(payload["data"]["id"])
elif notification_type == "point_integration_wh":
# Contiene la informaciĂČn relacionada a la notificaciĂČn.
else:
return
accessToken := "{{ACCESS_TOKEN}}"
cfg, err := config.New(accessToken)
if err != nil {
fmt.Println(err)
return
}
client := customer.NewClient(cfg)
switch req.Type {
case "payment":
client := payment.NewClient(cfg)
resource, err = client.Get(context.Background(), resource.ID)
if err != nil {
fmt.Println(err)
return
}
case "plan":
client := preapprovalplan.NewClient(cfg)
resource, err := client.Get(context.Background(), preApprovalPlanID)
if err != nil {
fmt.Println(err)
return
}
case "invoice":
client := invoice.NewClient(cfg)
resource, err := client.Get(context.Background(), req.Data.ID)
if err != nil {
fmt.Println(err)
return
}
case "point_integration_wh":
// Contiene la informaciĂČn relacionada a la notificaciĂČn.
}