Webhooks API via OAuth 2.0

Configure and use the SePay Webhooks API through OAuth 2.0 authentication. Receive real-time notifications for transactions and account events securely.

||

Introduction

SePay's Webhooks API allows you to manage webhooks to receive real-time transaction notifications. Webhooks are an efficient way to automate payment processes, helping your system receive notifications immediately when new transactions occur.

To use this API, you need the corresponding permissions in the Access Token scope: webhook:read to view, webhook:write to create/update, and webhook:delete to delete webhooks.


Endpoints

The Webhooks API provides the following endpoints:

GET
/api/v1/webhooks
GET
/api/v1/webhooks/{id}
POST
/api/v1/webhooks
PATCH
/api/v1/webhooks/{id}
DELETE
/api/v1/webhooks/{id}

Get Webhook List

GET
https://my.sepay.vn/api/v1/webhooks
Authorization: Bearer {YOUR_ACCESS_TOKEN}

This endpoint returns a list of webhooks for your company. You can filter results by various criteria.

Required permissions:

  • Scope: webhook:read
  • User permission: Webhooks (View webhooks list)

Query parameters:

webhook_urlstring
Filter by webhook URL (partial search)
api_keystring
Filter by API key
activeinteger
Filter by active status (0: inactive, 1: active)
pageinteger
Page number, starting from 1
limitinteger
Number of results per page
>
>
>
>
>
curl -G "https://my.sepay.vn/api/v1/webhooks" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
--data-urlencode "active=1" \
--data-urlencode "page=1" \
--data-urlencode "limit=20"
RESPONSE
{
    "status": "success",
    "data": [
        {
            "id": 23,
            "bank_account_id": 19,
            "name": "Online shop integration",
            "event_type": "In_only",
            "authen_type": "HMAC_SHA256",
            "webhook_url": "https://example.com/webhook/payment",
            "is_verify_payment": true,
            "skip_if_no_code": true,
            "prefix_filters": [],
            "retry_conditions": { "non_2xx_status_code": 0 },
            "only_va": true,
            "va_mode": "list",
            "bank_mode": "single",
            "alert_threshold": 3,
            "alert_event_types": ["failure", "recovery"],
            "active": true,
            "created_at": "2025-02-15 14:23:56",
            "secret_key": "whsec_a7c3b4e5f6a7b8c9d0e1f2a3b4c5d6e7",
            "request_content_type": "Json",
            "bank_sub_account_ids": [25, 26]
        },
        {
            "id": 22,
            "bank_account_id": 0,
            "name": "Company-wide webhook",
            "event_type": "All",
            "authen_type": "OAuth2.0",
            "webhook_url": "https://crm.example.com/webhook/transactions",
            "is_verify_payment": false,
            "skip_if_no_code": false,
            "prefix_filters": ["SEVQR", "ORDER"],
            "retry_conditions": { "non_2xx_status_code": 0 },
            "only_va": false,
            "va_mode": "all",
            "bank_mode": "multi",
            "alert_threshold": null,
            "alert_event_types": null,
            "active": true,
            "created_at": "2025-02-10 09:45:32",
            "oauth2_client_id": "client_id_example",
            "oauth2_client_secret": "client_secret_example",
            "oauth2_access_token_url": "https://crm.example.com/oauth/token"
        }
    ],
    "meta": {
        "pagination": {
            "total": 5,
            "per_page": 20,
            "current_page": 1,
            "last_page": 1
        }
    }
}

Get Webhook Details

GET
https://my.sepay.vn/api/v1/webhooks/{id}
Authorization: Bearer {YOUR_ACCESS_TOKEN}

This endpoint returns detailed information of a webhook based on ID.

Required permissions:

  • Scope: webhook:read
  • User permission: Webhooks (View webhooks list)

Path parameters:

