Before integrating webhooks, make sure you’ve completed the Quickstart guide and have your authentication set up.

Overview

When you make a request to our API, you’ll typically get an immediate response. However, some operations like payments can take time to process. Instead of timing out, we return a pending status and use webhooks to notify you of the final result.

You have two options for handling these async operations:

  • Poll the API endpoints periodically (not recommended for production)
  • Use webhooks to receive real-time event updates (recommended)

Webhooks vs Polling

Setting Up Webhooks

1. Create Your Webhook URL

Create a POST endpoint on your server to receive webhook events. The endpoint should:

  1. Accept JSON payloads
  2. Return a 200 OK response
  3. Process events idempotently (handle duplicates safely)
from flask import Flask, request
import hmac
import hashlib
import json

app = Flask(__name__)

def validate_signature(payload, checksum, business_id):
  # Separate event and data
  event = payload['event']
  data = payload['data']

  # Sort data alphabetically and encode
  sorted_data = json.dumps(data, sort_keys=True)
  message = f"{event}|{sorted_data}"

  # Create HMAC SHA256 hash
  expected = hmac.new(
    business_id.encode('utf-8'),
    message.encode('utf-8'),
    hashlib.sha256
  ).hexdigest().upper()

  return hmac.compare_digest(expected, checksum)

@app.route('/webhook', methods=['POST'])
def handle_webhook():
  payload = request.json
  checksum = payload.get('checksum')
  business_id = 'YOUR_BUSINESS_ID'

  # Validate webhook signature
  if not validate_signature(payload, checksum, business_id):
    return 'Invalid signature', 401

  # Process the webhook event
  event_type = payload.get('event')
  if event_type == 'payment.session.succeeded':
    handle_successful_payment(payload['data'])
  elif event_type == 'payment.session.failed':
    handle_failed_payment(payload['data'])

  # Return 200 to acknowledge receipt
  return 'Webhook received', 200

2. Register Your Webhook URL

Add your webhook URL to your account settings:

PATCH /accounts/settings
Request
{
  "webhook_urls": [
    "https://your-domain.com/webhooks"
  ]
}
Response
{
  "data": {
    "settings": {
      "webhook_urls": [
        "https://your-domain.com/webhooks"
      ]
    }
  }
}

Security

🔒 Security Notice

Important Security Considerations:

  • Never expose sensitive credentials in client-side code or VCS
  • Always validate request signatures and origins
  • Use HTTPS for all API communications
  • Implement proper access control and authentication
  • Follow secure key management practices

Verifying Webhook Origins

Secure your webhook endpoint using either or both:

1. Checksum Validation

Each webhook includes a checksum for verification:

{
  "checksum": "32762AE880695AE7343A649CB9C36CA6FF83AA258A139804AEF7D73B421DE097",
  "data": {
    "card_id": "81817411-9ffd-42ba-8bc8-f407b5cef9d9",
    "amount": 1000,
    "reference": "b070b0d2-e394-4783-a6f0-f10ccb3cae89",
    "currency": "USD"
  },
  "event": "card.transaction"
}

To validate:

  1. Concatenate: event|json_encoded_data (data must be alphabetically sorted)
  2. Create HMAC SHA-256 hash using your business ID as the key
  3. Compare with the received checksum

The encoded data must exclude the checksum field and be in alphabetical order:

Valid Order
{"amount":1000, "card_id": "81817411-9ffd-42ba-8bc8-f407b5cef9d9", "currency": "USD", "reference": "b070b0d2-e394-4783-a6f0-f10ccb3cae89"}

2. IP Whitelisting

Whitelist these Juicyway IPs:

164.92.161.1
209.38.214.10
209.38.206.237
46.101.196.147
46.101.192.205
46.101.241.6
46.101.221.92

Go-Live Checklist

1

Verify Public Access

Ensure your webhook URL is publicly accessible (no localhost)

2

URL Configuration

Add trailing / if using .htaccess

3

Test Integration

Verify JSON parsing and 200 OK responses

4

Handle Long Tasks

Return 200 OK before processing lengthy operations

5

Monitor Failed Webhooks

Track non-200 responses in your logs

6

Implement Idempotency

Handle duplicate events safely

Supported Events

In sandbox, successful transactions remain pending. Only failure events are sent.

Payment Events

Next Steps