Skip to main content

Webhooks Integration Guide

This guide shows you how to set up and handle webhooks to receive real-time notifications from Oho about accreditation updates, ICR completions, and other important events.

Overview

Webhooks allow Oho to push event notifications to your application in real-time. Instead of polling the API for updates, your application receives HTTP POST requests from Oho whenever important events occur.

Base URL: https://app.weareoho.com/api

Authentication: Required (Bearer token)

Content-Type: application/json

Key Benefits:

  • ✅ Real-time event notifications
  • ✅ Automatic retry logic with exponential backoff
  • ✅ Secure HMAC-SHA1 signature verification
  • ✅ Event history tracking
  • ✅ Support for multiple webhook endpoints
  • ✅ Per-organization webhook configuration
Prerequisites

Before setting up webhooks, ensure you have:

  • An active Oho account with API access
  • A valid API authentication token (see Authentication Guide)
  • A publicly accessible HTTPS endpoint to receive webhooks
  • Ability to respond within 10 seconds

Understanding Webhooks

What are Webhooks?

A webhook is an HTTP callback that Oho makes to your server when specific events occur. Think of it as a "reverse API" - instead of you requesting data from Oho, Oho sends data to you automatically when something important happens.

When to Use Webhooks

Use webhooks for:

  • WWC Scan Results - Get notified when background check validations complete
  • Accreditation Updates - Receive alerts when accreditations are updated, expire, or are revoked
  • Status Changes - Track changes to constituent or accreditation status in real-time

Webhook Lifecycle

Event Occurs → Oho Creates Webhook → HTTP POST to Your Endpoint → Your Response
↓ (if failed)
Retry with Backoff (up to 5 times)
Asynchronous by Design

Oho operations like WWC scans are asynchronous. Webhooks are the recommended way to receive results without constant polling.


Setting Up Webhooks

Webhook Access Required

Webhooks must be enabled for your Oho account before you can use them. Contact Oho Support to request webhook access for your organization. Once enabled, you can manage webhooks via the UI or API.

Managing Webhooks in the Oho UI

The easiest way to manage webhooks is through the Oho web interface:

Navigation: Settings > Webhooks

Available Actions:

  • ✅ Create new webhooks with a user-friendly form
  • ✅ View all configured webhooks and their status
  • ✅ Edit webhook URLs, labels, and settings
  • ✅ Enable/disable webhooks with a toggle

When to Use the UI:

  • Setting up your first webhook
  • Troubleshooting delivery issues
  • Reviewing event history
  • Quick configuration changes

When to Use the API:

  • Automated webhook provisioning
  • Managing webhooks programmatically
  • Integrating webhook setup into your deployment process
  • Bulk operations across multiple webhooks

Creating a Webhook via API

Endpoint: POST /api/webhooks

Example Request:

curl -X POST https://app.weareoho.com/api/webhooks \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-domain.com/webhooks/oho",
"label": "Production Webhook Handler",
"active": true,
"organization": {
"id": 123
}
}'

Request Fields:

  • url (required) - Your webhook endpoint URL (must be HTTPS)
  • label (required) - Descriptive name for this webhook
  • active (optional) - Whether webhook is active (default: true)
  • organization.id (optional) - Specific organization ID
  • username (optional) - HTTP Basic Auth username for your endpoint
  • password (optional) - HTTP Basic Auth password for your endpoint

Response:

{
"active": true,
"id": 210,
"label": "Production Webhook Handler",
"organization": {
"id": 123
},
"secret": "SS8arjMQmDh9SH6Y/oUFbTWYNdxBsEcl",
"status": "untriggered",
"url": "https://your-domain.com/webhooks/oho"
}

Response Fields:

  • id - Unique webhook identifier for updates/deletes
  • secret - CRITICAL - Use this to verify webhook authenticity (see Security section)
  • status - Current webhook status (active, failed, etc.)
Save Your Webhook Secret

The secret is only returned once during webhook creation. Store it securely - you'll need it to verify incoming webhooks. If lost, you'll need to delete and recreate the webhook.


Managing Webhooks

List All Webhooks

curl -X GET "https://app.weareoho.com/api/webhooks?organization_id=123" \
-H "Authorization: Bearer YOUR_TOKEN"

Response:

{
"items": [
{
"id": 210,
"url": "https://your-domain.com/webhooks/oho",
"label": "Production Webhook Handler",
"active": true,
"status": "active"
}
],
"total": 1,
}

Update a Webhook

curl -X PATCH https://app.weareoho.com/api/webhooks/210 \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-domain.com/webhooks/oho-v2",
"label": "Production Webhook Handler v2",
"active": true
}'

Webhook Event Types

Oho sends webhooks for various events. Each webhook includes an event field to identify the type.

Accreditation Validation Complete

Event: accreditation_validation

Sent when a WWC scan or other accreditation validation completes.

Example Payload:

