Using Account Webhooks For Your CRM

Viktor Ristic
Viktor Ristic
  • Updated

Overview

gaiia's account.* webhooks let your external systems — CRMs, billing tools, support desks, data warehouses, marketing platforms — stay automatically in sync with account data, without polling the API on a schedule. When something changes in gaiia, gaiia calls your endpoint in near real-time so your downstream systems can react immediately.

This article covers how webhooks work in gaiia, how to register and secure an endpoint, what each account event represents, and practical patterns for putting them to work in third-party apps.

 

How webhooks work in gaiia

Instead of your application asking gaiia "has anything changed?", gaiia sends an HTTP POST request to an endpoint URL you've registered the moment a change occurs. The request body is a JSON object describing the event. Your endpoint acknowledges receipt, and your code handles whatever syncing or processing is needed.

You can register a single endpoint that handles many event types at once, or create separate endpoints dedicated to specific events — whichever matches how your downstream systems are organized.

 

Getting started

There are three steps to start receiving events. More on this here.

  1. Set up an endpoint. Create a route or function in your application that accepts POST requests and is served over HTTPS. gaiia requires HTTPS endpoints.
  2. Register the endpoint in gaiia. Go to Admin → Webhooks, provide your endpoint URL, and select the events you want to subscribe to — in this case, the account.* events.
  3. Secure the endpoint with your signing secret. Each registered endpoint is issued a secret key. Use it to verify that incoming requests genuinely came from gaiia before acting on them (see the next section).

 

Verifying authenticity

Because your endpoint is a public URL, you should confirm every request is genuinely from gaiia before processing it. gaiia signs each event and includes the signature in an X-Gaiia-Webhook-Signature header. That header contains a timestamp prefixed with t= and one or more signatures prefixed with a scheme — the current live scheme is v1. Signatures are generated using HMAC-SHA256.

The verification flow has four steps:

  1. Extract the timestamp and signatures from the header by splitting on commas, then on =, to read the t and v1 values.
  2. Build the signed payload by concatenating the timestamp, a literal period (.), and the raw JSON request body.
  3. Compute your expected signature by running HMAC-SHA256 over that signed payload string using your endpoint's secret key.
  4. Compare your computed signature against the one in the header. If they match, also verify that the timestamp falls within your tolerance window (this guards against replayed requests), then process the event. If they don't match, respond with a 400 status and do not process the event.

Compute the HMAC over the exact raw request body bytes received, before any JSON re-serialization. Re-stringifying the body can change whitespace or key order and break signature comparison. More on this here.

 

The shape of every account event

All account events share the same envelope, which makes them straightforward to route in code:

Field Type Description
id string Unique ID for this event delivery. Use it to deduplicate.
eventName string The event type, e.g. account.status_updated.
webhookId string Identifies which registered webhook delivered the event.
objectId string The account (or related object) the event is about.
createdAt string When the event occurred (ISO 8601).
payload object Event-specific data (see below).

Switch on eventName to decide how to handle each event, and use objectId to identify which account to update in your external system. For "updated" events, gaiia includes both the new and previous values in the payload, so you can diff them or build an audit trail without an extra API call.

 

The account events

There are nine account.* events, grouped below by what they represent.

Lifecycle

Event When it fires Payload highlights
account.created A new account is created. Full account snapshot: status, mailing and physical addresses, primary contact, communication preferences, readableId, tags, custom fields.
account.deleted An account is deleted. Intentionally empty — objectId alone is sufficient to remove or archive the downstream record.

Status

Event When it fires Payload highlights
account.status_updated An account's status changes. newStatus and previousStatus, each with a name and a type from the fixed set: "Active", "Inactive", "Lead", "Pending", "Suspended".

Contacts

Event When it fires Payload highlights
account.contact_created A contact is added to an account. firstName, lastName, email, phone numbers, isPrimary flag, optional role, and notificationTypes (e.g. "Billing").
account.contact_updated A contact's details are edited.
account.contact_deleted A contact is removed from an account.

Location & preferences

Event When it fires Payload highlights
account.physical_address_updated The service/physical address changes. newPhysicalAddress and previousPhysicalAddress: address lines, locality, region, postal code, country, optional latitude/longitude.
account.communication_preferences_updated Contact/messaging preferences change. newCommunicationPreferences and previousCommunicationPreferences: emailMessagingEnabled, smsMessagingEnabled, languagePreference ("EN" or "FR").
account.unit_assignations_updated An account is linked to or unlinked from a unit. Useful for keeping property/premises relationships aligned in external systems.

 

Common integration patterns

Keeping a CRM in sync

Subscribe to account.created to create the corresponding CRM record, mapping over the name, primary contact, and addresses from the payload. Subscribe to account.contact_* and account.physical_address_updated so edits in gaiia flow into the CRM automatically. Use account.deleted to archive the CRM record. Because update events carry both new and previous values, you can write meaningful activity-log entries (e.g. "Address changed from X to Y") without an extra API lookup.

Lifecycle automation and marketing

Listen for account.status_updated and branch on the status type transition:

  • "Lead" → "Active": trigger an onboarding sequence.
  • "Active" → "Suspended": pause campaigns and notify your retention team.
  • Any → "Inactive": kick off a win-back flow.

Pair this with account.communication_preferences_updated so opt-outs are respected immediately — if emailMessagingEnabled flips to false, suppress that contact in your email tool. Use languagePreference to pick the right localized template.

A small dedicated endpoint subscribed only to account.communication_preferences_updated can fan out consent changes to every system that sends messages — email service provider, SMS gateway, support desk — ensuring you never message someone who has opted out and that you always use their preferred language.

Syncing a network monitoring or provisioning system

Use account.created to trigger provisioning workflows in your network management system when a new subscriber is activated — for example, pre-staging equipment or reserving IP resources. Listen for account.status_updated to automatically suspend or restore service at the network layer when an account's status changes in gaiia, keeping billing state and network access in sync without manual intervention.

Feeding a data warehouse or analytics platform

Point a catch-all endpoint at an ingestion service and append each event to an append-only log keyed by objectId and createdAt. Because update events include previous values, you get a clean change history out of the box — useful for cohort analysis, churn modeling, and auditing.

Syncing GIS and infrastructure mapping tools

Use account.physical_address_updated and account.unit_assignations_updated to keep your external GIS or network infrastructure platform current when subscriber addresses or unit linkages change in gaiia. This is useful for maintaining accurate plant records, updating serviceable address databases, or triggering automated network feasibility checks when a subscriber moves to a new unit.

 

Implementation best practices

  • Make your handler idempotent. Track the event id — networks occasionally deliver the same event twice, and processing the same id a second time should be a no-op.
  • Acknowledge fast. Return a 2xx response immediately and do heavier syncing work asynchronously (e.g. on a queue). Slow handlers can cause delivery timeouts and retries.
  • Branch on eventName, not on payload shape, to route events in your code.
  • Treat the payload as the source of truth for what changed. Fall back to the gaiia API only when you need data the event payload doesn't include.

Was this article helpful?

Have more questions? Submit a request