# Procore Webhooks

Procore (construction management platform) lets company and project admins create **hooks**
(Company Admin > Webhooks) that POST a notification to your endpoint whenever a Procore API
resource is created, updated or deleted. Payloads are **not signed**. The only credential is the
optional **Authorization Header** field, which Procore places verbatim in the `Authorization`
header of each POST.

## When to Use This Skill

* How do I receive Procore webhooks?
* How do I verify the Procore `Authorization` header on a webhook?
* Does Procore sign webhook payloads? (No: shared header credential only)
* Why does my Procore webhook endpoint return 401?
* How do I handle Procore `create`, `update` and `delete` events for a resource like RFIs?

## Verification (core)

Set the **Authorization Header** on the hook, store the exact same string as
`PROCORE_AUTHORIZATION`, and compare it to the **whole** `Authorization` header. Paste the
Authorization Header value exactly as set in Procore, including any "Bearer " or "Basic "
prefix. Never strip, parse or base64-decode it: the docs' example, `Basic c3a24b8208ac5199d083d54a1234e94b8864`, is a token, not base64 `user:pass`.

```javascript
const crypto = require('crypto');

// Hash both sides: equal-length buffers, so timingSafeEqual never throws.
function safeEqual(a, b) {
  const ha = crypto.createHash('sha256').update(String(a)).digest();
  const hb = crypto.createHash('sha256').update(String(b)).digest();
  return crypto.timingSafeEqual(ha, hb);
}

function verifyProcoreRequest(headers, expected = process.env.PROCORE_AUTHORIZATION) {
  if (!expected) return false;               // never accept when unconfigured
  const received = headers['authorization']; // full value, e.g. "Basic c3a2..."
  return Boolean(received) && safeEqual(received, expected);
}

```

Return `401` when the header is missing or does not match, `400` for a body that isn't a JSON
object, and `200` once handled. Read the body raw (`express.raw({ type: '*/*' })`) so any
content type works, and parse it only after the credential check. Python and Next.js
equivalents are in [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/procore-webhooks/references/verification.md).

**What this does and does not give you:** a static shared credential authenticates the
*sender*, not the *body*, and offers no replay protection (no signature, no timestamp). Use
HTTPS, and rotate the credential in Procore and in your environment if it leaks.

> **For complete handlers with tests**, see [examples/express/](https://github.com/hookdeck/webhook-skills/tree/main/skills/procore-webhooks/examples/express/),
> [examples/nextjs/](https://github.com/hookdeck/webhook-skills/tree/main/skills/procore-webhooks/examples/nextjs/), [examples/fastapi/](https://github.com/hookdeck/webhook-skills/tree/main/skills/procore-webhooks/examples/fastapi/).

## Event Types

Each event has a **resource name** (the Procore API resource, e.g. RFIs) and an **event type**:

| Event type | Triggered when |
| --- | --- |
| `create` | A resource record is created |
| `update` | A resource record is updated |
| `delete` | A resource record is deleted |

The v2 payload is described as carrying fields like `id`, `ulid`, `timestamp`, `user_id`,
`company_id`, `project_id`, `api_version`, `event_type`, `resource_name` and `resource_id`. The
Procore support article confirms only the resource name, resource ID, event type and timestamp;
the developer docs are not readable here, so treat the payload in the examples as illustrative.

## Environment Variables

```bash
PROCORE_AUTHORIZATION=Basic c3a24b8208ac5199d083d54a1234e94b8864   # full header value

```

## Local Development

```bash
npx hookdeck-cli listen 3000 procore --path /webhooks/procore

```

No account required. Hookdeck's Procore source shows this note: Paste the Authorization Header
value exactly as set in Procore, including any "Bearer " or "Basic " prefix. Give the printed
URL to Procore as the hook's Endpoint URL.

## Resources

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/procore-webhooks/references/overview.md) - Hooks, resources, event types, payload fields
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/procore-webhooks/references/setup.md) - Creating a hook in Company Admin and setting the Authorization Header
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/procore-webhooks/references/verification.md) - Header check in Node, Python and Next.js, gotchas
* [examples/](https://github.com/hookdeck/webhook-skills/tree/main/skills/procore-webhooks/examples/) - Runnable Express, Next.js and FastAPI handlers with tests