Skip to content

Webhook Endpoints API

The Webhook Endpoints API allows you to manage webhook endpoints that receive real-time notifications when events occur in your TreasuryPath account.

Endpoints


List Webhook Endpoints

Retrieve all webhook endpoints for a company.

Endpoint

GET /api/v1/companies/{company_id}/webhook_endpoints

Headers

Authorization: Bearer {jwt_token}

Query Parameters

Parameter Type Required Description
active boolean No Filter by active status

Example Request

curl -X GET "https://api.treasurypath.com/api/v1/companies/{company_id}/webhook_endpoints" \
  -H "Authorization: Bearer {jwt_token}"

Success Response (200 OK)

{
  "data": [
    {
      "id": "Z2lkOi8vd2FsbGV0LWFwcC9XZWJob29rRW5kcG9pbnQvMQ",      
      "url": "https://your-app.com/webhooks/treasurypath",
      "active": true,
      "created_at": "2025-01-15T10:30:00Z",
      "updated_at": "2025-01-15T10:30:00Z",
      "subscribed_events_count": 3,      
      "webhook_subscribed_events": [
        {
          "id": "Z2lkOi8vd2FsbGV0LWFwcC9XZWJob29rU3Vic2NyaWJlZEV2ZW50LzE",
          "event_name": "PaymentEvents::CompletedEvent",
          "display_name": "Payment Completed",
          "event_category": "payment",
          "event_action": "completed"
        }
      ]
    }
  ],
  "meta": {
    "current_page": 1,
    "total_pages": 1,
    "total_count": 1,
    "per_page": 25
  }
}

Create Webhook Endpoint

Create a new webhook endpoint to receive event notifications.

Endpoint

POST /api/v1/companies/{company_id}/webhook_endpoints

Headers

Authorization: Bearer {jwt_token}
Content-Type: application/json

Request Body

{
  "url": "https://your-app.com/webhooks/treasurypath",
  "active": true,
  "company_id": "Z2lkOi8vd2FsbGV0LWFwcC9Db21wYW55LzE",
  "event_names": [
    "PaymentEvents::CompletedEvent",
    "PaymentEvents::FailedEvent",
    "BankAccountEvents::UpdatedEvent",
    "PaymentProfileEvents::CreatedEvent"
  ]
}

Parameters

Parameter Type Required Description
url string Yes HTTPS URL to receive webhook events
active boolean No Whether endpoint is active (default: true)
event_names array Yes Array of event names to subscribe to

Example Request

curl -X POST "https://api.treasurypath.com/api/v1/companies/{company_id}/webhook_endpoints" \
  -H "Authorization: Bearer {jwt_token}" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/webhooks/treasurypath",
    "event_names": ["PaymentEvents::CompletedEvent", "PaymentEvents::FailedEvent", "BankAccountEvents::CreatedEvent"]
  }'

Success Response (201 Created)

{
  "data": {
    "id": "Z2lkOi8vd2FsbGV0LWFwcC9XZWJob29rRW5kcG9pbnQvMQ",    
    "url": "https://your-app.com/webhooks/treasurypath",
    "active": true,
    "created_at": "2025-01-15T10:30:00Z",
    "updated_at": "2025-01-15T10:30:00Z",
    "subscribed_events_count": 3,    
    "webhook_secret": "whsec_1234567890abcdef"
  }
}

Note: The webhook_secret is only returned once during creation. Store it securely to verify webhook signatures.


Get Webhook Endpoint

Retrieve details of a specific webhook endpoint.

Endpoint

GET /api/v1/webhook_endpoints/{id}

Headers

Authorization: Bearer {jwt_token}

Example Request

curl -X GET "https://api.treasurypath.com/api/v1/webhook_endpoints/Z2lkOi8vd2FsbGV0LWFwcC9XZWJob29rRW5kcG9pbnQvMQ" \
  -H "Authorization: Bearer {jwt_token}"

Success Response (200 OK)

