Webhooks

Webhooks tell your system the moment something happens in Closepact — a deal is won, a document is signed, a work order is completed, an invoice is issued — so you do not have to poll. Register an HTTPS URL and the events it wants; Closepact sends each one as a signed JSON POST.

Managing endpoints needs an API key with the admin scope, for reading too: endpoints hand out signing secrets and their deliveries carry event data. Creating, changing, testing or deleting an endpoint also needs the member the key acts as to hold Manage outbound webhooks (webhooks.manage).

Delivery. Answer with any 2xx status within 15 seconds. Anything else — another status, a redirect (redirects are not followed), a timeout, a refused connection — is a failed attempt and is retried: 7 attempts in all, 5 seconds, 30 seconds, 5 minutes, 1 hour, 6 hours and 24 hours apart (about 31 hours end to end), after which the delivery is abandoned. Every attempt shows under the endpoint's deliveries. Closepact only connects to public internet addresses: a host that resolves to a loopback, private, link-local or otherwise reserved address is not sent to, and the delivery is abandoned at once. Pausing an endpoint stops new events reaching it; retries already scheduled still run.

Verify every request with the X-Signature header before trusting it — see Verifying signatures (x-signature below).

Duplicates. A delivery can arrive more than once — for example when your server processed it but answered after the timeout. Make your handler idempotent: deduplicate on event_id, which is the same for every endpoint that receives the event, or on the X-Delivery-Id header, which is unique per endpoint.

Order. Events are delivered independently and retries interleave with newer events, so the order of arrival is not guaranteed. Use created, and fetch the record from the API when you need its current state.

Answer first, work later. Acknowledge with a 2xx straight away and do the processing on your own queue; slow handlers time out and are retried.

Payloads grow. New fields can be added to any event without notice; ignore fields you do not recognise. Fields are never renamed or removed without a new event name.

List webhook endpoints

GET/webhooks

Every webhook endpoint in the organization, newest first, with the events each one receives and when it last succeeded or failed. Signing secrets are never included.

curl 'https://api.closepact.com/v1/api/webhooks' \
  -H "Authorization: Bearer $CLOSEPACT_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "01a1c3e0-4b2f-7d19-9c55-2f6a8e1b7d30",
      "url": "https://integration.nordiskfastighet.se/closepact/webhooks",
      "description": "Affärer och signeringar till vårt affärssystem",
      "events": [
        "deal.won",
        "deal.lost",
        "signature.completed"
      ],
      "status": "active",
      "last_success_at": "2026-10-18T09:14:06+00:00",
      "last_failure_at": null,
      "created_at": "2026-10-02T13:40:12+00:00",
      "updated_at": "2026-10-02T13:40:12+00:00"
    }
  ]
}

