How Webhooks Work
Learn how Procore notifies your app in real time with webhooks.
Ready to implement? This page covers webhook concepts, event payloads, and how delivery works. For step-by-step setup using the API, see Set Up Webhooks.
Overview
A webhook is an HTTP request that Procore sends to your app the moment something changes — so your integration reacts in seconds instead of constantly polling the API. In Procore, you subscribe to events (create, update, delete) for supported resources; for example, your integration can be notified the instant a new RFI is created.
Think of a webhook as a notification that something already happened in Procore — not the data itself. By the time Procore sends it, the change has committed and is stored; the webhook just tells you to go fetch it. That makes webhooks a fast, best‑effort signal: if one is delayed or lost, the change still succeeded and is waiting in the REST API. So pair webhooks (for speed) with a periodic reconciliation sync (for completeness) — see Reliability and Your Fallback Strategy.
Why use webhooks
- Get near real‑time updates without polling.
- Automate workflows in external systems.
- Reduce API calls and infrastructure cost.
How Webhooks Work
- An event occurs in Procore (Web, Mobile, or API).
- If webhooks are configured at the company or project level, Procore sends an HTTPS
POSTto your endpoint with an event object in the JSON body. - For creates and updates, your service can make a follow‑up
GETto the Procore API to retrieve details for the changed resource.
Access and Authentication
Procore supports a dedicated permissions set for Webhooks called Webhooks API. This is the recommended permission set at the Company and Project level to create, list, edit and delete Hooks or Triggers.
Permissions
- The Webhooks API permission must be Standard for your data connector component.
- By default, the permissions are set to None.
Webhook Event Payload
When you configure a webhook, choose a payload format for event deliveries. In current v1.0 APIs this is called api_version; in future versions it will be payload_version. This setting controls the JSON schema of each delivered event. Use the versions below to pick the right option.
Each webhook delivery includes an event object with the fields below (legacy payload format shown):
| Event property | Description |
|---|---|
api_version |
Procore API version. |
company_id |
Company where the event occurred. |
event_type |
create, update, or delete. |
id |
Event ID. |
metadata |
Context about the event (source app, user, etc.). |
project_id |
Project where the event occurred. |
resource_id |
ID of the changed resource. |
resource_name |
Name of the changed resource. |
timestamp |
UTC time when the event occurred. |
ulid |
26‑character unique identifier. |
user_id |
User who initiated the event. |
Events are sent in one or more deliveries to your endpoint. Deliveries include additional fields such as response status and outcome. For details, see Using the Webhooks API.
Payload Formats
New integrations should use v4.0 — it’s the latest and most capable format: all‑string IDs, a simplified schema, and support for more resource types. Choose an earlier version only to match an existing integration.
Version v2.0 (legacy)
This is our legacy payload format and is used for most existing webhook deliveries.
{
"id": 123456789,
"ulid": "0A1B2C3D4F5G6H7I8J9K0LMN",
"timestamp": "2025-02-06T23:34:12.246562Z",
"metadata": {
"source_user_id": 987654321,
"source_project_id": 2468013579,
"source_operation_id": null,
"source_company_id": 1357908642,
"source_application_id": null
},
"user_id": 987654321,
"company_id": 1357908642,
"project_id": 2468013579,
"api_version": "v2.0",
"event_type": "update",
"resource_name": "RFIs",
"resource_id": 54321
}
Version v3.0
v3.0 adds arelated_resources array. It is usually empty; certain line item resources include a related object. Example for Direct Cost Line Items:
{
"id": 123456789,
"ulid": "0A1B2C3D4F5G6H7I8J9K0LMN",
"timestamp": "2025-02-06T23:34:12.246562Z",
"metadata": {
"source_user_id": 987654321,
"source_project_id": 2468013579,
"source_operation_id": null,
"source_company_id": 1357908642,
"source_application_id": null
},
"user_id": 987654321,
"company_id": 1357908642,
"project_id": 2468013579,
"api_version": "v3.0",
"event_type": "update",
"resource_name": "Direct Cost Line Items",
"resource_id": 379913,
"related_resources": [
{ "id": 1234, "name": "Direct Costs" }
]
}
Version v4.0
v4.0 simplifies the schema and changes some key types. All IDs are strings.event_type is renamed to reason and can include more than create, update, and delete. Hooks using v4.0 can also deliver additional resource types.
{
"id": "01JMYXMZRBVKK0PC6XS8SA4QRE",
"timestamp": "2025-02-25T16:04:43.619085Z",
"reason": "update",
"company_id": "8",
"project_id": "6778",
"user_id": "5447",
"resource_type": "Direct Cost Line Items",
"resource_id": "379913"
}
Set Up Your Endpoint
Your notification endpoint must:
- Be publicly accessible over HTTPS.
- Accept
POSTrequests withapplication/jsonand parse the body. - Return a
2xxstatus on success (send it quickly; process work asynchronously). - Match the endpoint URL you configure on the Webhooks page.
Expected request/response
| HTTP method | Content‑Type | Body | Successful response |
|---|---|---|---|
POST |
application/json |
Event JSON | 200 OK or 204 No Content |
Reliability and Your Fallback Strategy
Procore aims to deliver every webhook, quickly and reliably. But a webhook is only a notification — by the time it’s sent, the underlying change has already committed in Procore and is retrievable from the REST API. Delivery of that notification is best‑effort, not guaranteed: during a Procore or network incident, or a prolonged failure at your endpoint, notifications can be delayed or, in the worst case, dropped.
The key distinction: a delayed or missing webhook is a notification problem, never a data problem. The record is safe in Procore either way — the API is always the source of truth. Your job is to make sure a late or missing notification never turns into missing data on your side.
Important — design a reconciliation fallback. Do not treat webhooks as your only source of truth or as a guaranteed queue. Pair them with a periodic reconciliation sync: on a schedule, query the Procore REST API for resources changed since your last successful sync (for example, filtering by
updated_at) and fill any gaps. Webhooks make your integration fast; reconciliation makes it complete. This is your safety net for the downtime and delay cases below.
Make delivery resilient:
- Idempotency: A delivery for the same event can arrive more than once. Make processing idempotent — track processed events by
ulidor eventidso a re‑delivery is a no‑op. - Respond fast: Return a
2xxas soon as you receive the event, then handle downstream work asynchronously. Procore’s request timeout is 5 seconds after a connection is established. - Retry/backoff: On failures (non‑
2xx, timeout, or connection issues), deliveries pause and retry with exponential backoff (starting at 1 second, up to 1 hour). After 12 hours of continuous failure the queue is flushed and the queued events are marked discarded — precisely the gap your reconciliation sync must close. A successful delivery resets the counters and normal delivery resumes. - Watch for gaps: Deliveries carry a response status and outcome (see Using the Webhooks API). Monitor for repeated failures or discards so you know when your reconciliation sync needs to catch up.
Next steps
- Set Up Webhooks — create and manage hooks and triggers via the API.
- Configure in the Procore UI: Company Webhooks · Project Webhooks.