{
  "data": {
    "id": "Z2lkOi8vd2FsbGV0LWFwcC9XZWJob29rRW5kcG9pbnQvMQ",    
    "url": "https://your-app.com/webhooks/treasurypath",
    "active": true,
    "created_at": "2025-01-15T10:30:00Z",
    "updated_at": "2025-01-15T10:30:00Z",
    "subscribed_events_count": 3,    
    "webhook_subscribed_events": [
      {
        "event_name": "PaymentEvents::CompletedEvent",
        "display_name": "Payment Completed"
      }
    ]
  }
}

Update Webhook Endpoint

Update an existing webhook endpoint.

Endpoint

PATCH /api/v1/webhook_endpoints/{id}

Headers

Authorization: Bearer {jwt_token}
Content-Type: application/json

Request Body

{
  "url": "https://your-app.com/webhooks/treasurypath/v2",
  "active": false,
  "event_names": [
    "PaymentEvents::CompletedEvent",
    "PaymentEvents::FailedEvent",
    "BankAccountEvents::CreatedEvent",
    "PaymentProfileEvents::FailedEvent"
  ]
}

Example Request

curl -X PATCH "https://api.treasurypath.com/api/v1/webhook_endpoints/Z2lkOi8vd2FsbGV0LWFwcC9XZWJob29rRW5kcG9pbnQvMQ" \
  -H "Authorization: Bearer {jwt_token}" \
  -H "Content-Type: application/json" \
  -d '{
    "active": false
  }'

Success Response (200 OK)

{
  "data": {
    "id": "Z2lkOi8vd2FsbGV0LWFwcC9XZWJob29rRW5kcG9pbnQvMQ",
    "uuid": "webhook_123e4567-e89b-12d3-a456-426614174000",
    "url": "https://your-app.com/webhooks/treasurypath/v2",
    "active": false,
    "updated_at": "2025-01-15T11:00:00Z"
  }
}

Delete Webhook Endpoint

Delete a webhook endpoint.

Endpoint

DELETE /api/v1/webhook_endpoints/{id}

Headers

Authorization: Bearer {jwt_token}

Example Request

curl -X DELETE "https://api.treasurypath.com/api/v1/webhook_endpoints/Z2lkOi8vd2FsbGV0LWFwcC9XZWJob29rRW5kcG9pbnQvMQ" \
  -H "Authorization: Bearer {jwt_token}"

Success Response (204 No Content)

(empty response body)

Toggle Webhook Endpoint

Toggle the active status of a webhook endpoint.

Endpoint

PATCH /api/v1/webhook_endpoints/{id}/toggle

Headers

Authorization: Bearer {jwt_token}

Example Request

curl -X PATCH "https://api.treasurypath.com/api/v1/webhook_endpoints/Z2lkOi8vd2FsbGV0LWFwcC9XZWJob29rRW5kcG9pbnQvMQ/toggle" \
  -H "Authorization: Bearer {jwt_token}"

Success Response (200 OK)

{
  "data": {
    "id": "Z2lkOi8vd2FsbGV0LWFwcC9XZWJob29rRW5kcG9pbnQvMQ",
    "active": true,
    "updated_at": "2025-01-15T11:15:00Z"
  }
}

Available Events

To see all available webhook events, use the Available Events endpoint:

Endpoint

GET /api/v1/webhook_events

Example Response

