# /webhook

Registers a new webhook URL for receiving transaction status change notifications.
## Integration Guide
Webhooks allow you to receive real-time HTTP POST notifications when your transactions change status (e.g., from `onHold` to `paid`). Instead of polling `/transaction/status`, you configure a URL and ViaBlocks pushes updates to you.
### Step-by-Step Setup
1. **Register your webhook** — `POST /webhook` with your HTTPS URL and desired events. Save the returned `webhook_id` and `webhook_secret` securely.
2. **Implement your endpoint** — Your server must accept HTTP POST, return 2xx within 10 seconds, and verify the `X-Webhook-Signature` header.
3. **Verify signatures** — Compute `HMAC-SHA256(webhook_secret, raw_body_bytes)` and compare with the hex value in `X-Webhook-Signature` (after removing the `sha256=` prefix). Use constant-time comparison.
4. **Manage your config** — Use `PUT /webhook` (with webhook_id in body) to update, `GET /webhook?webhook_id=xxx` to view, or `DELETE /webhook?webhook_id=xxx` to deactivate.
5. **Rotate secrets** — Use `POST /webhook/rotate-secret` (with webhook_id in body) periodically. Old secret remains valid for 24 hours.
6. **Test connectivity** — Use `POST /webhook/test` (with webhook_id in body) to send a test delivery and verify your endpoint is working.
7. **Monitor deliveries** — Use `GET /webhook/deliveries?webhook_id=xxx` to check delivery history and troubleshoot failures.

### Available Endpoints
| Method | Path | Purpose |
|  --- | --- | --- |
| POST | /webhook | Register webhook URL and get signing secret |
| PUT | /webhook | Update webhook configuration (webhook_id in body) |
| GET | /webhook | List all webhooks or get one (optional ?webhook_id=xxx) |
| DELETE | /webhook | Deactivate webhook (?webhook_id=xxx required) |
| POST | /webhook/rotate-secret | Rotate signing secret (webhook_id in body) |
| POST | /webhook/test | Send test delivery (webhook_id in body) |
| GET | /webhook/deliveries | Query delivery history (?webhook_id=xxx required) |

### Supported Events
| Event Type | Description |
|  --- | --- |
| `transaction.status.onHold` | Transaction placed on hold (compliance/operational review) |
| `transaction.status.inProcess` | Transaction completed internal processing |
| `transaction.status.readyToSend` | Transaction sent to bank for processing |
| `transaction.status.transferred` | Funds transferred to payout network |
| `transaction.status.paid` | Funds paid to beneficiary |
| `transaction.status.cancelled` | Transaction cancelled before completion |
| `transaction.status.void` | Transaction voided (within first minutes, before reaching central system) |
| `transaction.status.expired` | Transaction expired (not completed in allowed time window) |
| `transaction.status.all` | Subscribe to all events above |

### Webhook Payload Format

```json
{
  "event_id": "550e8400-e29b-41d4-a716-446655440000",
  "event_type": "transaction.status.paid",
  "transaction_uuid": "4ed19e29-5a6a-433d-908d-23377fabb617",
  "new_status": "PAID",
  "timestamp": "2025-01-15 19:55:24",
  "id_branch": "A00765",
  "id_receiver": "12345",
  "external_id": "partner-ref-123"
}
```
### HTTP Headers Sent With Each Notification
| Header | Description |
|  --- | --- |
| `Content-Type` | `application/json` |
| `User-Agent` | `ViaBlocks-Webhook/1.0` |
| `X-Webhook-Signature` | `sha256=<64-char-hex>` — HMAC-SHA256 of the body |
| `X-Webhook-Event` | Event type (e.g., `transaction.status.paid`) |
| `X-Webhook-Id` | Unique event ID (UUID v4) for deduplication |

### Signature Verification (Python Example)