Responses

    • dataarray of objectsrequired
      • idstring(uuid)required
      • urlstring(uri)required

        Where events are POSTed.

      • descriptionstringnullablerequired

        Your note on what the endpoint is for.

      • eventsarray of stringsrequired

        The events it receives (see WebhookEventName); ["*"] for all.

      • statusstringrequired

        paused endpoints receive no new events.

        One ofactivepaused

      • last_success_atstring(date-time)nullablerequired

        When a delivery to it last succeeded.

      • last_failure_atstring(date-time)nullablerequired

        When an attempt to deliver to it last failed.

      • created_atstring(date-time)required
      • updated_atstring(date-time)required
  • 401No key, or the key is invalid, revoked or expired, or its creator no longer has access.
    Errors
  • 402The organization has not bought the module this endpoint belongs to, or it has lapsed to read-only, or its tier does not include what the operation needs: feature names the capability (the operation's x-feature) and required_tier the cheapest tier that grants it. Every operation answers this with "feature": "core.api" when no module the organization holds is on a tier that includes the API.
    Errors
  • 403The key lacks the admin scope (insufficient_scope), or the member it acts as lacks webhooks.manage (permission_denied), or the organization is suspended.
    Errors
  • 429The key has made more requests this minute than its limit allows.
    Errors

Create a webhook endpoint

POST/webhooks
Scope admin Permission webhooks.manage

Registers a URL to receive the events listed in events, or every event with ["*"]. The endpoint starts active.

The response contains the endpoint's signing secret (secret, starting whsec_). It is shown this once and cannot be read again — store it with your receiver now. If it is lost, rotate it with POST /webhooks/{endpoint}/rotate-secret.

Unknown event names are refused with a 422 that lists them, so a typo cannot leave an endpoint waiting for an event that never comes. Send a test event with POST /webhooks/{endpoint}/test to check the receiver end to end.

curl -X POST 'https://api.closepact.com/v1/api/webhooks' \
  -H "Authorization: Bearer $CLOSEPACT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://integration.nordiskfastighet.se/closepact/webhooks",
  "events": [
    "deal.won",
    "deal.lost",
    "signature.completed"
  ],
  "description": "Affärer och signeringar till vårt affärssystem"
}'
Response · 201
{
  "data": {
    "id": "01a1c3e0-4b2f-7d19-9c55-2f6a8e1b7d30",
    "url": "https://integration.nordiskfastighet.se/closepact/webhooks",
    "description": "Affärer och signeringar till vårt affärssystem",
    "events": [
      "deal.won",
      "deal.lost",
      "signature.completed"
    ],
    "status": "active",
    "last_success_at": null,
    "last_failure_at": null,
    "created_at": "2026-10-02T13:40:12+00:00",
    "updated_at": "2026-10-02T13:40:12+00:00",
    "secret": "whsec_Q3n8vT1kXz5bLm2RfY7wHc4pJd9sGa6E"
  }
}

Request body

application/json · required

  • urlstring(uri)required

    An https URL on the public internet. Refused with a 422: plain http; an address that is loopback, private, link-local (including 169.254.169.254) or otherwise reserved, also when written as IPv6; and names that only exist inside a network, such as localhost, names without a dot and names under .local or .internal.

    at most 1,024 characters

  • eventsarray of stringsrequired

    The events to receive, or ["*"] for all.

    Each one ofdeal.createddeal.stage_changeddeal.wondeal.lostroom.createdroom.publishedstakeholder.addedmessage.postedquote.acceptedsignature.requesteddocument.viewedsigner.signedsignature.completedsignature.canceledwork_order.completedinvoice.issuedwork_order.created_from_quoteinvoice.created_from_quote*

    at least 1 item

  • descriptionstringnullable

    at most 255 characters

