Register Webhook
Endpoints to create, list, and remove notification webhooks.
Create Webhook
POST /api/external/webhooksHeaders
| Header | Type | Required | Description |
|---|---|---|---|
Authorization | String | Yes | ApiKey {client_id}:{client_secret} |
Content-Type | String | Yes | application/json |
hmac | String | Yes | HMAC-SHA512 signature of the body (learn more) |
Request Body
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
url | String | Yes | -- | URL to receive notifications (HTTPS by default) |
events | Array | Yes | -- | List of events to subscribe to. Must be a non-empty array with at least one valid event from the table below. Omitting the field returns 400 {"errors": {"events": ["can't be blank"]}}. |
secret | String | No | auto-generated | Key for HMAC-SHA256 signing of deliveries. If omitted, a random value is auto-generated. |
description | String | No | null | Free description of the webhook for internal identification |
allow_insecure | Boolean | No | false | Allow HTTP (non-HTTPS) URLs. Data security is the client's responsibility. |
Available events (PIX, TEF between Minha Konta accounts, and operational webhook test):
| Event | Status body | Description | Dispatch |
|---|---|---|---|
pix.charge.created | created | QR code generated or cash-in initiated | Active |
pix.charge.paid | paid | PIX received and settled | Active |
pix.charge.expired | expired | QR code expired without payment | Active |
pix.charge.cancelled | cancelled | QR code cancelled before payment | Registered, not yet dispatched |
pix.payout.queued | queued | PIX send queued by operational limit | Active |
pix.payout.processing | processing | PIX sent, awaiting confirmation | Active |
pix.payout.confirmed | settled | PIX sent and confirmed (terminal) | Active |
pix.payout.failed | rejected | PIX send rejected (terminal) | Active |
pix.payout.returned | returned | Sent PIX was returned | Active |
pix.refund.requested | requested | Refund request received (BACEN infraction); preventive block created on the client balance | Active |
pix.refund.completed | settled / completed | Defense analysis finalized and refund executed (or released) | Active |
pix.return.received | settled | PIX return received (credit) | Active |
pix.infraction.created | ACKNOWLEDGED | PIX infraction reported by counterparty via BACEN DICT | Active |
pix.infraction.resolved | CLOSED / CANCELLED | Infraction resolved by final decision or counterparty cancellation | Active |
pix.infraction.defense_submitted | defense_submitted | Defense submitted by the merchant | Active |
tef.transfer.sent | settled | TEF between Minha Konta accounts settled for the origin account | Active |
tef.transfer.received | settled | TEF between Minha Konta accounts settled for the destination account | Active |
tef.transfer.failed | failed | TEF between Minha Konta accounts rejected or not settled | Active |
webhook.test | test | Manual test. Available only via Admin/Merchant portal - there is no External API endpoint to dispatch | Manual dispatch |
pix.charge.cancelled is not yet dispatched
The event can be subscribed to, but there is no public QR code cancellation flow currently dispatching this notification type. You may include it in the events array - the API accepts it - but no notification will arrive at your endpoint until the flow is made available.
Any event outside this table is rejected
When creating a webhook, each requested event is validated against the public list of supported events. Unknown events (boleto.paid, account.created, sta.file.*, etc.) return 400 with error events: contains invalid events: ....
Payloads for each event
Full payload examples for each event are in Webhook Payloads.
Example
BODY='{"url":"https://yoursite.com/webhook","events":["pix.charge.paid","pix.payout.confirmed"]}'
HMAC=$(echo -n "$BODY" | openssl dgst -sha512 -hmac "$CLIENT_SECRET" | awk '{print $2}')
curl -X POST https://api.minhakonta.com/api/external/webhooks \
-H "Authorization: ApiKey $CLIENT_ID:$CLIENT_SECRET" \
-H "Content-Type: application/json" \
-H "hmac: $HMAC" \
-d "$BODY"Success Response (201)
{
"worked": true,
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"url": "https://yoursite.com/webhook",
"events": ["pix.charge.paid", "pix.payout.confirmed"],
"secret": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
"description": null,
"is_active": true,
"created_at": "2026-03-07T15:30:00Z"
}Format of id
The webhook id is a canonical UUID v4 (36 characters with hyphens). Use this value directly in DELETE /api/external/webhooks/:id.
Error Response (422)
{
"worked": false,
"detail": "URL deve utilizar HTTPS"
}HTTPS only by default
The webhook URL must use HTTPS. URLs with HTTP will be rejected unless allow_insecure: true is sent on registration.
Important - Webhook Secret
The secret field returned in the registration response is the key used to sign webhook deliveries (HMAC-SHA256). Store this value securely as soon as you receive it - it is what validates that a notification actually came from Minha Konta.
Do NOT confuse with client_secret:
client_secret= authentication for your API requests (Authorization header)- Webhook
secret= verification of received delivery signatures (X-Minha Konta-Signature header)
If you do not send the secret field at registration, a random value will be auto-generated and returned in the response.
See Webhook Validation for examples of how to verify the signature.
Retrieving the secret later
The secret is returned both in POST /api/external/webhooks (creation) and in GET /api/external/webhooks and GET /api/external/webhooks/:id (query). If you lose the value, simply query the webhook again via GET.
In a future version this behavior may be restricted (display only on creation); we recommend storing the secret in a managed secret (vault, SSM, etc.) at registration time.
HTTP URLs
By default, webhooks require HTTPS to guarantee data security in transit. To use HTTP, send allow_insecure: true on registration.
Attention
HTTP URLs transmit data without encryption. The security and confidentiality of the information exchanged is the client's full responsibility. Minha Konta performs webhook delivery normally but assumes no liability for interception or data leakage on unencrypted connections.
Private URLs are always blocked
Even with allow_insecure: true, URLs pointing to private/internal addresses are rejected:
localhost/127.x.x.x- RFC1918:
10.x.x.x,192.168.x.x,172.16-31.x.x - Internal TLDs:
.local,.internal
Webhooks must point to public URLs accessible over the internet.
List Webhooks
GET /api/external/webhooksHeaders
| Header | Type | Required | Description |
|---|---|---|---|
Authorization | String | Yes | ApiKey {client_id}:{client_secret} |
Example
curl -X GET https://api.minhakonta.com/api/external/webhooks \
-H "Authorization: ApiKey $CLIENT_ID:$CLIENT_SECRET"Success Response (200)
Returns an array of objects (not wrapped in {"worked": true}). Each item contains the same fields as registration, including secret.
[
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"url": "https://yoursite.com/webhook",
"events": ["pix.charge.paid", "pix.payout.confirmed"],
"description": null,
"account_id": 10014,
"is_active": true,
"allow_insecure": false,
"status": "active",
"secret": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
"created_at": "2026-03-07T15:30:00",
"updated_at": "2026-03-07T15:30:00"
}
]| Field | Type | Description |
|---|---|---|
id | string (UUID) | Webhook identifier |
url | string | Destination URL |
events | array | Subscribed events |
description | string or null | Optional description |
account_id | integer or null | Associated account. null = webhook global for the API key (if supported) |
is_active | boolean | false = webhook paused, no delivery is dispatched |
allow_insecure | boolean | true = HTTP URLs accepted |
status | string | Derived from is_active - "active" or "inactive" |
secret | string | HMAC-SHA256 key used to sign deliveries. Returned on LIST to allow recovery if the client lost the original value |
created_at / updated_at | string ISO 8601 | Timestamps in UTC, format NaiveDateTime (without Z suffix, e.g., "2026-03-07T15:30:00"). Different from other date fields in webhook payloads (paid_at, returned_at, expired_at) which use DateTime ISO 8601 with trailing Z. Always assume UTC for the webhook object fields |
Remove Webhook
DELETE /api/external/webhooks/:idHeaders
| Header | Type | Required | Description |
|---|---|---|---|
Authorization | String | Yes | ApiKey {client_id}:{client_secret} |
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | String (UUID) | Yes | Webhook ID (UUID v4 returned by the creation endpoint) |
Example
curl -X DELETE https://api.minhakonta.com/api/external/webhooks/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
-H "Authorization: ApiKey $CLIENT_ID:$CLIENT_SECRET"Success Response (204)
HTTP 204 No Content - empty body. The webhook was successfully removed; no pending delivery will be dispatched.
First call: 204. Subsequent: 404
The first successful call returns 204 No Content. Subsequent calls with the same id return 404 { "errors": { "not_found": "webhook not found" } } - the webhook was already removed. This is not strict HTTP idempotency (where every call would return 204) - it is the standard DELETE behavior when the resource ceases to exist. Write your integration to accept both 204 and 404 as "the webhook is no longer active".
Error Response (400)
Invalid id format (not UUID):
{
"errors": {
"bad_request": "id must be a valid UUID"
}
}Error Response (404)
Webhook does not exist or does not belong to your account:
{
"errors": {
"not_found": "webhook not found"
}
}