```python
import hmac
import hashlib

def verify_signature(payload_body: bytes, secret: str, signature_header: str) -> bool:
    expected = hmac.new(
        key=secret.encode('utf-8'),
        msg=payload_body,
        digestmod=hashlib.sha256
    ).hexdigest()
    received = signature_header.removeprefix('sha256=')
    return hmac.compare_digest(expected, received)
```
### Retry Behavior
If your endpoint returns a non-2xx response or times out, ViaBlocks retries with exponential backoff: 30s, 2m, 10m, 30m, 2h (5 retries max). After 10 consecutive permanently failed events, the webhook is automatically deactivated.
### Best Practices
- Return HTTP 200 quickly (within 10 seconds) — process the payload asynchronously
- Use the `X-Webhook-Id` header to deduplicate notifications on your side
- Store the `webhook_secret` securely; it is only returned at registration time
- Rotate secrets periodically using `/webhook/rotate-secret`
- Monitor `/webhook/deliveries` to catch failures early

## Authentication
Requires `x-client-id` and `x-secret-key` headers.
## Common errors
- `400` Invalid URL format, unsupported event types, or empty events list
- `401` Invalid credentials
- `500` Internal error during registration

Endpoint: POST /webhook
Version: 1.0.0

## Header parameters:

  - `x-client-id` (string, required)
    Unique identifier assigned to the integrating client.

Error codes: required=400001, type=400002, minLength=400003, maxLength=400004

  - `x-secret-key` (string, required)
    Secret authentication key associated with the client.

Error codes: required=400001, type=400002, minLength=400003, maxLength=400004

## Request fields (application/json):

  - `webhook_id` (string, required)
    UUID v4 identifier of the webhook to update. Required for PUT operations.
Error codes: required=400001, type=400002

  - `url` (string)
    New HTTPS endpoint URL for webhook notifications. If provided, triggers regeneration of the webhook_secret. Must use HTTPS scheme and not exceed 2048 characters.
Error codes: type=400002, minLength=400003, maxLength=400004, pattern=400009

  - `events` (array)
    Updated list of transaction status event types to subscribe to. If provided, must contain at least one valid event type.
Error codes: type=400002

  - `active` (boolean)
    Whether the webhook should be active. Set to false to temporarily disable notifications without removing the configuration.
Error codes: type=400002

  - `branches` (array)
    List of branch IDs to receive notifications for. Use ["all"] to receive notifications for all branches. If not provided, the current value is preserved.
Error codes: type=400002

## Response 200 fields (application/json):

  - `status` (string)
    Response status (success)

  - `data` (object)
    Registration result

  - `data.webhook_id` (string)
    UUID v4 identifier for the registered webhook

  - `data.webhook_url` (string)
    The registered webhook URL

  - `data.events` (array)
    List of subscribed event types

  - `data.webhook_secret` (string)
    The generated 64-character hex HMAC signing secret. Store this securely — it is only returned at registration time.

  - `data.active` (boolean)
    Whether the webhook is active (true after registration)

  - `data.created_at` (string)
    ISO 8601 UTC timestamp of when the webhook was registered

## Response 400 fields (application/json):

  - `errors` (array)
    List of validation errorsError catalog for 400 (click to expand)CodeDescription400001URL is required, must use HTTPS scheme, or invalid event type provided400009URL does not match required HTTPS pattern400004URL exceeds maximum length of 2048 characters400010Event type is not in the list of supported event types

  - `errors.status` (string)

  - `errors.code` (number)

  - `errors.message` (string)

  - `errors.details` (string)

## Response 401 fields (application/json):

  - `errors` (array)
    List of authentication errorsError catalog for 401 (click to expand)CodeDescription401000Invalid credentials

  - `errors.status` (string)

  - `errors.code` (number)

  - `errors.message` (string)

  - `errors.details` (string)

## Response 500 fields (application/json):

  - `errors` (array)
    List of server errorsError catalog for 500 (click to expand)CodeDescription500000Internal server error during registration

  - `errors.status` (string)

  - `errors.code` (number)

  - `errors.message` (string)

  - `errors.details` (string)