Responses

    • dataobjectrequired

      A webhook endpoint with its plain signing secret — only in the response that created the secret.

      • idstring(uuid)required
      • urlstring(uri)required

        Where events are POSTed.

      • descriptionstringnullablerequired

        Your note on what the endpoint is for.

      • eventsarray of stringsrequired

        The events it receives (see WebhookEventName); ["*"] for all.

      • statusstringrequired

        paused endpoints receive no new events.

        One ofactivepaused

      • last_success_atstring(date-time)nullablerequired

        When a delivery to it last succeeded.

      • last_failure_atstring(date-time)nullablerequired

        When an attempt to deliver to it last failed.

      • created_atstring(date-time)required
      • updated_atstring(date-time)required
      • secretstringrequired

        The signing secret, starting whsec_. Shown once: store it now. Use the whole string, prefix included, as the HMAC key.

  • 401No key, or the key is invalid, revoked or expired, or its creator no longer has access.
    Errors
  • 402The organization has not bought the module this endpoint belongs to, or it has lapsed to read-only, or its tier does not include what the operation needs: feature names the capability (the operation's x-feature) and required_tier the cheapest tier that grants it. Every operation answers this with "feature": "core.api" when no module the organization holds is on a tier that includes the API.
    Errors
  • 403The key lacks the admin scope (insufficient_scope), or the member it acts as lacks webhooks.manage (permission_denied), or the organization is suspended.
    Errors
  • 422The body failed validation — for example an event name Closepact does not send, or a URL that is not http(s).
    Errors
  • 429The key has made more requests this minute than its limit allows.
    Errors

Retrieve a webhook endpoint

GET/webhooks/{endpoint}

One webhook endpoint: its URL, events, status and when a delivery last succeeded or failed. The signing secret is never included.

curl 'https://api.closepact.com/v1/api/webhooks/01a14f2c-7c1e-7d0b-9a3e-3f5b2c8d1e40' \
  -H "Authorization: Bearer $CLOSEPACT_API_KEY"
Response · 200
{
  "data": {
    "id": "01a1c3e0-4b2f-7d19-9c55-2f6a8e1b7d30",
    "url": "https://integration.nordiskfastighet.se/closepact/webhooks",
    "description": "Affärer och signeringar till vårt affärssystem",
    "events": [
      "deal.won",
      "deal.lost",
      "signature.completed"
    ],
    "status": "active",
    "last_success_at": "2026-10-18T09:14:06+00:00",
    "last_failure_at": "2026-10-11T22:03:51+00:00",
    "created_at": "2026-10-02T13:40:12+00:00",
    "updated_at": "2026-10-02T13:40:12+00:00"
  }
}

Path parameters

  • endpointstring(uuid)required

    The webhook endpoint's id.

Responses

    • dataobjectrequired

      A URL that receives webhook events. The signing secret is never part of it, except in the responses to create and rotate-secret.

      • idstring(uuid)required
      • urlstring(uri)required

        Where events are POSTed.

      • descriptionstringnullablerequired

        Your note on what the endpoint is for.

      • eventsarray of stringsrequired

        The events it receives (see WebhookEventName); ["*"] for all.

      • statusstringrequired

        paused endpoints receive no new events.

        One ofactivepaused

      • last_success_atstring(date-time)nullablerequired

        When a delivery to it last succeeded.

      • last_failure_atstring(date-time)nullablerequired

        When an attempt to deliver to it last failed.

      • created_atstring(date-time)required
      • updated_atstring(date-time)required
  • 401No key, or the key is invalid, revoked or expired, or its creator no longer has access.
    Errors
  • 402The organization has not bought the module this endpoint belongs to, or it has lapsed to read-only, or its tier does not include what the operation needs: feature names the capability (the operation's x-feature) and required_tier the cheapest tier that grants it. Every operation answers this with "feature": "core.api" when no module the organization holds is on a tier that includes the API.
    Errors
  • 403The key lacks the admin scope (insufficient_scope), or the member it acts as lacks webhooks.manage (permission_denied), or the organization is suspended.
    Errors
  • 404No such record in this organization.
    Errors
  • 429The key has made more requests this minute than its limit allows.
    Errors

Update a webhook endpoint

PATCH/webhooks/{endpoint}
Scope admin Permission webhooks.manage

Changes only the fields you send. Set status to paused to stop new events reaching the endpoint without deleting it (retries already scheduled still run), and back to active to resume; events that happened while it was paused are not sent afterwards. events replaces the whole list. description: null clears the description. The signing secret is unchanged — see POST /webhooks/{endpoint}/rotate-secret.

curl -X PATCH 'https://api.closepact.com/v1/api/webhooks/01a14f2c-7c1e-7d0b-9a3e-3f5b2c8d1e40' \
  -H "Authorization: Bearer $CLOSEPACT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "events": [
    "deal.won",
    "deal.lost",
    "signature.completed",
    "invoice.issued"
  ],
  "status": "active"
}'
Response · 200
{
  "data": {
    "id": "01a1c3e0-4b2f-7d19-9c55-2f6a8e1b7d30",
    "url": "https://integration.nordiskfastighet.se/closepact/webhooks",
    "description": "Affärer och signeringar till vårt affärssystem",
    "events": [
      "deal.won",
      "deal.lost",
      "signature.completed",
      "invoice.issued"
    ],
    "status": "active",
    "last_success_at": "2026-10-18T09:14:06+00:00",
    "last_failure_at": null,
    "created_at": "2026-10-02T13:40:12+00:00",
    "updated_at": "2026-10-18T10:02:44+00:00"
  }
}

Path parameters

  • endpointstring(uuid)required

    The webhook endpoint's id.

Request body

application/json · required

