Verifi RDR Webhook Event
6 min
Webhook Headers
- X-Butter-Webhook-Type
- Value: verifi.rdr
- Description: The type of webhook event.
- X-Butter-Webhook-Signature
- Description: A signed hash of the webhook body used to validate the authenticity. Examples of calculating signature hashes can be found below in the Webhook Signature Code Snippets section.
- X-Butter-Webhook-Deduplication-ID
- Description: An Idempotent ID to verify if you have received the same webhook before.
- X-Butter-Webhook-Created
- Description: Time webhook was created, additionally used for calculating the signature hash.
Webhook Body
{
"id": "event_ac7d19a7863bec06d7b1ae56",
"object": "verifi.rdr",
"data": {
"case": {
"date": "2024-01-01",
"amount": 19.99,
"currency": "USD",
},
"authorization_code": "12345D",
"acquirer_reference_number": "78709066262500100248962",
"refunded": true,
"original_transaction": {
"date": "2023-11-01",
"amount": 19.99,
"currency": "USD"
},
"card": {
"bin": 424242,
"last4": 4242
},
"network": {
"merchant_id": 123456789,
"scheme": "visa",
"transaction_id": "103431687468834",
"reason_code": "13.2",
"merchant_order_id": "string",
"merchant_category_code": 5411
},
"psp_transaction": {
"type": "charge",
"id": "ch_3MmlLrLkdIwHu7ix0snN0B15"
}
},
"created_at": 1735689600
}Field Descriptors
- case.date
- Type: string
- Format: YYYY-MM-DD
- Description: The date when the Verifi case was opened.
- Nullable: false
- case.amount
- Type: float
- Description: The disputed amount as reported by the card network.
- Nullable: false
- case.currency
- Type: string
- Format: ISO-4217
- Description: The currency of the original transaction as reported by the card network.
- Nullable: false
- authorization_code
- Type: string
- Description: The authorization code of the original transaction as reported by the card network.
- Nullable: false
- acquirer_reference_number
- Type: string
- Description: The Acquirer Reference Number (ARN) of the original transaction as reported by the card network.
- Nullable: false
- refunded
- Type: boolean
- Description: Indicates whether the transaction was refunded by an applied RDR rule.
- Nullable: false
- original_transaction.date
- Type: string
- Format: YYYY-MM-DD
- Description: The date of the original transaction as reported by the card network.
- Nullable: false
- original_transaction.amount
- Type: float
- Description: The amount of the original transaction as reported by the card network.
- Nullable: false
- original_transaction.currency
- Type: string
- Format: ISO-4217
- Description: The currency of the original transaction as reported by the card network.
- Nullable: false
- card.bin
- Type: integer
- Description: The first six to eight digits of the card used to make the transaction as reported by the card network.
- Nullable: false
- card.last4
- Type: integer
- Description: The last four digits of the card used to make the transaction as reported by the card network.
- Nullable: false
- network.merchant_id
- Type: integer
- Description: The merchant ID (MID) used during processing of the transaction as reported by the card network.
- Nullable: false
- network.scheme
- Type: string
- Description: The card network where the transaction was made.
- Nullable: false
- Enums:
- visa
- network.reason_code
- Type: string
- Description: The reason the transaction was disputed as reported by the card network.
- Enums:
- 10.4 (Other Fraud - Card Absent Environment)
- 10.5 (Visa Fraud Monitoring Program)
- 11.1 (Card Recovery Bulletin)
- 11.2 (Declined Authorization)
- 11.3 (No Authorization)
- 12.1 (Late Presentment)
- 12.2 (Incorrect Transaction Code)
- 12.3 (Incorrect Currency)
- 12.4 (Incorrect Account Number)
- 12.5 (Incorrect Amount)
- 12.6.1 (Duplicate processing)
- 12.6.2 (Paid by other means)
- 13.1 (Merchandise/Services Not Received)
- 13.8 (Original Credit Transaction Not Accepted)
- 13.9 (Non-Receipt of Cash or Load Transaction Value)
- 13.2 (Cancelled Recurring)
- 13.3 (Not as Described or Defective Merchandise/Services)
- 13.4 (Counterfeit Merchandise)
- 13.5 (Misrepresentation)
- 13.6 (Credit not processed)
- 13.7 (Cancelled Merchandise/Services)
- Nullable: false
- network.merchant_order_id
- Type: string
- Description: The order ID reported to the card network by the processor.
- Nullable: true
- network.merchant_category_code
- Type: integer
- Description: The Merchant Category Code (MCC) as reported by the card network.
- Nullable: false
- psp_transaction
- Type: object
- Description: Contains information about the linked transaction in the respective PSP.
- Nullable: true
- psp_transaction.type
- Type: string
- Description: Type of ID used for linking the disputed transaction to the transaction in the respective PSP.
- Enums
- charge
- Nullable: false
- psp_transaction.id
- Type: string
- Description: The ID linking the disputed transaction to the transaction in the respective PSP.
- created_at
- Type: integer
- Description: A unix timestamp of when the webhook was created.
Webhook Signature Code Snippets
import json
import hashlib
import hmac
from time import time
def verify_webhook_signature(body: dict, headers: dict, signing_key: str) -> bool:
payload = json.dumps(body, separators=(",", ":"))
provided_signature = headers.get("X-Butter-Webhook-Signature")
created_at = headers.get("X-Butter-Webhook-Created")
message = f"{payload}+{created_at}".encode("utf-8")
cacluated_signature = hmac.new(signing_key.encode("utf-8"), message, hashlib.sha256).hexdigest()
return provided_signature == cacluated_signature
const crypto = require('crypto');
function verifyWebhookSignature(body, headers, signingKey) {
const payload = JSON.stringify(body);
const createdAt = headers["X-Butter-Webhook-Created"];
const providedSignature = headers["X-Butter-Webhook-Signature"];
const hmac = crypto.createHmac('SHA256', signingKey);
const data = hmac.update(Buffer.from(`${JSON.stringify(body)}+${createdAt}`));
const calculatedSignature = data.digest('hex');
return (calculatedSignature == providedSignature) ? true : false;
}
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"strconv"
"time"
)
func verifyWebhookSignature(headers map[string]string, body string, signingKey string) bool {
createdAtStr := headers["X-Butter-Webhook-Expires"]
createdAt, err := strconv.ParseInt(createdAtStr, 10, 64)
if err != nil {
fmt.Println("Error parsing createdAt timestamp:", err)
return false
}
providedSignature := headers["X-Butter-Webhook-Signature"]
hmacSha256 := hmac.New(sha256.New, []byte(signingKey))
_, err = hmacSha256.Write([]byte(body + "+" + createdAtStr))
if err != nil {
fmt.Println("Error computing HMAC:", err)
return false
}
calculatedSignature := hex.EncodeToString(hmacSha256.Sum(nil))
if calculatedSignature != providedSignature {
return false
}
return true
}
import java.nio.charset.StandardCharsets;
import java.util.Map;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import com.fasterxml.jackson.databind.ObjectMapper;
public class WebhookVerifier {
public static boolean verifyWebhookSignature(Map<String, String> headers, Object body, String signingKey) {
String createdAtStr = headers.get("X-Butter-Webhook-Created");
long createdAt = Long.parseLong(createdAtStr);
String providedSignature = headers.get("X-Butter-Webhook-Signature");
try {
ObjectMapper objectMapper = new ObjectMapper();
String payload = objectMapper.writeValueAsString(body);
Mac hmac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(signingKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
hmac.init(secretKeySpec);
byte[] payloadBytes = (payload + "+" + createdAtStr).getBytes(StandardCharsets.UTF_8);
byte[] signatureBytes = hmac.doFinal(payloadBytes);
String calculatedSignature = bytesToHex(signatureBytes);
if (!calculatedSignature.equals(providedSignature)) {
return false;
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
private static String bytesToHex(byte[] bytes) {
StringBuilder hexString = new StringBuilder();
for (byte b : bytes) {
String hex = Integer.toHexString(0xFF & b);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
}
}