Why webhooks
For a typical partner integration, webhooks are strictly better than polling on three dimensions:- Freshness. A webhook delivers within seconds of the source event. A polled sync runs on whatever interval you configure — typically minutes or hours.
- Cost. Webhook deliveries do not count against your hourly rate limit. A poll that scans for recent changes does — even when nothing has changed.
- Completeness. Webhooks fire for events generated by any source — your own integration, other integrations, manual entry by a Virtuous user, the nightly Transaction batch. A poll only sees changes that landed before your last query timestamp.
How the flow works
The full lifecycle of a webhook integration: The four pieces:- Subscribe. Your integration calls
POST /api/Webhookto register a payload URL and select which events you want delivered. Virtuous returns the subscription details, including thesecretused for signature verification. - Receive. When a subscribed event occurs in the nonprofit’s Virtuous organization, Virtuous sends an HTTP POST to your
payloadUrlwith the event payload. - Verify and process. Your endpoint verifies the request signature (proving the request came from Virtuous and was not tampered with), then processes the event.
- Acknowledge. Your endpoint returns a
2xxHTTP status to confirm delivery. Non-2xxresponses trigger retries — see Retry Behavior.
Subscribing to webhooks
A webhook subscription specifies (a) where to deliver events and (b) which events to deliver. Create one withPOST /api/Webhook:
id for later management (updating event selections, deactivating, deleting). Store the secret securely — it is used to verify the authenticity of every incoming webhook delivery.
The subscription fields
See Event Types for what each event represents and when it fires.
Generating the secret
You provide thesecret value when creating the subscription. Virtuous does not generate it for you. Use a cryptographically secure random string of at least 32 bytes:
Managing webhook subscriptions
The standard CRUD endpoints work as expected:Updating the event selections
To subscribe to additional event types after the initial creation, send aPUT /api/Webhook/{webhookId} with the full set of fields you want enabled:
cURL
GET-then-PUT pattern used elsewhere in CRM+ minimizes the risk of inadvertently disabling event types you previously subscribed to.
Rotating the secret
To rotate the webhook secret, generate a new value andPUT the subscription with the new secret. The new secret takes effect on the next webhook delivery. Your endpoint must accept both the old and new secret during the rotation window — at minimum the time between the API call and your verification code being updated.
A safer rotation pattern: maintain a list of valid current and recent secrets in your verifier, accept signatures matching any of them, and drop the old secret from the list once you have confirmation that no deliveries with the old signature have arrived.
Endpoint requirements
YourpayloadUrl must meet a few requirements to receive webhooks reliably:
The exact delivery timeout enforced by Virtuous is not documented in the OpenAPI spec.⚠️ Human input required: Confirm the exact delivery timeout (seconds before Virtuous considers a delivery failed and triggers retry) so partners can size their endpoints appropriately.
The receiver pattern
The recommended shape of a webhook receiver:JavaScript
- Capture the raw body. Signature verification runs over the exact bytes Virtuous sent. JSON-parsing-then-re-serializing changes whitespace and ordering, which breaks the signature.
- Acknowledge before processing. Return
2xxas soon as you have verified and stored the event. Heavy processing in the request handler increases the risk of timeout-triggered retries. - Queue the work. A robust integration pushes the event onto a background queue (SQS, Cloud Tasks, Redis Stream, etc.) and processes asynchronously. This isolates the webhook endpoint’s latency from the cost of downstream processing.
Where to go next
Event Types
The 15 event types CRM+ delivers and what each one represents.
Signature Verification
How to verify that an incoming webhook came from Virtuous and was not tampered with.
Retry Behavior
What happens when your endpoint is unavailable or returns non-2xx.
Idempotency and Safe Reprocessing
Why and how to make your handler safe against duplicate deliveries.
Local Testing
Receive Virtuous webhooks on localhost using a tunneling tool.
Rate Limits
Why webhooks are the recommended pattern when the alternative is polling.