idintegerrequired
Webhook ID
>
>
curl -X GET "https://my.sepay.vn/api/v1/webhooks/{id}" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
RESPONSE
{
    "status": "success",
    "data": {
        "id": 23,
        "bank_account_id": 19,
        "name": "Online shop integration",
        "event_type": "In_only",
        "authen_type": "Api_Key",
        "webhook_url": "https://example.com/webhook/payment",
        "is_verify_payment": true,
        "skip_if_no_code": true,
        "prefix_filters": [],
        "retry_conditions": {
            "non_2xx_status_code": 0
        },
        "only_va": true,
        "va_mode": "list",
        "bank_mode": "single",
        "alert_threshold": null,
        "alert_event_types": null,
        "active": true,
        "created_at": "2025-02-15 14:23:56",
        "api_key": "a7c3b4e5f6a7b8c9d0e1f2a3b4c5d6e7",
        "request_content_type": "Json",
        "bank_sub_account_ids": [25, 26]
    }
}

Create New Webhook

POST
https://my.sepay.vn/api/v1/webhooks
Authorization: Bearer {YOUR_ACCESS_TOKEN}
Content-Type: application/json

This endpoint allows you to create a new webhook to receive transaction notifications.

Required permissions:

  • Scope: webhook:write
  • User permission: Webhooks (Add webhooks)

Request parameters:

bank_account_idinteger
Bank account ID. Required when `bank_mode` is not provided.
bank_account_idsarray
List of bank account IDs. Required when `bank_mode=multi`.
bank_modestring
`single`: one account. `multi`: multiple accounts. `all`: every account in the company.
namestringrequired
Webhook name
event_typestringrequired
Event type: `All`, `In_only`, `Out_only`
authen_typestringrequired
`No_Authen`, `Api_Key`, `HMAC_SHA256`, `OAuth2.0`
webhook_urlstringrequired
Webhook receiving URL. Must be a public URL. Internal or localhost IPs are not allowed.
is_verify_paymentintegerrequired
Verify payment (0 or 1)
skip_if_no_codeinteger
Skip transactions with no payment code (0 or 1)
activeinteger
Active status (0 or 1)
retry_conditionsobject
Retry conditions, e.g. `{"non_2xx_status_code": 1}`
prefix_filtersarray<string>
Filter by payment code prefix. Webhook fires only when the code starts with one of the prefixes. Up to 50 prefixes, 100 chars each.
only_vainteger
Only receive transactions on virtual accounts (0 or 1)
va_modestring
`all`: primary account and virtual accounts. `list`: only listed virtual accounts. `none`: primary account only.
bank_sub_account_idsarray<integer>
Virtual account IDs. Required when `only_va=1` or `va_mode=list`.
alert_thresholdinteger
Consecutive failure count before an alert fires (1-20). Omit to disable alerts.
alert_event_typesarray<string>
Alert event types: `failure`, `recovery`.
alert_channel_idsarray<integer>
IDs of alert channels (Telegram, Email, Slack, Discord) already created in the Webhooks page.

Additional parameters per authentication type:

Api_Key

  • api_key (required): API Key, max 1000 chars
  • request_content_type (required): Json, multipart_form-data, or application_x-www-form-urlencoded

HMAC_SHA256 (recommended)

  • secret_key (required): Secret Key, max 500 chars. SePay signs the payload with HMAC-SHA256 and sends the signature in the X-SePay-Signature header, alongside X-SePay-Timestamp.
  • request_content_type (required): Json, multipart_form-data, or application_x-www-form-urlencoded

See the HMAC-SHA256 section in the SePay Webhooks documentation for the signature verification guide.

OAuth2.0

  • oauth2_access_token_url (required): Access token URL. Must be a public URL.
  • oauth2_client_id (required): Client ID
  • oauth2_client_secret (required): Client Secret

No_Authen

  • request_content_type (required): Json, multipart_form-data, or application_x-www-form-urlencoded
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
curl -X POST "https://my.sepay.vn/api/v1/webhooks" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-d '{
"bank_account_id": 19,
"name": "Online shop integration",
"event_type": "In_only",
"authen_type": "Api_Key",
"webhook_url": "https://example.com/webhook/payment",
"is_verify_payment": 1,
"skip_if_no_code": 1,
"active": 1,
"only_va": 1,
"bank_sub_account_ids": [25, 26],
"retry_conditions": {"non_2xx_status_code": 1},
"api_key": "a7c3b4e5f6a7b8c9d0e1f2a3b4c5d6e7",
"request_content_type": "Json"
}'
RESPONSE
{
    "status": "success",
    "message": "Webhook created successfully",
    "data": { "id": 23 }
}

