Wire your CRM workflow to an agent (webhook URL and secret)
Last updated: September 8, 2026
Every AI agent in GodSetter has its own webhook URL. The workflow you point at that URL decides which agent makes the call — so one client can run different agents for different campaigns just by using different URLs.
This guide wires a CRM workflow (e.g. "new lead created") to an agent so that every lead the workflow processes gets called within seconds — the first call is placed the moment the lead arrives.
Before you start
- Your CRM is connected in Connections (OAuth) and the client sub-account has been imported (it appears in Clients as active). It needs somewhere to book: a calendar of its own, or a default calendar on the agent (Identity & routing), matched by name in the client's sub-account.
- The agent exists and has at least one active phone number assigned (agent editor → Numbers tab). This is fail-closed: an agent with no numbers never dials.
- The agent's direction is Outbound. An inbound agent answers call-backs and is never allowed to start a call cycle, so it cannot be the target of a trigger — see Create inbound and outbound agents.
Step 1 — Copy the agent's webhook URL and secret
Open the agent in Agents, then the Data & GHL tab. You'll find:
- the agent's webhook URL (
…/api/webhooks/ghl-trigger/agent/<agent-id>), - the agent's webhook secret,
- a sample request body,
each with a copy button. The secret is unique per agent — treat it like a password.
Step 2 — Add the webhook action to your workflow
In the client's sub-account, edit the workflow that should trigger calls (for example, on "Contact created" or a pipeline stage change) and add a Webhook action:
- Method:
POST - URL: the agent URL you copied
- Header:
Content-Type: application/json
Step 3 — Build the JSON body
Minimum required fields:
{
"webhookSecret": "<the copied per-agent secret>",
"locationId": "{{location.id}}",
"contactId": "{{contact.id}}",
"phone": "{{contact.phone}}"
}
Recommended additions:
| Field | Why |
|---|---|
firstName, lastName, email | The agent greets the lead by name. |
customValues | Key/value map, available in the prompt as {{cv_*}} variables. |
consentProof | Consent evidence (source, timestamp, text). Required for every call when strict mode is on. |
timezone | The contact's own IANA time zone (e.g. America/New_York). Used by agents whose calling window runs in Contact time zone mode. |
The timezone field is optional and safe to send always: an absent or
unrecognised value is ignored, and the calling window falls back to the client
sub-account's zone and then to the agent's fallback zone. It is stored on the
lead, so later retries and callbacks reuse it. Details in
Set a calling window per agent.
Step 4 — Send a test lead
The quickest check is in the app. In the same Data & GHL tab, right under the webhook card, the Send a test lead card simulates a lead arriving from the workflow: pick the client (only active clients with somewhere to book — their own calendar or the agent's default — are listed), enter a phone you control and click Send test lead. The lead goes through the very same ingress the webhooks use — direction, client, number, consent and Do-Not-Call gates — and then through the instant dispatch, so if everything is wired the agent calls you within seconds. It is a real call (real cost) on a real lead, kept in Calls and Leads like any other. The calendar is the client's real one; booking, tags and notes are simulated — nothing is left in the CRM. The card shows a three-line trace (and because the lead is real, an unanswered test is redialed by the agent's retry plan — expect more real calls to your number unless you block the lead from the Leads page):
- Ingress — lead accepted, or skipped with the reason (same reasons as the table below);
- Dispatch — call started, queued at the head (all slots busy), parked at the window opening (outside the calling window), or not started with the reason;
- Open the lead — the lead the test created.
Then run the real check from the CRM: trigger the workflow with a test contact (use a phone you control). Expected response:
{ "status": "enqueued", "leadId": "…" }
Inside your calling window the call starts within seconds; outside it, the lead waits for the opening. Check Calls for the live entry.
If the response says skipped
The reason field tells you which activation gate stopped the call:
| Reason | Meaning | Fix |
|---|---|---|
client_inactive_or_not_found | The sub-account isn't imported or is inactive. | Sync sub-accounts, open the client, activate it. |
not_configured | The client has no calendar of its own and the agent has no default calendar. | Set a default calendar on the agent (Identity & routing) or pick one in the client detail page. |
no_number | The agent has no active numbers assigned. | Assign one in the agent's Numbers tab. |
no_consent | Strict mode is on and consent proof is missing/invalid. | Include a valid consentProof, or review strict mode. |
blocked | The lead asked not to be contacted (Do-Not-Call). | Only unblock deliberately, from the Leads page. |
inbound_agent | The URL points at an inbound agent, which never starts calls. | Point the workflow at the outbound agent, or switch the direction in the agent's Identity & routing tab. |
A duplicate trigger — the same contact fired twice within 10 minutes — gets its
own response, {"status":"duplicate"}, and is simply ignored: that's the
built-in dedup working as intended.
Three of these skips are also tagged in your CRM — no_number, no_consent and
blocked (names configurable in Settings → CRM tags) — so your workflows can
react to them. The other three (client_inactive_or_not_found, not_configured
and inbound_agent) are setup mistakes on your side: they are reported in the
response and on the lead, but nothing is written to the CRM.
Step 5 — Stop the cycle when the contact books on their own
A booking made during a call already stops the cycle automatically. But a contact can also book outside any call — via a funnel link, or with a human agent. Tell GodSetter about it so scheduled retries never dial someone who has already booked:
- In the client's sub-account, create a second workflow on the CRM's native "Customer booked appointment" trigger.
- Add a Webhook action pointing at the "Appointment booked (stop calls)" URL shown on the Connections page (the page also shows the agency webhook secret and a ready-made sample body to paste).
- Body fields:
webhookSecret(the agency secret from Connections),locationId,contactIdand optionallyphone.
On success the response is {"status":"stopped"}: the lead is marked booked
and every scheduled redial/callback for them is removed. A not_found response is
benign — that contact simply was never in a call cycle.
The other URLs on the Connections page
The Inbound webhooks card on Connections lists five URLs, and only two of them are yours to paste into GoHighLevel:
- Call trigger — the agency-level trigger (the legacy URL; the per-agent URL from Step 1 is the recommended one).
- Appointment booked (stop calls) — Step 5 above.
The other three — Inbound voice, Call lifecycle and In-call tools — are Retell webhooks, and GodSetter configures them for you: the call-lifecycle and in-call-tool URLs are set on the agent when it is created (and re-asserted by "Sync GHL tools"), and the inbound-voice URL is set on the phone number when it is registered on Retell. Nothing to paste anywhere — they are shown for reference, e.g. to check which host your agents and numbers point at. The Webhook secret applies only to the two GoHighLevel ones.
Prefer the branded workflow actions
If the GodSetter marketplace app is installed on the sub-account, both steps are available as native workflow actions — no URL or JSON to paste. They require that app installed on the sub-account and the "Workflow LC Premium Triggers & Actions" billing enabled on it; without both, the branded nodes do not appear in the workflow builder and the generic webhook stays the way to go.
- Start call cycle — pick the action, paste the Agent ID (copy it from the
agent's Data & GHL tab). The contact's phone, name and custom fields are
fetched automatically — every
{{cv_contact_*}}token in the prompt resolves with no mapping work. - Appointment booked (stop calls) — pick the action, paste your Account ID (copy it from the Connections page).
The generic webhook remains fully supported; the actions are the same thing with
less setup. One note: the start-calls action carries no consentProof — with
strict mode on, use the webhook for consent-requiring clients. (Contact custom
fields and any values persisted by earlier webhook triggers are applied
automatically.)
Good to know
- One URL per agent. To route a campaign to a different agent, duplicate the workflow and swap the URL + secret — no changes in GodSetter needed.
- A new trigger restarts the cycle. Firing the workflow again for a contact GodSetter already knows resets the attempt counter and drops the retries still parked for that lead, so the plan starts from call #1 instead of resuming mid-way. A callback the lead explicitly asked for is kept.
- The agency-level legacy webhook (without
/agent/) still works and uses the client's default agent, but the per-agent URL is the recommended setup — and it answers{"status":"skipped","reason":"no_template"}when the client has no default agent. That default is the Agent Template field on the client's detail page (Manage your clients). - If the workflow fires while the calling window is closed, the lead waits in the queue and is dialed when the window reopens.
