# Webhooks & Notifications Easypay uses webhooks (also called notifications) to inform your application about events that happen in your Easypay account. This is a server-to-server service that sends near real-time notifications about payment status changes. ## What are Webhooks? Webhooks are **POST API** calls (JSON encoded) that let your application know an event has happened. They enable your system to react automatically to payment events without constantly polling the API. ## Why Use Webhooks? Webhooks are particularly useful for asynchronous events like: - When a customer pays a Multibanco reference - A frequent payment succeeds/fails - A subscription payment succeeds/fails - A checkout single sale payment succeeds/fails - Authorization is granted or declined - Capture is completed With webhooks, your system can automate custom actions in response to the transitions that happen in a payment flow. ## Supported Notification Types Easypay supports 3 notification types: ### 1. Generic Notification A notification informing about all state transitions of some payment resource. **Use Case**: Comprehensive monitoring of all payment events **Payload Example**: ```json { "id": "5eca7446-14e9-47bb-aabb-5ee237159b8b", "key": "dcf9ab3fd95ca3d5607853f36d46f161c8715858", "type": "capture", "status": "success", "messages": ["Your request was successfully captured"], "date": "2022-08-10 14:56:54" } ``` ### 2. Authorisation Notification A notification informing about some payment transitioning to authorization status. Available for single and frequent payments. **Use Case**: Specific monitoring of authorization events **Payload Example**: ```json { "id": "1bbc14c3-8ca8-492c-887d-1ca86400e4fa", "value": 1, "currency": "EUR", "key": "the merchant key", "expiration_time": "2022-01-01 10:20", "customer": { "id": "22ea3cc9-424b-489a-91b7-8955f643dc93", "name": "Customer Example", "email": "customer@example.com", "phone": "911234567", "phone_indicative": "+351" }, "method": "mb", "account": { "id": "4c67e74b-a256-4e0a-965d-97bf5d01bd50" }, "authorisation": { "id": "4c67e74b-a256-4e0a-965d-97bf5d01bd50" } } ``` ### 3. Transaction Notification A notification informing about some payment transitioning to capture status. Available for single and frequent payments. **Use Case**: Specific monitoring of successful payment captures **Payload Example**: ```json { "id": "87615356-0a88-42bd-8abb-aab3e90128de", "value": "40", "currency": "EUR", "key": "the merchant key", "expiration_time": "2023-08-07 20:00", "method": "MBW", "customer": { "id": "2eb64a7f-90a7-4dc6-959b-1d9aba44910c", "phone": "910410419" }, "account": { "id": "0b8de6e7-89c8-4d76-93e8-019bc058f27d" }, "transaction": { "id": "eb23923b-3529-4b71-b54e-1e707a8d55c4", "key": "transaction_key_of_this_capture", "type": "capture", "date": "2022-08-10T12:45:50Z", "values": { "requested": "40", "paid": "40", "fixed_fee": "0", "variable_fee": "0", "tax": "0", "transfer": "0" } } } ``` **Note**: If you subscribe to both Generic and Authorisation notifications, you will receive two notifications for the same event with different message contracts. ## Recommended Notification Flow ![Recommended flow](https://easypay-cdn-delivery.s3.eu-central-1.amazonaws.com/docs/checkout/notification_recommended_flow.png) 1. **Easypay sends notification** to your configured endpoint 2. **Your system receives notification** and extracts the payment ID 3. **Your system queries Easypay API** to verify the notification (recommended for security) 4. **Your system processes** the payment according to the API response ## Configuring Webhooks ### Via Backoffice 1. Log in to Easypay backoffice 2. Navigate to `Developers > Configuration API 2.0` 3. Select the payment account you want to receive notifications 4. Select `Notifications` 5. Configure your endpoints: - **Generic - URL**: For generic notifications - **Authorisation - URL**: For authorisation notifications - **Payment - URL**: For capture/transaction notifications ## Implementing a Webhook Endpoint ### Basic Requirements Your webhook endpoint must: - Accept POST requests - Accept JSON payloads - Respond with HTTP 200 status code - Process requests within 20 seconds - Be accessible over HTTPS (recommended) ### Example Implementation Node ```javascript const express = require('express'); const axios = require('axios'); const app = express(); app.use(express.json()); app.post('/webhooks/easypay/generic', async (req, res) => { const notification = req.body; // 1. Acknowledge receipt immediately res.status(200).send('OK'); // 2. Verify the notification by querying the API try { const response = await axios.get( `https://api.prod.easypay.pt/2.0/single/${notification.id}`, { headers: { 'AccountId': process.env.EASYPAY_ACCOUNT_ID, 'ApiKey': process.env.EASYPAY_API_KEY } } ); // 3. Process the verified payment if (response.data.status === 'success') { await processSuccessfulPayment(response.data); } else { await handleFailedPayment(response.data); } } catch (error) { console.error('Error verifying notification:', error); // Implement retry logic or alert system } }); async function processSuccessfulPayment(payment) { // Your business logic here console.log('Processing successful payment:', payment.id); // Update database, send confirmation email, etc. } async function handleFailedPayment(payment) { // Your error handling logic console.log('Handling failed payment:', payment.id); } app.listen(3000); ``` Python ```python from flask import Flask, request, jsonify import requests import os app = Flask(__name__) @app.route('/webhooks/easypay/generic', methods=['POST']) def generic_notification(): notification = request.json # 1. Acknowledge receipt immediately response = jsonify({'status': 'received'}) response.status_code = 200 # 2. Verify the notification by querying the API try: verify_response = requests.get( f"https://api.prod.easypay.pt/2.0/single/{notification['id']}", headers={ 'AccountId': os.getenv('EASYPAY_ACCOUNT_ID'), 'ApiKey': os.getenv('EASYPAY_API_KEY') } ) payment = verify_response.json() # 3. Process the verified payment if payment['status'] == 'success': process_successful_payment(payment) else: handle_failed_payment(payment) except Exception as e: print(f"Error verifying notification: {e}") # Implement retry logic or alert system return response def process_successful_payment(payment): # Your business logic here print(f"Processing successful payment: {payment['id']}") # Update database, send confirmation email, etc. def handle_failed_payment(payment): # Your error handling logic print(f"Handling failed payment: {payment['id']}") if __name__ == '__main__': app.run(port=3000) ``` ## Generic Notification Fields by Payment Type The `id` and `key` fields in generic notifications change according to payment type and operation: | Payment Type | id | key | | --- | --- | --- | | **Single Authorisation** | Single payment ID | `key` from create request | | **Single Capture** | Single payment ID | `transaction_key` from capture request | | **Single Sale** | Single payment ID | `transaction_key` from `capture` object in create request | | **Frequent Create** | Frequent payment ID | `key` from create request | | **Frequent Authorization** | Frequent payment ID | `transaction_key` from authorization request | | **Frequent Capture** | Capture operation ID | `transaction_key` from capture request | | **Refund** | Refund ID | `transaction_key` from refund request | | **Void** | Void ID | `transaction_key` from void request | | **Subscription Create** | Subscription ID | `key` from create request | | **Subscription Capture** | Subscription ID | `transaction_key` from `capture` object | | **Chargeback Single** | Single ID | `transaction_key` from create request | | **Chargeback Frequent** | Capture operation ID | `transaction_key` from capture request | | **Out Payment** | Out payment ID | `key` from create request | ## Security Best Practices 1. **Always Verify Notifications**: Query the Easypay API to confirm webhook authenticity 2. **Use HTTPS**: Ensure your webhook endpoint uses HTTPS 3. **Validate Payload**: Verify the payload structure before processing 4. **Idempotent Processing**: Handle duplicate notifications gracefully 5. **IP Whitelisting**: Optionally restrict access to Easypay's IP ranges 6. **Log Everything**: Keep detailed logs for troubleshooting 7. **Monitor Failures**: Alert on webhook processing failures ## Testing Webhooks ### Local Development with ngrok ```bash # 1. Start your local server npm start # or python app.py # 2. Expose local server with ngrok ngrok http 3000 # 3. Use the ngrok URL in your Easypay backoffice # Example: https://abc123.ngrok.io/webhooks/easypay/generic ``` ### Manual Testing Create test payments and monitor webhook delivery: ```bash # Create a test payment curl -X POST 'https://api.test.easypay.pt/2.0/single' \ -H 'AccountId: 2b0f63e2-9fb5-4e52-aca0-b4bf0339bbe6' \ -H 'ApiKey: eae4aa59-8e5b-4ec2-887d-b02768481a92' \ -H 'Content-Type: application/json' \ -d '{ "type": "sale", "value": 10.00, "method": "cc" }' ``` ## Monitoring Webhooks You can monitor webhook delivery via the Easypay backoffice: 1. Log in to Easypay backoffice 2. Navigate to `Developers > Notifications API 2.0` 3. Select your payment account 4. View webhook delivery status, retry attempts, and response codes ## Handling Failures If your webhook endpoint is unreachable or returns an error, Easypay will: - Retry the webhook multiple times - Use exponential backoff between retries - Eventually mark the webhook as failed ## Next Steps - [Payment Types](/docs/guides/payment-types) - Understand different payment workflows - [Authorizations & Captures](/docs/guides/authorizations-captures) - Learn about auth/capture events - [API Reference](/openapi) - Webhook payload schemas - [Error Handling](/docs/error-handling) - Handle webhook errors gracefully