Notifications
Query and replay webhook notifications
This endpoint allows you to search your webhook notification history and re-trigger failed or missed webhook deliveries. Useful for debugging integration issues or recovering from temporary webhook endpoint outages.
All notification endpoints are rate-limited to 5 requests per minute per IP address.
List Notifications
GET /v2/notifications
Search and list notifications with optional filters.
Query Parameters
| Name | Type | Description |
|---|---|---|
| e2e_id | string | Bank e2e_id (E* for payments, D* for refunds). Min 20 characters. |
| transaction_id | string | KamiPay transaction ID (kamipay_id or kamipay_refund_id). |
| status | string | Filter by webhook status: done, processing, failed, refunded. |
| type | string | Filter by type: pay (payout), charge (payin), or refund. |
| from_date | datetime | Start date filter (ISO 8601 format). |
| to_date | datetime | End date filter (ISO 8601 format). |
| limit | int | Maximum results to return (1-100). Default: 25. |
| offset | int | Pagination offset. Default: 0. |
Example Request
const params = new URLSearchParams({
type: 'pay',
status: 'failed',
from_date: '2026-01-01T00:00:00Z',
to_date: '2026-01-28T23:59:59Z',
limit: '50'
});
const url = `${baseURL}/v2/notifications?${params}`;
const response = await fetch(url, {
method: "GET",
headers: {
Authorization: `Bearer ${access_token}`,
"Content-Type": "application/json",
},
});import requests
params = {
'type': 'pay',
'status': 'failed',
'from_date': '2026-01-01T00:00:00Z',
'to_date': '2026-01-28T23:59:59Z',
'limit': 50
}
url = f"{base_url}/v2/notifications"
headers = {
'Authorization': f'Bearer {access_token}',
'Content-Type': 'application/json',
}
response = requests.get(url, params=params, headers=headers)package main
import (
"fmt"
"net/http"
"net/url"
)
func main() {
baseURL := "https://api.kamipay.io"
params := url.Values{}
params.Add("type", "pay")
params.Add("status", "failed")
params.Add("from_date", "2026-01-01T00:00:00Z")
params.Add("to_date", "2026-01-28T23:59:59Z")
params.Add("limit", "50")
url := fmt.Sprintf("%s/v2/notifications?%s", baseURL, params.Encode())
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", access_token))
req.Header.Add("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error:", err)
return
}
defer resp.Body.Close()
}Response
{
"notifications": [
{
"notification_id": "a1b2c3d4-0001-4000-8000-000000000001",
"last_updated_at": "2026-01-22T12:30:00+00:00",
"payload": {
"status": "done",
"transaction_hash": null,
"data": {
"operation_id": "txc_01kfktest001done",
"address_in": "0x14eD551D293E41A26E62D605Bc64F9beC154A698",
"usdt_amount": "19.10718",
"brl_amount": "100.00",
"bank_txid": "E27084098202601221953g4eyYfCurMV",
"pix_key": "11999887766",
"name": "Usuario Test Uno"
},
"type": "pay",
"timestamp": "2026-01-22 09:30:00.000000+0000",
"external_id": "ext_payout_done_001",
"kamipay_id": "txc_01kfktest001done",
"service_type": "prepaid"
}
}
],
"total": 1,
"limit": 50,
"offset": 0
}{
"detail": "Invalid e2e_id format: ABC123. Expected format: E* for payments, D* for refunds (min 20 characters)"
}{
"detail": "Incorrect Credentials"
}Get Notification by Transaction ID
GET /v2/notifications/{kp_transaction_id}
Retrieve a single notification by its KamiPay transaction ID.
Path Parameters
| Name | Type | Description |
|---|---|---|
| kp_transaction_id | string | Required. The KamiPay transaction ID. |
Query Parameters
| Name | Type | Description |
|---|---|---|
| type | string | Transaction type hint: pay, charge, or refund. Auto-detected from ID prefix if not provided. |
Auto-detection: The type is automatically detected from the transaction ID prefix:
txc_*: payout (pay)ptxr_*,pir_*: payin (charge)rpt_*: refund
Example Request
const kp_transaction_id = "txc_01jrazd7a9fqpp0bym8km1dbd6";
const url = `${baseURL}/v2/notifications/${kp_transaction_id}`;
const response = await fetch(url, {
method: "GET",
headers: {
Authorization: `Bearer ${access_token}`,
"Content-Type": "application/json",
},
});import requests
kp_transaction_id = "txc_01jrazd7a9fqpp0bym8km1dbd6"
url = f"{base_url}/v2/notifications/{kp_transaction_id}"
headers = {
'Authorization': f'Bearer {access_token}',
'Content-Type': 'application/json',
}
response = requests.get(url, headers=headers)package main
import (
"fmt"
"net/http"
)
func main() {
kpTransactionID := "txc_01jrazd7a9fqpp0bym8km1dbd6"
url := fmt.Sprintf("%s/v2/notifications/%s", baseURL, kpTransactionID)
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", access_token))
req.Header.Add("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error:", err)
return
}
defer resp.Body.Close()
}Response
{
"notification_id": "a1b2c3d4-0001-4000-8000-000000000001",
"last_updated_at": "2026-01-22T12:30:00+00:00",
"payload": {
"status": "done",
"transaction_hash": null,
"data": {
"operation_id": "txc_01kfktest001done",
"address_in": "0x14eD551D293E41A26E62D605Bc64F9beC154A698",
"usdt_amount": "19.10718",
"brl_amount": "100.00",
"bank_txid": "E27084098202601221953g4eyYfCurMV",
"pix_key": "11999887766",
"name": "Usuario Test Uno"
},
"type": "pay",
"timestamp": "2026-01-22 09:30:00.000000+0000",
"external_id": "ext_payout_done_001",
"kamipay_id": "txc_01kfktest001done",
"service_type": "prepaid"
}
}{
"detail": "Invalid transaction ID format: invalid_id. Expected prefixes: txc_, txp_, dqr_, lnk_, sqr_, ptxr_, pir_, rpt_, rbc_"
}{
"detail": "Notification not found"
}Get Refunds for Transaction
GET /v2/notifications/{kp_transaction_id}/refunds
Find all refund notifications associated with a transaction.
Path Parameters
| Name | Type | Description |
|---|---|---|
| kp_transaction_id | string | Required. The original KamiPay transaction ID. |
Example Request
const kp_transaction_id = "txc_01jrazd7a9fqpp0bym8km1dbd6";
const url = `${baseURL}/v2/notifications/${kp_transaction_id}/refunds`;
const response = await fetch(url, {
method: "GET",
headers: {
Authorization: `Bearer ${access_token}`,
"Content-Type": "application/json",
},
});import requests
kp_transaction_id = "txc_01jrazd7a9fqpp0bym8km1dbd6"
url = f"{base_url}/v2/notifications/{kp_transaction_id}/refunds"
headers = {
'Authorization': f'Bearer {access_token}',
'Content-Type': 'application/json',
}
response = requests.get(url, headers=headers)package main
import (
"fmt"
"net/http"
)
func main() {
kpTransactionID := "txc_01jrazd7a9fqpp0bym8km1dbd6"
url := fmt.Sprintf("%s/v2/notifications/%s/refunds", baseURL, kpTransactionID)
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", access_token))
req.Header.Add("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error:", err)
return
}
defer resp.Body.Close()
}Response
{
"original_transaction_id": "txc_01kfktest004refunded",
"refunds": [
{
"notification_id": "c1b2c3d4-0001-4000-8000-000000000001",
"last_updated_at": "2026-01-22T13:00:00+00:00",
"payload": {
"kamipay_refund_id": "rpt_01kfktest001refund",
"kamipay_id": "txc_01kfktest004refunded",
"external_id": "ext_payout_refunded",
"refund_bank_txid": "D14796606202601222051497837G0003",
"original_bank_txid": "E270840982026012219462noRErpDQMV",
"service_type": "prepaid",
"type": "pay",
"status": "refunded",
"refunded_brl_amount": "171.93",
"refunded_usdt_amount": "32.850973",
"original_brl_amount": "171.93",
"original_usdt_amount": "32.850973",
"original_recipient_name": "Usuario Refund Test",
"timestamp": "2026-01-22 10:00:00.000000+0000"
}
}
],
"total": 1
}{
"detail": "No refunds found for this transaction"
}Replay Single Notification
POST /v2/notifications/{kp_transaction_id}/replay
Queue a single notification for replay. The notification will be re-delivered to your webhook URL.
Path Parameters
| Name | Type | Description |
|---|---|---|
| kp_transaction_id | string | Required. The KamiPay transaction ID to replay. |
The notification type is auto-detected from the transaction ID prefix. Ensure you're using the correct transaction ID format.
Example Request
const kp_transaction_id = "txc_01jrazd7a9fqpp0bym8km1dbd6";
const url = `${baseURL}/v2/notifications/${kp_transaction_id}/replay`;
const response = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${access_token}`,
"Content-Type": "application/json",
},
});import requests
kp_transaction_id = "txc_01jrazd7a9fqpp0bym8km1dbd6"
url = f"{base_url}/v2/notifications/{kp_transaction_id}/replay"
headers = {
'Authorization': f'Bearer {access_token}',
'Content-Type': 'application/json',
}
response = requests.post(url, headers=headers)package main
import (
"fmt"
"net/http"
)
func main() {
kpTransactionID := "txc_01jrazd7a9fqpp0bym8km1dbd6"
url := fmt.Sprintf("%s/v2/notifications/%s/replay", baseURL, kpTransactionID)
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", access_token))
req.Header.Add("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error:", err)
return
}
defer resp.Body.Close()
}Response
{
"status": "queued",
"notification_id": "a1b2c3d4-0001-4000-8000-000000000001",
"kp_transaction_id": "txc_01kfktest001done"
}{
"detail": "Invalid transaction ID format"
}{
"detail": "Notification not found"
}{
"status": "already_queued",
"notification_id": "a1b2c3d4-0001-4000-8000-000000000001",
"kp_transaction_id": "txc_01kfktest001done"
}Batch Replay Notifications
POST /v2/notifications/replay
Queue multiple notifications for replay by date range. All notifications matching the criteria will be re-delivered to your webhook URL.
Request Body
| Name | Type | Description |
|---|---|---|
| start_date | datetime | Required. Start of date range (ISO 8601 format). |
| end_date | datetime | Required. End of date range (ISO 8601 format). |
| type | string | Required. Transaction type: pay, charge, or refund. |
Maximum date range is 24 hours. For longer periods, make multiple requests with different date ranges.
Example Request
const url = `${baseURL}/v2/notifications/replay`;
const body = {
start_date: "2026-01-15T00:00:00Z",
end_date: "2026-01-15T23:59:59Z",
type: "pay"
};
const response = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${access_token}`,
"Content-Type": "application/json",
},
body: JSON.stringify(body)
});import requests
url = f"{base_url}/v2/notifications/replay"
body = {
'start_date': '2026-01-15T00:00:00Z',
'end_date': '2026-01-15T23:59:59Z',
'type': 'pay'
}
headers = {
'Authorization': f'Bearer {access_token}',
'Content-Type': 'application/json',
}
response = requests.post(url, json=body, headers=headers)package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
func main() {
url := fmt.Sprintf("%s/v2/notifications/replay", baseURL)
requestBody, _ := json.Marshal(map[string]interface{}{
"start_date": "2026-01-15T00:00:00Z",
"end_date": "2026-01-15T23:59:59Z",
"type": "pay",
})
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(requestBody))
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", access_token))
req.Header.Add("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error:", err)
return
}
defer resp.Body.Close()
}Response
Notifications queued successfully
{
"status": "queued",
"total_found": 2,
"queued_count": 2,
"already_queued_count": 0,
"failed_count": 0,
"notifications": [
{
"notification_id": "b1b2c3d4-0001-4000-8000-000000000001",
"kp_transaction_id": "ptxr_01kfktest001done",
"status": "queued",
"error": null
},
{
"notification_id": "b1b2c3d4-0002-4000-8000-000000000002",
"kp_transaction_id": "ptxr_01kfktest002proc",
"status": "already_queued",
"error": null
}
]
}{
"detail": "'end_date' must be after 'start_date'"
}{
"detail": "Date range cannot exceed 24 hours (got 48.0 hours)"
}Response Status Values
| Status | Description |
|---|---|
queued | Notifications were successfully queued for replay. |
already_queued | All notifications were already queued from a previous request. |
none_found | No notifications found matching the criteria. |
partial_failure | Some notifications failed to queue. Check individual notification errors. |