Update Webhook

PATCH
https://my.sepay.vn/api/v1/webhooks/{id}
Authorization: Bearer {YOUR_ACCESS_TOKEN}
Content-Type: application/json

This endpoint allows you to update information of an existing webhook.

Required permissions:

  • Scope: webhook:write
  • User permission: Webhooks (Edit webhooks)

Path parameters:

idintegerrequired
Webhook ID

Request parameters: same as when creating a webhook, but all are optional. Only send the fields you want to change.

Notes:

  • Webhooks with bank_mode=multi or bank_mode=all cannot have bank_account_id changed via the API. Use the web UI instead.
  • bank_account_id=0 is only accepted when sent together with bank_mode=all.
>
>
>
>
>
>
>
curl -X PATCH "https://my.sepay.vn/api/v1/webhooks/{id}" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-d '{
"active": 0,
"skip_if_no_code": 0
}'
RESPONSE
{
    "status": "success",
    "message": "Webhook updated successfully",
    "data": { "active": 0, "skip_if_no_code": 0 }
}

Delete Webhook

DELETE
https://my.sepay.vn/api/v1/webhooks/{id}
Authorization: Bearer {YOUR_ACCESS_TOKEN}

This endpoint allows you to delete a webhook.

Required permissions:

  • Scope: webhook:delete
  • User permission: Webhooks (Delete webhooks)

Path parameters:

idintegerrequired
Webhook ID
>
>
curl -X DELETE "https://my.sepay.vn/api/v1/webhooks/{id}" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
RESPONSE
Code
1
HTTP/1.1 204 No Content

Example: HMAC-SHA256 webhook

{
  "bank_account_id": 19,
  "name": "HMAC webhook",
  "event_type": "In_only",
  "authen_type": "HMAC_SHA256",
  "webhook_url": "https://example.com/webhook/payment",
  "secret_key": "whsec_a1b2c3d4e5f6...",
  "request_content_type": "Json",
  "is_verify_payment": 1
}

SePay signs the payload with HMAC-SHA256 and sends the signature in the X-SePay-Signature header, alongside X-SePay-Timestamp. See the HMAC-SHA256 section in the SePay Webhooks documentation for verification.


Example: multi-account webhook

{
  "bank_account_ids": [19, 20, 21],
  "bank_mode": "multi",
  "name": "Multi-account webhook",
  "event_type": "In_only",
  "authen_type": "Api_Key",
  "webhook_url": "https://example.com/webhook/payment",
  "api_key": "a7c3b4e5f6a7b8c9d0e1f2a3b4c5d6e7",
  "request_content_type": "Json",
  "is_verify_payment": 1
}

Apply to every bank account in the company:

{
  "bank_mode": "all",
  "name": "Company-wide webhook",
  "event_type": "All",
  "authen_type": "HMAC_SHA256",
  "webhook_url": "https://example.com/webhook/all",
  "secret_key": "whsec_...",
  "request_content_type": "Json",
  "is_verify_payment": 1
}

Example: enable alerts

Send alerts when the webhook fails consecutively and again when it recovers, to channels pre-created in the Webhooks page (Alert Channels tab):

{
  "bank_account_id": 19,
  "name": "Webhook with alerts",
  "event_type": "In_only",
  "authen_type": "HMAC_SHA256",
  "webhook_url": "https://example.com/webhook/payment",
  "secret_key": "whsec_...",
  "request_content_type": "Json",
  "is_verify_payment": 1,
  "alert_threshold": 3,
  "alert_event_types": ["failure", "recovery"],
  "alert_channel_ids": [5, 7]
}

Error Codes

400validation_error

Invalid input (e.g. `webhook_url` not public, `bank_account_id=0` without `bank_mode=all`).

401unauthorized

Token is invalid or expired.

403forbidden

No permission to access this resource.

404not_found

Webhook not found.

500delete_failed

Delete failed. Safe to retry.