{
"event": "accreditation_validation",
"correlation_id": "a8f5d2e1-3c4b-4d5e-8f9a-1b2c3d4e5f6a",
"message_id": 12345,
"content": {
"notification_type": "accreditation-result",
"org_id": 123,
"previous": null,
"current": {
"id": 5354,
"identifier": "1076131A",
"type": "vicwwc",
"status": "active",
"status_flags": {
"current": true,
"may_engage": true,
"expired": false,
"expiring": false
},
"registry_response": {
"may_engage": true,
"response": ["Current", "May Engage"],
"oho_status": "active",
"card_type": "employee_wwc"
}
},
"constituent": {
"id": 113767,
"first_name": "Cameron",
"surname": "Schafer",
"email": "cameron@example.com"
}
}
}

Handling Webhooks

Endpoint Requirements

Your webhook endpoint must:

  • ✅ Be publicly accessible via HTTPS (HTTP not supported)
  • ✅ Respond with 200 OK within 10 seconds
  • ✅ Handle duplicate deliveries idempotently
  • ✅ Verify the X-Hub-Signature header
  • ✅ Process data asynchronously after responding
Response Time Limit

If your endpoint doesn't respond within 10 seconds, Oho will consider the delivery failed and schedule a retry. Keep your endpoint fast by responding immediately and processing data asynchronously.

Processing Pattern

Best Practice Flow:

  1. Receive webhook POST request
  2. Verify signature immediately
  3. Store raw payload (optional but recommended)
  4. Respond 200 OK quickly
  5. Process data asynchronously (queue, background job, etc.)

Handling Duplicate Deliveries

Webhooks may be delivered more than once (network issues, retries, etc.). Ensure your processing is idempotent.

Strategies:

  • Use message_id as a unique key to track processed webhooks
  • Use correlation_id for WWC scans to match with your original request
  • Check database state before applying updates
  • Use database transactions with unique constraints

Common Workflows

Workflow 1: WWC Scan Result Handling

Submit WWC Scan → API Returns correlation_id → Store correlation_id

Wait for webhook

Receive accreditation_validation event

Match by correlation_id

Update internal records

Notify relevant parties

Workflow 2: Expiry Monitoring

Receive accreditation_validation webhook → Check if expiring/expired

Update constituent status

Trigger renewal workflow

Notify manager and constituent

Troubleshooting

Webhook Not Receiving Events

Problem: Created webhook but not receiving any events

Solutions:

  1. ✅ Verify webhook is active: GET /api/webhooks
  2. ✅ Check webhook URL is publicly accessible (test with curl from external server)
  3. ✅ Ensure endpoint responds to POST requests
  4. ✅ Verify HTTPS is configured correctly (not self-signed certificate)
  5. ✅ Check firewall rules allow incoming connections
  6. ✅ Review webhook event history: GET /api/webhooks/{id}/events

Webhooks Timing Out

Problem: Webhooks showing timeout errors in event history

Solutions:

  1. ✅ Ensure endpoint responds within 10 seconds
  2. ✅ Move slow processing to background jobs
  3. ✅ Check for database connection pooling issues
  4. ✅ Monitor server resources (CPU, memory)
  5. ✅ Implement proper async handling

Duplicate Webhook Processing

Problem: Same webhook processed multiple times

Solutions:

  1. ✅ Implement idempotency using message_id
  2. ✅ Use database transactions
  3. ✅ Add unique constraints on key fields
  4. ✅ Check for processing before applying updates

FAQ

Q: Can I have multiple webhook endpoints?

A: Yes, you can create multiple webhooks. Each can have a different URL and label. All active webhooks will receive events.

Q: What happens if my endpoint is down?

A: Oho will retry up to 5 times with exponential backoff (30s, 2min, 10min, 1hr, 6hr). After 5 failures, the webhook is marked as failed and you can manually retry from the dashboard.

Q: How do I test webhooks locally?

A: Use ngrok to expose your local development server to the internet. Create a webhook pointing to your ngrok HTTPS URL.

Q: Can I replay/retry old webhooks?

A: You can view webhook event history via GET /api/webhooks/{id}/events. For failed deliveries, you can manually trigger retries from your dashboard.

Q: What's the difference between message_id and correlation_id?

A:

  • message_id - Unique ID for the webhook delivery itself (use for idempotency)
  • correlation_id - Links webhook back to your original API request (e.g., WWC scan submission)

Q: Can I filter which events a webhook receives?

A: Currently, webhooks receive all event types for your organization. Implement filtering in your webhook handler based on the event field.

Q: How long are webhook events stored?

A: Webhook event history is available through the API. Contact support for specific retention policies.



Support

For questions or issues with webhook integration:

  1. Check webhook event history: GET /api/webhooks/{id}/events
  2. Review server logs for signature verification failures
  3. Test endpoint accessibility from external sources
  4. Contact Oho support with your webhook ID and example message_id

Version: 1.0 Last Updated: 2026-01-23 Status: Production Ready