Only the fields sent are changed.

  • urlstring(uri)

    The same rules as on create: https, on the public internet.

    at most 1,024 characters

  • eventsarray of strings

    Replaces the whole list.

    Each one ofdeal.createddeal.stage_changeddeal.wondeal.lostroom.createdroom.publishedstakeholder.addedmessage.postedquote.acceptedsignature.requesteddocument.viewedsigner.signedsignature.completedsignature.canceledwork_order.completedinvoice.issuedwork_order.created_from_quoteinvoice.created_from_quote*

    at least 1 item

  • descriptionstringnullable

    null clears it.

    at most 255 characters

  • statusstring

    One ofactivepaused

Responses

    • dataobjectrequired

      A URL that receives webhook events. The signing secret is never part of it, except in the responses to create and rotate-secret.

      • idstring(uuid)required
      • urlstring(uri)required

        Where events are POSTed.

      • descriptionstringnullablerequired

        Your note on what the endpoint is for.

      • eventsarray of stringsrequired

        The events it receives (see WebhookEventName); ["*"] for all.

      • statusstringrequired

        paused endpoints receive no new events.

        One ofactivepaused

      • last_success_atstring(date-time)nullablerequired

        When a delivery to it last succeeded.

      • last_failure_atstring(date-time)nullablerequired

        When an attempt to deliver to it last failed.

      • created_atstring(date-time)required
      • updated_atstring(date-time)required
  • 401No key, or the key is invalid, revoked or expired, or its creator no longer has access.
    Errors
  • 402The organization has not bought the module this endpoint belongs to, or it has lapsed to read-only, or its tier does not include what the operation needs: feature names the capability (the operation's x-feature) and required_tier the cheapest tier that grants it. Every operation answers this with "feature": "core.api" when no module the organization holds is on a tier that includes the API.
    Errors
  • 403The key lacks the admin scope (insufficient_scope), or the member it acts as lacks webhooks.manage (permission_denied), or the organization is suspended.
    Errors
  • 404No such record in this organization.
    Errors
  • 422The body failed validation — for example an event name Closepact does not send, or a URL that is not http(s).
    Errors
  • 429The key has made more requests this minute than its limit allows.
    Errors

Delete a webhook endpoint

DELETE/webhooks/{endpoint}
Scope admin Permission webhooks.manage

Deletes the endpoint and its delivery history. Deliveries still waiting for a retry are dropped. To stop events for a while instead, set status to paused.

curl -X DELETE 'https://api.closepact.com/v1/api/webhooks/01a14f2c-7c1e-7d0b-9a3e-3f5b2c8d1e40' \
  -H "Authorization: Bearer $CLOSEPACT_API_KEY"
Response · 204
204 — no response body

Path parameters

  • endpointstring(uuid)required

    The webhook endpoint's id.

Responses

  • 204Deleted. No body.
  • 401No key, or the key is invalid, revoked or expired, or its creator no longer has access.
    Errors
  • 402The organization has not bought the module this endpoint belongs to, or it has lapsed to read-only, or its tier does not include what the operation needs: feature names the capability (the operation's x-feature) and required_tier the cheapest tier that grants it. Every operation answers this with "feature": "core.api" when no module the organization holds is on a tier that includes the API.
    Errors
  • 403The key lacks the admin scope (insufficient_scope), or the member it acts as lacks webhooks.manage (permission_denied), or the organization is suspended.
    Errors
  • 404No such record in this organization.
    Errors
  • 429The key has made more requests this minute than its limit allows.
    Errors

List an endpoint's deliveries

GET/webhooks/{endpoint}/deliveries

Every event queued for this endpoint, newest first, with its status, the number of attempts, your endpoint's last response (status and the first 2,000 characters of the body) or the connection error, and when the next retry is due. Filter on filter[status]=abandoned to find events your system never acknowledged.

A delivery is pending until an attempt succeeds (next_retry_at says when the next one runs), succeeded once your endpoint answered with a 2xx, and abandoned after the seventh failed attempt. failed is only seen for the moment between a failed attempt and the scheduling of the next.

curl 'https://api.closepact.com/v1/api/webhooks/01a14f2c-7c1e-7d0b-9a3e-3f5b2c8d1e40/deliveries' \
  -H "Authorization: Bearer $CLOSEPACT_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "01a1c412-77d0-7a3e-b1c4-5e9f0a2d6c81",
      "endpoint_id": "01a1c3e0-4b2f-7d19-9c55-2f6a8e1b7d30",
      "event": "deal.won",
      "event_id": "evt_3f9b2c1e-8a4d-4e6f-9b21-7c5d0e8a1f42",
      "status": "succeeded",
      "attempts": 1,
      "response_status": 200,
      "response_body": "{\"received\":true}",
      "error": null,
      "payload": {
        "id": "01a1b9f2-2c6e-7f40-8d13-6b0e4a9c5f17",
        "title": "Byggpartner Norden AB – serviceavtal 2027",
        "value_cents": 48000000,
        "currency": "SEK",
        "stage": "contract_signed",
        "status": "won",
        "owner_id": "01a14eb3-c634-7238-bc76-18b09b287f98",
        "account_id": "01a15a77-0d3b-7e21-a6f9-3c8e2b1d4a05"
      },
      "next_retry_at": null,
      "delivered_at": "2026-10-18T09:14:06+00:00",
      "created_at": "2026-10-18T09:14:05+00:00",
      "updated_at": "2026-10-18T09:14:06+00:00"
    },
    {
      "id": "01a1c3f8-0b91-7c02-8e6d-4a7f1c3b9e52",
      "endpoint_id": "01a1c3e0-4b2f-7d19-9c55-2f6a8e1b7d30",
      "event": "signature.completed",
      "event_id": "evt_9a0d4e7b-2f61-4c3a-8b5e-1d7f9c2a6e04",
      "status": "pending",
      "attempts": 2,
      "response_status": 503,
      "response_body": "Service Unavailable",
      "error": null,
      "payload": {
        "id": "01a1bc5d-93e4-7a10-b6c2-7e1f4d8a2c63",
        "document_id": "01a1bc31-6f2a-7d84-9e15-3b8c0d4f7a29",
        "deal_room_id": "01a1ba10-5e7c-7b88-9f02-1d4c6a8e3b29",
        "title": "Serviceavtal 2027 – Byggpartner Norden AB",
        "status": "completed",
        "completed_at": "2026-10-18T08:51:17+00:00"
      },
      "next_retry_at": "2026-10-18T08:51:53+00:00",
      "delivered_at": null,
      "created_at": "2026-10-18T08:51:17+00:00",
      "updated_at": "2026-10-18T08:51:23+00:00"
    }
  ],
  "links": {
    "first": null,
    "last": null,
    "prev": null,
    "next": "https://api.closepact.com/v1/api/webhooks/01a1c3e0-4b2f-7d19-9c55-2f6a8e1b7d30/deliveries?per_page=2&cursor=eyJjcmVhdGVkX2F0IjoiMjAyNi0xMC0xOCAwODo1MToxNyJ9"
  },
  "meta": {
    "path": "https://api.closepact.com/v1/api/webhooks/01a1c3e0-4b2f-7d19-9c55-2f6a8e1b7d30/deliveries",
    "per_page": 2,
    "next_cursor": "eyJjcmVhdGVkX2F0IjoiMjAyNi0xMC0xOCAwODo1MToxNyJ9",
    "prev_cursor": null
  }
}

