# Manage webhooks ## Create a webhook Permissions required Only owners and administrators can configure webhooks. 1. Develop a HTTPS endpoint on your server to receive webhook events 2. Navigate to the ‘Settings’ page in the Wallet-as-a-Service (Palisade) console and click ‘Webhooks’ 3. Click ‘Create webhook’ 4. Enter a webhook name This should be an identifiable name that describes the purpose of the webhook. 5. Optional: enter a description for the webhook 6. Copy and paste the HTTPS endpoint address into the ‘URL’ section 7. Select which events you want the endpoint to receive 8. Click ‘Save’ ## Verify webhook deliveries 1. After you create a webhook, Wallet-as-a-Service (Palisade) generates and returns a P-256 ECDSA public key in ASN.1 DER format. For example: ```json { "id": "a6a1e8bd-30eb-419f-b6ba-e7ac11e86f84", "name": "wefewfwe", "publicKey": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpHiEkdd/ba5dU4sNCgsWrMOE6fLakHywl0OgF5aVfxkiqNh22oybRAREev7jvnwH4jqitHx79KGi6CMwiJjmaw==", // other fields omitted } ``` You can view this public key by clicking on the webhook in the Wallet-as-a-Service (Palisade) console. 1. Extract the signature from the webhook event headers in the URL (it will be in ASN.1 DER format, base64-encoded) 2. Create a SHA-256 hash of the base64-encoded payload 3. Use the public key to verify that the signature matches the payload hash Most programming languages have cryptography libraries that support ECDSA verification. ### Code Examples #### Python ```python import hashlib import base64 from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.serialization import load_der_public_key def verify_webhook(public_key_b64: str, signature_b64: str, payload_b64: str) -> bool: """ Verify a Palisade webhook signature. Args: public_key_b64: Base64-encoded public key from webhook creation signature_b64: Base64-encoded signature from the 'Signature' header payload_b64: The base64-encoded payload string from the webhook body Returns: True if signature is valid, False otherwise """ public_key = load_der_public_key(base64.b64decode(public_key_b64)) signature = base64.b64decode(signature_b64) payload_hash = hashlib.sha256(payload_b64.encode()).digest() try: public_key.verify(signature, payload_hash, ec.ECDSA(hashes.SHA256())) return True except Exception: return False ``` #### JavaScript (Node.js) ```javascript const crypto = require('crypto'); /** * Verify a Palisade webhook signature. * * @param {string} publicKeyB64 - Base64-encoded public key from webhook creation * @param {string} signatureB64 - Base64-encoded signature from the 'Signature' header * @param {string} payloadB64 - The base64-encoded payload string from the webhook body * @returns {boolean} - True if signature is valid */ function verifyWebhook(publicKeyB64, signatureB64, payloadB64) { const publicKey = crypto.createPublicKey({ key: Buffer.from(publicKeyB64, 'base64'), format: 'der', type: 'spki' }); const payloadHash = crypto.createHash('sha256').update(payloadB64).digest(); return crypto.verify( null, payloadHash, publicKey, Buffer.from(signatureB64, 'base64') ); } ``` #### Go ```go package main import ( "crypto/ecdsa" "crypto/sha256" "crypto/x509" "encoding/base64" ) // VerifyWebhook verifies a Palisade webhook signature. func VerifyWebhook(publicKeyB64, signatureB64, payloadB64 string) (bool, error) { publicKeyDER, err := base64.StdEncoding.DecodeString(publicKeyB64) if err != nil { return false, err } pubKey, err := x509.ParsePKIXPublicKey(publicKeyDER) if err != nil { return false, err } ecdsaPubKey, ok := pubKey.(*ecdsa.PublicKey) if !ok { return false, err } signature, err := base64.StdEncoding.DecodeString(signatureB64) if err != nil { return false, err } hash := sha256.Sum256([]byte(payloadB64)) return ecdsa.VerifyASN1(ecdsaPubKey, hash[:], signature), nil } ``` ## Security Requirements & Best Practices * **HTTPS Only**: All webhook endpoints must use HTTPS for secure communication * **Signature Verification**: Always verify the webhook signature to ensure authenticity * **Response Codes**: Return a 200 OK response code to acknowledge receipt of the webhook ## Webhook settings The console lists your webhooks in a table after you create them. You can view or delete webhooks by clicking the three dots in the ‘actions’ column of the table. When you view a webhook, you see the following information: * Name * Description * URL * Public key * Subscriptions: the event subscriptions configured * Who created the webhook and when API documentation See our [Wallet-as-a-Service (Palisade) API reference](/products/wallet/api-docs/palisade-api/palisade-api) for information on how to configure webhooks via the API.