Send listings to Halo
Post events, places or offerings from your own system to a webhook source in Halo CRM. The token, the body, how repeats are handled, and what comes back.
A webhook source lets your own system post to Halo CRM's directory: a ticketing system's events, say. What you post goes to the Inbox for someone to decide on, or applies itself if the source is trusted.
Make a source
In Halo CRM, under Sources, choose New source, and under What to read pick Something that posts to Halo. It takes someone who can manage the CRM.
The token starts with
hci_and shows once. It does this one thing and nothing else. Choose New token there if it leaks.What it finds says what your items are, such as events. A sender can't set an item's kind, status or business: those are for people at your organization.
Trust this source applies what you send, unless it might be a duplicate, lacks something its kind needs, or would take the directory past your plan. Those wait in the Inbox, as everything does from a source you don't trust.
The key holding each item's id names your own id key, if it isn't
id.Which key fills which field names your own keys, if they aren't the fields below.
namefromtitle, for example. With any set, only the keys you name are read.
Post to it
curl -sS -X POST https://api.usehalo.net/v1/public/crm/ingest \
-H "Authorization: Bearer $HALO_INGEST_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"items": [
{
"id": "evt-2041",
"name": "Oyster Night",
"summary": "Shucking lessons on the pier.",
"website": "https://example.com/oyster-night",
"city": "Newport",
"startsAt": "2026-12-12T18:00:00-08:00",
"tags": ["food"]
}
]
}'The body is one item, a list of them, or an object with items. Up to 2,000 items and 4 MB a request.
| Field | Means |
|---|---|
id | Your own id for it, or the key the source names instead. Send one: it's how Halo tells a change from something new. Without it, the fields themselves are the key, so any edit looks new |
name | Its name |
summary, description | A line about it, and more |
website, email, phone | How to reach it, as a reader would |
address, city, postalCode | Where it is |
region | A region's key, from the directory's settings. Left out, the source's Region, or else one worked out from the postal code or lat and lng |
lat, lng | Where it is, in numbers |
startsAt, endsAt | For a happening, as ISO 8601. A date with no zone reads in your organization's time zone |
tags | A list of words |
data | The fields the kind adds, by their keys |
Anything else is ignored. Send only what you know: an item doesn't clear what's already there.
What comes back
{ "found": 1, "new": 1, "updated": 0, "unchanged": 0, "applied": 0, "dropped": 0 }| Field | Means |
|---|---|
found | Items read. Each is counted in exactly one of new, updated, unchanged, applied and dropped, so they add up to it |
new | Things Halo hadn't seen, now waiting in the Inbox |
updated | Changes to what it had, now waiting in the Inbox |
unchanged | Items that said what they said last time |
applied | New things and changes that applied themselves, for a trusted source. They aren't in new or updated too |
dropped | Items left out, such as one with nothing usable |
skipped | How many values couldn't be used, by field, such as { "startsAt": 1 } for a date nobody can read, or a region you don't have. The rest of each item still arrives. Left out when there are none |
Sending the same item twice changes nothing, so it's safe to retry and safe to send everything each night.
When it's refused
| Answer | Means |
|---|---|
401 invalid_token | The token is wrong or was rolled, or the organization is suspended, deleted or doesn't have Halo CRM. It doesn't say which |
400 bad_request | The body isn't JSON |
422 validation_failed | The body is neither an object nor a list, or has more than 2,000 items |
429 rate_limited | Too many posts from your address: 120 a minute. Wait, then send again |
This route isn't part of the Developer API. It takes a source's token, and an API key gets 401. To read the directory back, use the Developer API.