Path parameters

  • endpointstring(uuid)required

    The webhook endpoint's id.

Query parameters

  • cursorstring

    Opaque cursor from meta.next_cursor or meta.prev_cursor of the previous page.

  • per_pageinteger

    Items per page.

    Default 251–100

  • filter[status]string

    Only deliveries with this status.

    One ofpendingsucceededfailedabandoned

  • filter[event]string

    Only deliveries of this event, e.g. invoice.issued.

Responses

    • dataarray of objectsrequired
      • idstring(uuid)required

        Sent as the X-Delivery-Id header.

      • endpoint_idstring(uuid)required
      • eventstringrequired

        The event name; ping for a test event.

      • event_idstringrequired

        The body's event_id.

      • statusstringrequired

        pending: waiting for its first attempt or a retry. succeeded: your endpoint answered 2xx. abandoned: all 7 attempts failed, or the endpoint's host resolved to a private or reserved address and nothing was sent (see error). failed: momentarily, between a failed attempt and scheduling the next.

        One ofpendingsucceededfailedabandoned

      • attemptsintegerrequired

        Attempts made so far.

        0–7

      • response_statusintegernullablerequired

        The HTTP status of the last answer, or null if none came.

      • response_bodystringnullablerequired

        The first 2,000 characters of the last answer's body.

      • errorstringnullablerequired

        Why the last attempt got no answer (timeout, DNS, TLS, refused connection), or why it was not sent (the host resolved to a private or reserved address).

      • payloadobjectrequired

        The event's data, exactly as sent.

      • next_retry_atstring(date-time)nullablerequired

        When the next attempt runs, while pending after a failure.

      • delivered_atstring(date-time)nullablerequired

        When it succeeded.

      • created_atstring(date-time)required

        When the event was queued — the body's created.

      • updated_atstring(date-time)required
    • linksobjectrequired
    • metaobjectrequired
  • 401No key, or the key is invalid, revoked or expired, or its creator no longer has access.
    Errors
  • 402The organization has not bought the module this endpoint belongs to, or it has lapsed to read-only, or its tier does not include what the operation needs: feature names the capability (the operation's x-feature) and required_tier the cheapest tier that grants it. Every operation answers this with "feature": "core.api" when no module the organization holds is on a tier that includes the API.
    Errors
  • 403The key lacks the admin scope (insufficient_scope), or the member it acts as lacks webhooks.manage (permission_denied), or the organization is suspended.
    Errors
  • 404No such record in this organization.
    Errors
  • 422The request body or query failed validation.
    Errors
  • 429The key has made more requests this minute than its limit allows.
    Errors

Send a test event

POST/webhooks/{endpoint}/test
Scope admin Permission webhooks.manage

Queues a ping event for this endpoint alone — whatever events it subscribes to, and even while it is paused — signed with its secret and retried like any other event. Use it to check that your receiver is reachable and verifies signatures before real events depend on it.

Answers 202 Accepted with the new delivery; it is normally sent within seconds. Follow its progress in GET /webhooks/{endpoint}/deliveries.

curl -X POST 'https://api.closepact.com/v1/api/webhooks/01a14f2c-7c1e-7d0b-9a3e-3f5b2c8d1e40/test' \
  -H "Authorization: Bearer $CLOSEPACT_API_KEY"
Response · 202
{
  "data": {
    "id": "01a1c47b-2d58-7e93-a0f1-6c2b8d5e4a17",
    "endpoint_id": "01a1c3e0-4b2f-7d19-9c55-2f6a8e1b7d30",
    "event": "ping",
    "event_id": "evt_c2e81f5a-7b3d-4f90-a6d2-5e8b1c4f7a39",
    "status": "pending",
    "attempts": 0,
    "response_status": null,
    "response_body": null,
    "error": null,
    "payload": {
      "endpoint_id": "01a1c3e0-4b2f-7d19-9c55-2f6a8e1b7d30",
      "message": "A test event from Closepact. Your endpoint received and can verify it."
    },
    "next_retry_at": null,
    "delivered_at": null,
    "created_at": "2026-10-18T09:20:31+00:00",
    "updated_at": "2026-10-18T09:20:31+00:00"
  }
}

Path parameters

  • endpointstring(uuid)required

    The webhook endpoint's id.

Responses

    • dataobjectrequired

      One event queued for one endpoint, and how its attempts went.

      • idstring(uuid)required

        Sent as the X-Delivery-Id header.

      • endpoint_idstring(uuid)required
      • eventstringrequired

        The event name; ping for a test event.

      • event_idstringrequired

        The body's event_id.

      • statusstringrequired

        pending: waiting for its first attempt or a retry. succeeded: your endpoint answered 2xx. abandoned: all 7 attempts failed, or the endpoint's host resolved to a private or reserved address and nothing was sent (see error). failed: momentarily, between a failed attempt and scheduling the next.

        One ofpendingsucceededfailedabandoned

      • attemptsintegerrequired

        Attempts made so far.

        0–7

      • response_statusintegernullablerequired

        The HTTP status of the last answer, or null if none came.

      • response_bodystringnullablerequired

        The first 2,000 characters of the last answer's body.

      • errorstringnullablerequired

        Why the last attempt got no answer (timeout, DNS, TLS, refused connection), or why it was not sent (the host resolved to a private or reserved address).

      • payloadobjectrequired

        The event's data, exactly as sent.

      • next_retry_atstring(date-time)nullablerequired

        When the next attempt runs, while pending after a failure.

      • delivered_atstring(date-time)nullablerequired

        When it succeeded.

      • created_atstring(date-time)required

        When the event was queued — the body's created.

      • updated_atstring(date-time)required
  • 401No key, or the key is invalid, revoked or expired, or its creator no longer has access.
    Errors
  • 402The organization has not bought the module this endpoint belongs to, or it has lapsed to read-only, or its tier does not include what the operation needs: feature names the capability (the operation's x-feature) and required_tier the cheapest tier that grants it. Every operation answers this with "feature": "core.api" when no module the organization holds is on a tier that includes the API.
    Errors
  • 403The key lacks the admin scope (insufficient_scope), or the member it acts as lacks webhooks.manage (permission_denied), or the organization is suspended.
    Errors
  • 404No such record in this organization.
    Errors
  • 422The request body or query failed validation.
    Errors
  • 429The key has made more requests this minute than its limit allows.
    Errors

Rotate the signing secret

POST/webhooks/{endpoint}/rotate-secret
Scope admin Permission webhooks.manage

Replaces the endpoint's signing secret and returns the new one in secret — shown this once. The old secret stops working immediately: every request from now on, including retries of earlier events, is signed with the new one. To switch without rejecting anything, have your receiver accept a signature made with either the old or the new secret until the new one is deployed.

curl -X POST 'https://api.closepact.com/v1/api/webhooks/01a14f2c-7c1e-7d0b-9a3e-3f5b2c8d1e40/rotate-secret' \
  -H "Authorization: Bearer $CLOSEPACT_API_KEY"
Response · 200
{
  "data": {
    "id": "01a1c3e0-4b2f-7d19-9c55-2f6a8e1b7d30",
    "url": "https://integration.nordiskfastighet.se/closepact/webhooks",
    "description": "Affärer och signeringar till vårt affärssystem",
    "events": [
      "deal.won",
      "deal.lost",
      "signature.completed"
    ],
    "status": "active",
    "last_success_at": "2026-10-18T09:14:06+00:00",
    "last_failure_at": null,
    "created_at": "2026-10-02T13:40:12+00:00",
    "updated_at": "2026-10-18T10:05:09+00:00",
    "secret": "whsec_m4Rk8ZpW2tYc6NvB1xHq9LsD3fJg7Ue5"
  }
}

Path parameters

  • endpointstring(uuid)required

    The webhook endpoint's id.

Responses

    • dataobjectrequired

      A webhook endpoint with its plain signing secret — only in the response that created the secret.

      • idstring(uuid)required
      • urlstring(uri)required

        Where events are POSTed.

      • descriptionstringnullablerequired

        Your note on what the endpoint is for.

      • eventsarray of stringsrequired

        The events it receives (see WebhookEventName); ["*"] for all.

      • statusstringrequired

        paused endpoints receive no new events.

        One ofactivepaused

      • last_success_atstring(date-time)nullablerequired

        When a delivery to it last succeeded.

      • last_failure_atstring(date-time)nullablerequired

        When an attempt to deliver to it last failed.

      • created_atstring(date-time)required
      • updated_atstring(date-time)required
      • secretstringrequired

        The signing secret, starting whsec_. Shown once: store it now. Use the whole string, prefix included, as the HMAC key.

  • 401No key, or the key is invalid, revoked or expired, or its creator no longer has access.
    Errors
  • 402The organization has not bought the module this endpoint belongs to, or it has lapsed to read-only, or its tier does not include what the operation needs: feature names the capability (the operation's x-feature) and required_tier the cheapest tier that grants it. Every operation answers this with "feature": "core.api" when no module the organization holds is on a tier that includes the API.
    Errors
  • 403The key lacks the admin scope (insufficient_scope), or the member it acts as lacks webhooks.manage (permission_denied), or the organization is suspended.
    Errors
  • 404No such record in this organization.
    Errors
  • 422The request body or query failed validation.
    Errors
  • 429The key has made more requests this minute than its limit allows.
    Errors