Skip to content

Webhook ​

Webhook event là các thông báo được kích hoạt bởi các thao tác cụ thể trong Bahn, cho phép backend của bạn phản ứng khi các thao tác đó xảy ra — chẳng hạn như một thanh toán thành công, một thanh toán bị hủy, hoặc một khoản hoàn tiền được xử lý.

Gửi nhận (delivery) ​

Bahn gửi webhook event dưới dạng một request JWS JSON Serialization đến endpoint HTTPS đã đăng ký của bạn.

POST <your-webhook-url>
Content-Type: application/jose+json

Request body là một đối tượng JWS đã ký ở định dạng JSON Serialization:

json
{
  "payload": "<base64url-encoded event JSON>",
  "signatures": [
    {
      "protected": "<base64url-encoded header>",
      "signature": "<base64url-encoded signature>"
    }
  ]
}

Để đọc event, giải mã base64url trường payload. Giá trị đã giải mã là JSON thông báo. Ví dụ:

json
{
  "payload": "eyJtZXJjaGFudF9pZCI6ImNfdGlja2V0IiwiZXZlbnRfaWQiOiI3NDI1NDhlNy00YzUzLTQwMjAtYmMyOC01NjU2N2ExYWY2ZDUiLCJldmVudF9uYW1lIjoicGF5bWVudF9pbnRlbnQuc3RhdHVzLnN1Y2NlZWRlZCIsImRhdGFfdHlwZSI6InBheW1lbnRfaW50ZW50IiwiZGF0YSI6eyJpZCI6ImM2YWY4ODU1LWNiZjYtNDJhMC05YzQ0LTM2ZGUwZGUwYTc5MyIsInN0YXR1cyI6InN1Y2NlZWRlZCIsImFtb3VudCI6IjE0MDAwIiwiY3VycmVuY3kiOiI3MDQiLCJwYXltZW50X21ldGhvZF9pZCI6IjAxOWNmNjY4LThiODktN2UyMi1hNmUzLWI4ODllY2M1NGI4NyIsImxhdGVzdF9jaGFyZ2VfaWQiOiI0ZjViMWFkNC0xYmI3LTQ0NTItOTMwMS04YWExMTI0MTc0YjAiLCJtZXRhZGF0YSI6eyJrZXlfMCI6InN0cmluZyIsImtleV8xIjoic3RyaW5nIn0sImNyZWF0ZWRfYXQiOiIyMDI2LTAzLTE2VDExOjI5OjI4Ljc5MzUxODYwMloiLCJ1cGRhdGVkX2F0IjoiMjAyNi0wMy0xNlQxMToyOToyOC44MjAwNjNaIiwiY2FuY2VsZWRfYXQiOm51bGx9LCJwdWJsaXNoZWRfYXQiOiIyMDI2LTAzLTE2VDE4OjI5OjM2LjI4MzIxNzA2NyswNzowMCJ9",
  "signatures": [
    {
      "protected": "eyJhbGciOiJFUzI1NiIsImlhdCI6MTc3MzY2MDU3Niwia2lkIjoiU2tQNDFYVXc3aGlUa0FmNlptYmU0byIsInR5cCI6IkpXUyIsInVybCI6Imh0dHBzOi8vYm4uY2FrZWRpZ2liYW5rLnRlY2gvbWVyY2hhbnQtc2ltdWxhdGlvbi93ZWJob29rIn0",
      "signature": "HT-RvOtf0Y0cUoCCEBRMkBAa1Q00d2ZxWOsOo0E0mH47MCvOsBGe87aZr4fV-EhEsnOtZWRg-kavcgzGLrtNSw"
    }
  ]
}
json
{
  "merchant_id": "c_ticket",
  "event_id": "742548e7-4c53-4020-bc28-56567a1af6d5",
  "event_name": "payment_intent.status.succeeded",
  "data_type": "payment_intent",
  "data": {
    "id": "c6af8855-cbf6-42a0-9c44-36de0de0a793",
    "status": "succeeded",
    "amount": "14000",
    "currency": "704",
    "payment_method_id": "019cf668-8b89-7e22-a6e3-b889ecc54b87",
    "latest_charge_id": "4f5b1ad4-1bb7-4452-9301-8aa1124174b0",
    "metadata": {
      "key_0": "string",
      "key_1": "string"
    },
    "created_at": "2026-03-16T11:29:28.793518602Z",
    "updated_at": "2026-03-16T11:29:28.820063Z",
    "canceled_at": null
  },
  "published_at": "2026-03-16T18:29:36.283217067+07:00"
}

Các trường trong thông báo ​

TrườngKiểuMô tả
merchant_idstringID của merchant mà event này thuộc về.
event_idstringĐịnh danh duy nhất cho lần gửi event này (UUID). Dùng giá trị này để loại bỏ trùng lặp.
event_namestringTên của event (ví dụ payment_intent.status.succeeded). Xem Sự kiện để biết danh sách đầy đủ.
data_typestringLoại đối tượng trong data. Một trong: payment_intent, charge, refund, authorization, transaction.
dataobjectMột bản chụp (snapshot) của resource tại thời điểm event được kích hoạt. Cấu trúc phụ thuộc vào data_type. Xem Sự kiện để biết tài liệu tham chiếu trường đầy đủ.
published_atstringTimestamp ISO 8601 của thời điểm event được publish.

Bắt đầu ​

Đăng ký endpoint của bạn ​

Để nhận webhook event, hãy expose một endpoint HTTPS trong backend của bạn chấp nhận các request POST và trả về mã trạng thái 200 khi thành công. Webhook endpoint của bạn được đăng ký trong quá trình onboarding merchant — hãy cung cấp cho Bahn URL endpoint HTTPS của bạn vào lúc đó.

INFO

Endpoint của bạn phải phản hồi với HTTP 200 để xác nhận đã nhận được. Bất kỳ mã trạng thái nào khác đều được coi là gửi thất bại và sẽ kích hoạt một lần retry.

Xác minh chữ ký ​

Mọi request đều được Bahn ký. Trước khi xử lý bất kỳ event nào, hãy xác minh chữ ký JWS để xác nhận request thực sự được gửi bởi Bahn và không bị can thiệp.

Xem Chữ ký webhook để biết đầy đủ các bước xác minh. Từ chối bất kỳ request nào không vượt qua việc xác minh chữ ký.

Xử lý trùng lặp ​

Việc gửi không hoàn toàn đảm bảo chỉ một lần — trong một số trường hợp hiếm, một event có thể được gửi nhiều hơn một lần. Luôn kiểm tra trường event_id và an toàn bỏ qua các event bạn đã xử lý trước đó.

Retry ​

WIP

Developers