Developers

Avero API

A REST API over your CRM data — deals, persons, organizations, activities and notes. Build your own integrations, sync your stack, automate your pipeline.

Create an API key

Webhooks

Avero POSTs a signed JSON payload to your endpoint whenever CRM records change — created, updated or deleted. Manage subscriptions in your workspace under Settings → Personal preferences → API.

Events

Subscribe to any combination of these events. A ping event is sent by the Test button.

deals.createddeals.updateddeals.deletedpersons.createdpersons.updatedpersons.deletedorganizations.createdorganizations.updatedorganizations.deletedactivities.createdactivities.updatedactivities.deletednotes.creatednotes.updatednotes.deleted

Deal updates that only touch board ordering (position and other derived fields) are suppressed. Every update payload carries changed_fields so you can filter further.

Payload

data is the full record as stored. For *.deleted events it is the record as it was before deletion.

{
  "id": "184",
  "event": "deals.updated",
  "created_at": "2026-07-15T09:12:33.412Z",
  "data": {
    "id": "9b2f7e34-1c5d-4a8e-b7f0-3d2a6c9e8f10",
    "title": "Horvat–Marin wedding — 40-room block",
    "stage": "proposal",
    "…": "…"
  },
  "changed_fields": [
    "stage",
    "updated_at"
  ]
}

Verifying signatures

Every delivery carries an x-avero-signature header of the form t=<unix>,v1=<hex>, where v1 is the HMAC-SHA256 of `${t}.${rawBody}`using your endpoint's signing secret (shown once when you create the webhook). Always verify before trusting a payload:

Node.js
import { createHmac, timingSafeEqual } from "node:crypto";

function verifyAveroSignature(rawBody, signatureHeader, secret) {
  const parts = Object.fromEntries(signatureHeader.split(",").map((p) => p.split("=")));
  const age = Math.abs(Date.now() / 1000 - Number(parts.t));
  if (age > 300) return false; // reject replays older than 5 minutes

  const expected = createHmac("sha256", secret)
    .update(`${parts.t}.${rawBody}`)
    .digest("hex");
  return timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}

Delivery & retries

Delivery is at-least-once — rare duplicates are possible, so deduplicate on the payload id. Your endpoint should respond with a 2xx within 8 seconds. Failed deliveries are retried after 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours (6 attempts total), then dropped. After 20 consecutive failed retries the subscription is disabled automatically (first attempts don't count, so a brief outage never disables you) — re-enable it from Settings once your endpoint is healthy.

Events from API writes usually arrive within a second; events from in-app edits and imports arrive within a minute. Deletions are only visible through webhooks — polling with updated_sincecan't see removed records, so pair the two for a full sync.