{
  "data": [
    {
      "category_name": "payment",
      "display_name": "Payment Events",
      "description": "Events related to payment processing",
      "event_count": 4,
      "events": [
        {
          "event_name": "PaymentEvents::CompletedEvent",
          "display_name": "Payment Completed",
          "action": "completed",
          "description": "Triggered when a payment is completed"
        },
        {
          "event_name": "PaymentEvents::FailedEvent",
          "display_name": "Payment Failed",
          "action": "failed",
          "description": "Triggered when a payment is failed"
        },
        {
          "event_name": "PaymentEvents::CancelledEvent",
          "display_name": "Payment Cancelled",
          "action": "cancelled",
          "description": "Triggered when a payment is cancelled"
        },
        {
          "event_name": "PaymentEvents::DebitInitiatedEvent",
          "display_name": "Payment Debit Initiated",
          "action": "debit_initiated",
          "description": "If payment has a payment order with direction debit, this event is triggered"
        }
      ]
    },
    {
      "category_name": "bank_account",
      "display_name": "Bank Account Events",
      "description": "Events related to bank account management",
      "event_count": 3,
      "events": [
        {
          "event_name": "BankAccountEvents::CreatedEvent",
          "display_name": "Bank Account Created",
          "action": "created",
          "description": "Triggered when a bank account is created"
        },
        {
          "event_name": "BankAccountEvents::UpdatedEvent",
          "display_name": "Bank Account Updated",
          "action": "updated",
          "description": "Triggered when a bank account is updated"
        },
        {
          "event_name": "BankAccountEvents::DeletedEvent",
          "display_name": "Bank Account Deleted",
          "action": "deleted",
          "description": "Triggered when a bank account is deleted"
        }
      ]
    },
    {
      "category_name": "payment_profile",
      "display_name": "Payment Profile Events",
      "description": "Events related to payment profile management",
      "event_count": 2,
      "events": [
        {
          "event_name": "PaymentProfileEvents::CreatedEvent",
          "display_name": "Payment Profile Created",
          "action": "created",
          "description": "Triggered when a payment profile is created"
        },
        {
          "event_name": "PaymentProfileEvents::FailedEvent",
          "display_name": "Payment Profile Failed",
          "action": "failed",
          "description": "Triggered when a payment profile becomes unable to be used for payments"
        }
      ]
    }
  ]
}

Error Responses

400 Bad Request

{
  "error": {
    "code": "validation_error",
    "message": "Invalid webhook URL format",
    "details": [
      {
        "field": "url",
        "message": "URL must use HTTPS"
      }
    ]
  }
}

404 Not Found

{
  "error": {
    "code": "not_found",
    "message": "Webhook endpoint not found"
  }
}

Webhook Security

Signature Verification

All webhook requests include a TreasuryPath-Signature header containing an HMAC-SHA256 signature of the request payload. This signature is generated using your webhook endpoint's unique secret key.

Header Format:

TreasuryPath-Signature: sha256=1234567890abcdef...

Verification Process: 1. Extract the signature from the header (remove the sha256= prefix) 2. Generate the expected signature using HMAC-SHA256 with your webhook secret and the raw request body 3. Compare the signatures using a secure comparison function to prevent timing attacks

Example Implementation:

import hmac
import hashlib

def verify_webhook_signature(payload, signature_header, webhook_secret):
    # Extract signature from header
    signature = signature_header.replace('sha256=', '')

    # Generate expected signature
    expected = hmac.new(
        webhook_secret.encode('utf-8'),
        payload.encode('utf-8'),
        hashlib.sha256
    ).hexdigest()

    # Use secure comparison
    return hmac.compare_digest(expected, signature)

# Usage
if verify_webhook_signature(request_body, signature_header, webhook_secret):
    # Process webhook
    process_webhook_event(request_body)
else:
    # Invalid signature - reject request
    return 401

Important Notes: - Always use the raw request body for signature verification (before JSON parsing) - Use secure comparison functions to prevent timing attacks - The webhook secret is only provided once during endpoint creation - store it securely

Retry Mechanism

TreasuryPath automatically retries failed webhook deliveries: - Retry Schedule: 1 minute, 5 minutes, 25 minutes, 125 minutes (up to 5 total attempts) - Signature Consistency: Each retry uses the same signature as the original request - Failure Conditions: Non-200 HTTP status codes or request timeouts (30 seconds)

Best Practices

  1. Use HTTPS: Only HTTPS URLs are accepted for webhook endpoints
  2. Verify signatures: Always verify webhook signatures before processing events
  3. Handle retries: Implement idempotent processing using event IDs to handle duplicate events
  4. Respond quickly: Return 200 status within 30 seconds to avoid timeouts
  5. Handle failures: Monitor webhook delivery logs and implement alerting for failed deliveries
  6. Test thoroughly: Use webhook testing tools during development to verify signature verification
  7. Secure secrets: Store webhook secrets securely and never log them