{
  "item": [
    {
      "name": "Webhook APIs V2",
      "description": "Webhook APIs V2 provide a per-subscription model for managing event-driven integrations with the LMS. Each webhook is an independent record with its own ID, URL, authentication configuration, and delivery log history \u2014 list, get, update, or delete individual subscriptions by ID.\n\nKey differences from V1:\n\n- **Per-webhook subscriptions** \u2014 V1 operated at the event-key level (one subscription per event). V2 lets you create multiple subscriptions for the same event with different URLs, secrets, or configurations.\n- **HMAC signature authentication** \u2014 outgoing payloads are signed using the subscription's `signing_key`. Verify the signature on your endpoint to confirm the payload came from Acorn and wasn't tampered with in transit.\n- **Wildcard event support** \u2014 subscribe to `Events\\Users\\*` (or `*` for all events) to receive every event in a category without creating one webhook per event type.\n- **Soft-delete** \u2014 `DELETE` marks a subscription as deleted but retains the record in the database for audit. No further events fire on the deleted subscription.\n- **Secret masking** \u2014 `signing_key` and `auth_token` are masked in GET responses (`\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022` followed by the last 4 characters) to prevent leakage.\n- **Per-webhook delivery logs** \u2014 delivery attempt history (success/failure status, response codes, retry counts) is retrievable per webhook via `/webhooks/:webhook_id/logs`.\n\nAll endpoints require authentication via an API Key (Bearer token).",
      "item": [
        {
          "id": "e1643ac7-7689-490a-9a2c-35d6dcc5d072",
          "name": "List Available Events",
          "request": {
            "name": "List Available Events",
            "description": {
              "content": "Returns a list of all available webhook event types that can be subscribed to.\n\nEvent categories include:\n- `Events\\Notifications\\*` - Notification events (Duedate, Refresher, Attendance, etc.)\n- `Events\\Users\\*` - User lifecycle events (Created, Updated, Deleted, etc.)\n- `Events\\Courses\\*` - Course completion events\n- `Events\\Quiz\\*` - Quiz attempt events",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "api",
                "v2",
                "{{tenancy_id}}",
                "webhooks",
                "events"
              ],
              "host": [
                "{{base_url}}"
              ],
              "query": [],
              "variable": []
            },
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "body": {},
            "auth": null
          },
          "response": [
            {
              "name": "List Available Events",
              "originalRequest": {
                "url": {
                  "path": [
                    "api",
                    "v2",
                    "{{tenancy_id}}",
                    "webhooks",
                    "events"
                  ],
                  "host": [
                    "{{base_url}}"
                  ],
                  "query": [],
                  "variable": []
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "description": {
                      "content": "Added as a part of security scheme: bearer",
                      "type": "text/plain"
                    },
                    "key": "Authorization",
                    "value": "Bearer <token>"
                  }
                ],
                "method": "GET",
                "body": {}
              },
              "status": "OK",
              "code": 200,
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                },
                {
                  "disabled": true,
                  "description": {
                    "content": "",
                    "type": "text/plain"
                  },
                  "key": "X-RateLimit-Limit",
                  "value": "60"
                },
                {
                  "disabled": true,
                  "description": {
                    "content": "",
                    "type": "text/plain"
                  },
                  "key": "X-RateLimit-Remaining",
                  "value": "58"
                }
              ],
              "body": "{\n    \"events\": [\n        \"Events\\\\Notifications\\\\Duedate\",\n        \"Events\\\\Notifications\\\\Refresher\",\n        \"Events\\\\Notifications\\\\Attendance\",\n        \"Events\\\\Notifications\\\\Session_changed\",\n        \"Events\\\\Notifications\\\\Session_cancelled\",\n        \"Events\\\\Notifications\\\\Expressed_interest\",\n        \"Events\\\\Notifications\\\\Enrolment\",\n        \"Events\\\\Notifications\\\\Account_Merge\",\n        \"Events\\\\Notifications\\\\Session_reminder\",\n        \"Events\\\\Notifications\\\\Session_registration\",\n        \"Events\\\\Notifications\\\\Session_withdrawn\",\n        \"Events\\\\Notifications\\\\Session_deny\",\n        \"Events\\\\Notifications\\\\Instructor_assignment\",\n        \"Events\\\\Notifications\\\\Instructor_unassignment\",\n        \"Events\\\\Notifications\\\\*\",\n        \"Events\\\\Users\\\\Created\",\n        \"Events\\\\Users\\\\Updated\",\n        \"Events\\\\Users\\\\Deleted\",\n        \"Events\\\\Users\\\\Tenancy_added\",\n        \"Events\\\\Users\\\\Tenancy_removed\",\n        \"Events\\\\Users\\\\*\",\n        \"Events\\\\Courses\\\\Completion_created\",\n        \"Events\\\\Courses\\\\Completion_updated\",\n        \"Events\\\\Courses\\\\Completion_deleted\",\n        \"Events\\\\Courses\\\\Completion_archived\",\n        \"Events\\\\Courses\\\\*\",\n        \"Events\\\\Quiz\\\\Attempt_completed\",\n        \"Events\\\\Quiz\\\\*\",\n        \"*\"\n    ]\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            }
          ],
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "4fd1e6d6-407a-4413-9fb6-612bade8badd",
          "name": "List Webhooks",
          "request": {
            "name": "List Webhooks",
            "description": {
              "content": "Lists all webhook subscriptions for the authenticated API key. Secrets (signing_key, auth_token) are masked in the response (shows `\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022` + last 4 characters), or `null` when unset.",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "api",
                "v2",
                "{{tenancy_id}}",
                "webhooks"
              ],
              "host": [
                "{{base_url}}"
              ],
              "query": [
                {
                  "disabled": true,
                  "description": {
                    "content": "integer - optional, the page number to return (default: 1)",
                    "type": "text/plain"
                  },
                  "key": "page",
                  "value": "1"
                },
                {
                  "disabled": true,
                  "description": {
                    "content": "integer - optional, the number of results per page (default: 50; values outside 1-100 are clamped to that range)",
                    "type": "text/plain"
                  },
                  "key": "perPage",
                  "value": "1"
                }
              ],
              "variable": []
            },
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "body": {},
            "auth": null
          },
          "response": [
            {
              "name": "List Webhooks",
              "originalRequest": {
                "url": {
                  "path": [
                    "api",
                    "v2",
                    "{{tenancy_id}}",
                    "webhooks"
                  ],
                  "host": [
                    "{{base_url}}"
                  ],
                  "query": [
                    {
                      "disabled": true,
                      "description": {
                        "content": "integer - optional, the page number to return (default: 1)",
                        "type": "text/plain"
                      },
                      "key": "page",
                      "value": "1"
                    },
                    {
                      "disabled": true,
                      "description": {
                        "content": "integer - optional, the number of results per page (default: 50; values outside 1-100 are clamped to that range)",
                        "type": "text/plain"
                      },
                      "key": "perPage",
                      "value": "1"
                    }
                  ],
                  "variable": []
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "description": {
                      "content": "Added as a part of security scheme: bearer",
                      "type": "text/plain"
                    },
                    "key": "Authorization",
                    "value": "Bearer <token>"
                  }
                ],
                "method": "GET",
                "body": {}
              },
              "status": "OK",
              "code": 200,
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                },
                {
                  "disabled": true,
                  "description": {
                    "content": "",
                    "type": "text/plain"
                  },
                  "key": "X-RateLimit-Limit",
                  "value": "60"
                },
                {
                  "disabled": true,
                  "description": {
                    "content": "",
                    "type": "text/plain"
                  },
                  "key": "X-RateLimit-Remaining",
                  "value": "59"
                }
              ],
              "body": "{\n    \"data\": [\n        {\n            \"id\": 30,\n            \"event\": \"Events\\\\Courses\\\\*\",\n            \"url\": \"https://example.com/webhook/79d769db-1b8d-4483-bf2b-b242eae0fa9b\",\n            \"content_type_header\": \"application/json\",\n            \"is_enabled\": true,\n            \"auth_type\": null,\n            \"signing_key\": \"\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022c256\",\n            \"auth_token\": \"\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022oken\",\n            \"created_at\": \"2026-04-16T05:11:33+00:00\",\n            \"updated_at\": \"2026-04-16T05:11:33+00:00\"\n        }\n    ],\n    \"meta\": {\n        \"current_page\": 1,\n        \"per_page\": 1,\n        \"total\": 1,\n        \"last_page\": 1,\n        \"next\": null,\n        \"prev\": null\n    }\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            }
          ],
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "5a7a387e-8620-422e-9cf7-d031c60cbfa8",
          "name": "Create Webhook",
          "request": {
            "name": "Create Webhook",
            "description": {
              "content": "Creates a new webhook subscription.\n\n**Body fields:**\n- `event` - required, the event to subscribe to\n- `url` - required, the destination URL (must be HTTPS)\n- `signing_key` - optional, nullable. When set, deliveries include an `X-Signature` header containing an HMAC-SHA256 signature of the payload\n- `auth_token` - optional, nullable. When set, deliveries include an `Authorization: Bearer` header with this token\n- `auth_type` - optional, nullable, one of `bearer`, `hmac`, `both`. Display-only label; the authentication actually applied to deliveries is inferred from which credentials are set (`signing_key`, `auth_token`)\n- `content_type_header` - optional, `application/json` or `application/x-www-form-urlencoded`. Display-only; deliveries are always sent as `application/json`\n- `is_enabled` - optional boolean\n\n**Business rules (422):**\n- Maximum of 100 subscriptions per API key: \"Maximum of 100 subscriptions per API key reached.\"\n- The same event + URL pair cannot be subscribed twice: \"A subscription for this event and URL already exists.\"\n\n**Create Webhook - Wildcard Event**\n\nCreates a webhook subscription that listens to ALL events in a category using the wildcard `*` character.\n\nExamples:\n- `Events\\\\Notifications\\\\*` - All notification events\n- `Events\\\\Users\\\\*` - All user events\n- `Events\\\\Courses\\\\*` - All course events\n- `*` - ALL events (use with caution!)\n\nBody fields and business rules (max 100 subscriptions per API key, no duplicate event + URL pairs) are the same as Create Webhook.",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "api",
                "v2",
                "{{tenancy_id}}",
                "webhooks"
              ],
              "host": [
                "{{base_url}}"
              ],
              "query": [],
              "variable": []
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"event\": \"Events\\\\Courses\\\\*\",\n  \"url\": \"https://example.com/webhook/79d769db-1b8d-4483-bf2b-b242eae0fa9b\",\n  \"content_type_header\": \"application/json\",\n  \"signing_key\": \"signing-key-hmac256\",\n  \"auth_token\": \"auth-token\",\n  \"is_enabled\": true\n}",
              "options": {
                "raw": {
                  "headerFamily": "json",
                  "language": "json"
                }
              }
            },
            "auth": null
          },
          "response": [
            {
              "id": "fc39a137-540e-4b97-b215-53c94aaedd40",
              "name": "Create Webhook",
              "originalRequest": {
                "url": {
                  "path": [
                    "api",
                    "v2",
                    "{{tenancy_id}}",
                    "webhooks"
                  ],
                  "host": [
                    "{{base_url}}"
                  ],
                  "query": [],
                  "variable": []
                },
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "description": {
                      "content": "Added as a part of security scheme: bearer",
                      "type": "text/plain"
                    },
                    "key": "Authorization",
                    "value": "Bearer <token>"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"event\": \"Events\\\\Courses\\\\*\",\n  \"url\": \"https://example.com/webhook/79d769db-1b8d-4483-bf2b-b242eae0fa9b\",\n  \"content_type_header\": \"application/json\",\n  \"signing_key\": \"signing-key-hmac256\",\n  \"auth_token\": \"auth-token\",\n  \"is_enabled\": true\n}",
                  "options": {
                    "raw": {
                      "headerFamily": "json",
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Created",
              "code": 201,
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                },
                {
                  "disabled": true,
                  "description": {
                    "content": "",
                    "type": "text/plain"
                  },
                  "key": "X-RateLimit-Limit",
                  "value": "60"
                },
                {
                  "disabled": true,
                  "description": {
                    "content": "",
                    "type": "text/plain"
                  },
                  "key": "X-RateLimit-Remaining",
                  "value": "57"
                }
              ],
              "body": "{\n  \"id\": 30,\n  \"event\": \"Events\\\\Courses\\\\*\",\n  \"url\": \"https://example.com/webhook/79d769db-1b8d-4483-bf2b-b242eae0fa9b\",\n  \"content_type_header\": \"application/json\",\n  \"is_enabled\": true,\n  \"auth_type\": null,\n  \"signing_key\": \"signing-key-hmac256\",\n  \"auth_token\": \"auth-token\",\n  \"created_at\": \"2026-04-16T05:11:33+00:00\",\n  \"updated_at\": \"2026-04-16T05:11:33+00:00\"\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "32c390dc-a084-4d9a-9554-e22e71c54f4e",
              "name": "Create Webhook - Wildcard Event",
              "originalRequest": {
                "url": {
                  "path": [
                    "api",
                    "v2",
                    "{{tenancy_id}}",
                    "webhooks"
                  ],
                  "host": [
                    "{{base_url}}"
                  ],
                  "query": [],
                  "variable": []
                },
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "description": {
                      "content": "Added as a part of security scheme: bearer",
                      "type": "text/plain"
                    },
                    "key": "Authorization",
                    "value": "Bearer <token>"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"event\": \"*\",\n  \"url\": \"https://example.com/webhook/79d769db-1b8d-4483-bf2b-b242eae0fa9b\",\n  \"content_type_header\": \"application/json\",\n  \"signing_key\": \"signing-key-hmac256\",\n  \"auth_token\": \"auth-token\",\n  \"is_enabled\": true\n}",
                  "options": {
                    "raw": {
                      "headerFamily": "json",
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Created",
              "code": 201,
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                },
                {
                  "disabled": true,
                  "description": {
                    "content": "",
                    "type": "text/plain"
                  },
                  "key": "X-RateLimit-Limit",
                  "value": "60"
                },
                {
                  "disabled": true,
                  "description": {
                    "content": "",
                    "type": "text/plain"
                  },
                  "key": "X-RateLimit-Remaining",
                  "value": "57"
                }
              ],
              "body": "{\n  \"id\": 31,\n  \"event\": \"*\",\n  \"url\": \"https://example.com/webhook/79d769db-1b8d-4483-bf2b-b242eae0fa9b\",\n  \"content_type_header\": \"application/json\",\n  \"is_enabled\": true,\n  \"auth_type\": null,\n  \"signing_key\": \"signing-key-hmac256\",\n  \"auth_token\": \"auth-token\",\n  \"created_at\": \"2026-04-16T05:18:29+00:00\",\n  \"updated_at\": \"2026-04-16T05:18:29+00:00\"\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            }
          ],
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "b865bad9-c3c3-402c-9ea7-a7259eefd117",
          "name": "Get Webhook by ID",
          "request": {
            "name": "Get Webhook by ID",
            "description": {
              "content": "Retrieves a specific webhook subscription by ID. Secrets (signing_key, auth_token) are masked in the response (shows `\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022` + last 4 characters), or `null` when unset.",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "api",
                "v2",
                "{{tenancy_id}}",
                "webhooks",
                ":webhook_id"
              ],
              "host": [
                "{{base_url}}"
              ],
              "query": [],
              "variable": [
                {
                  "type": "any",
                  "value": "",
                  "key": "webhook_id",
                  "disabled": false,
                  "description": {
                    "content": "(Required) ",
                    "type": "text/plain"
                  }
                }
              ]
            },
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "body": {},
            "auth": null
          },
          "response": [
            {
              "name": "Get Webhook by ID",
              "originalRequest": {
                "url": {
                  "path": [
                    "api",
                    "v2",
                    "{{tenancy_id}}",
                    "webhooks",
                    ":webhook_id"
                  ],
                  "host": [
                    "{{base_url}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "disabled": false,
                      "description": {
                        "content": "(Required) ",
                        "type": "text/plain"
                      },
                      "type": "any",
                      "value": "",
                      "key": "webhook_id"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "description": {
                      "content": "Added as a part of security scheme: bearer",
                      "type": "text/plain"
                    },
                    "key": "Authorization",
                    "value": "Bearer <token>"
                  }
                ],
                "method": "GET",
                "body": {}
              },
              "status": "OK",
              "code": 200,
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                },
                {
                  "disabled": true,
                  "description": {
                    "content": "",
                    "type": "text/plain"
                  },
                  "key": "X-RateLimit-Limit",
                  "value": "60"
                },
                {
                  "disabled": true,
                  "description": {
                    "content": "",
                    "type": "text/plain"
                  },
                  "key": "X-RateLimit-Remaining",
                  "value": "56"
                }
              ],
              "body": "{\n    \"id\": 30,\n    \"event\": \"Events\\\\Courses\\\\*\",\n    \"url\": \"https://example.com/webhook/79d769db-1b8d-4483-bf2b-b242eae0fa9b\",\n    \"content_type_header\": \"application/json\",\n    \"is_enabled\": true,\n    \"auth_type\": null,\n    \"signing_key\": \"\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022c256\",\n    \"auth_token\": \"\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022oken\",\n    \"created_at\": \"2026-04-16T05:11:33+00:00\",\n    \"updated_at\": \"2026-04-16T05:11:33+00:00\"\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            }
          ],
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "3d834de8-b7f6-4bb1-97c5-30cca538fef7",
          "name": "Update Webhook",
          "request": {
            "name": "Update Webhook",
            "description": {
              "content": "Updates an existing webhook subscription. `PUT` is also accepted and behaves identically. All fields are optional - only include the fields you want to change.\n\n**Updatable fields:**\n- `event` - Change the event type\n- `url` - Change the destination URL (must be HTTPS)\n- `auth_type` - Change the authentication label (`bearer`, `hmac`, `both`). Display-only; the authentication actually applied to deliveries is inferred from which credentials are set (`signing_key`, `auth_token`)\n- `auth_token` - Update the bearer token (the HMAC secret is `signing_key`)\n- `signing_key` - Update the HMAC-SHA256 signing key\n- `content_type_header` - Change the content type label. Display-only; deliveries are always sent as `application/json`\n- `is_enabled` - Enable/disable the webhook\n\nIf the request body includes `signing_key` or `auth_token`, the response echoes those values unmasked; otherwise secrets are masked as usual.",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "api",
                "v2",
                "{{tenancy_id}}",
                "webhooks",
                ":webhook_id"
              ],
              "host": [
                "{{base_url}}"
              ],
              "query": [],
              "variable": [
                {
                  "type": "any",
                  "value": "",
                  "key": "webhook_id",
                  "disabled": false,
                  "description": {
                    "content": "(Required) ",
                    "type": "text/plain"
                  }
                }
              ]
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "PATCH",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"is_enabled\": false,\n  \"url\": \"https://example.com/webhook/e1a03fe3-be2b-490d-a23b-020793f2d046\"\n}",
              "options": {
                "raw": {
                  "headerFamily": "json",
                  "language": "json"
                }
              }
            },
            "auth": null
          },
          "response": [
            {
              "name": "Update Webhook",
              "originalRequest": {
                "url": {
                  "path": [
                    "api",
                    "v2",
                    "{{tenancy_id}}",
                    "webhooks",
                    ":webhook_id"
                  ],
                  "host": [
                    "{{base_url}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "disabled": false,
                      "description": {
                        "content": "(Required) ",
                        "type": "text/plain"
                      },
                      "type": "any",
                      "value": "",
                      "key": "webhook_id"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "description": {
                      "content": "Added as a part of security scheme: bearer",
                      "type": "text/plain"
                    },
                    "key": "Authorization",
                    "value": "Bearer <token>"
                  }
                ],
                "method": "PATCH",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"is_enabled\": false,\n  \"url\": \"https://example.com/webhook/e1a03fe3-be2b-490d-a23b-020793f2d046\"\n}",
                  "options": {
                    "raw": {
                      "headerFamily": "json",
                      "language": "json"
                    }
                  }
                }
              },
              "status": "OK",
              "code": 200,
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                },
                {
                  "disabled": true,
                  "description": {
                    "content": "",
                    "type": "text/plain"
                  },
                  "key": "X-RateLimit-Limit",
                  "value": "60"
                },
                {
                  "disabled": true,
                  "description": {
                    "content": "",
                    "type": "text/plain"
                  },
                  "key": "X-RateLimit-Remaining",
                  "value": "59"
                }
              ],
              "body": "{\n    \"id\": 30,\n    \"event\": \"Events\\\\Courses\\\\*\",\n    \"url\": \"https://example.com/webhook/e1a03fe3-be2b-490d-a23b-020793f2d046\",\n    \"content_type_header\": \"application/json\",\n    \"is_enabled\": true,\n    \"auth_type\": null,\n    \"signing_key\": \"\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022c256\",\n    \"auth_token\": \"\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022oken\",\n    \"created_at\": \"2026-04-16T05:11:33+00:00\",\n    \"updated_at\": \"2026-04-16T05:14:18+00:00\"\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            }
          ],
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "60140320-ef99-49ee-9da9-c1be02a625f1",
          "name": "Delete Webhook",
          "request": {
            "name": "Delete Webhook",
            "description": {
              "content": "Soft-deletes a webhook subscription. The subscription is marked as deleted but retained in the database for audit purposes. No further events will be dispatched to this webhook.\n\nReturns 204 No Content on success.",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "api",
                "v2",
                "{{tenancy_id}}",
                "webhooks",
                ":webhook_id"
              ],
              "host": [
                "{{base_url}}"
              ],
              "query": [],
              "variable": [
                {
                  "type": "any",
                  "value": "",
                  "key": "webhook_id",
                  "disabled": false,
                  "description": {
                    "content": "(Required) ",
                    "type": "text/plain"
                  }
                }
              ]
            },
            "header": [
              {
                "key": "Accept",
                "value": "text/plain"
              }
            ],
            "method": "DELETE",
            "body": {},
            "auth": null
          },
          "response": [
            {
              "name": "Delete Webhook",
              "originalRequest": {
                "url": {
                  "path": [
                    "api",
                    "v2",
                    "{{tenancy_id}}",
                    "webhooks",
                    ":webhook_id"
                  ],
                  "host": [
                    "{{base_url}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "disabled": false,
                      "description": {
                        "content": "(Required) ",
                        "type": "text/plain"
                      },
                      "type": "any",
                      "value": "",
                      "key": "webhook_id"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "text/plain"
                  },
                  {
                    "description": {
                      "content": "Added as a part of security scheme: bearer",
                      "type": "text/plain"
                    },
                    "key": "Authorization",
                    "value": "Bearer <token>"
                  }
                ],
                "method": "DELETE",
                "body": {}
              },
              "status": "No Content",
              "code": 204,
              "header": [
                {
                  "key": "Content-Type",
                  "value": "text/plain"
                },
                {
                  "disabled": true,
                  "description": {
                    "content": "",
                    "type": "text/plain"
                  },
                  "key": "X-RateLimit-Limit",
                  "value": "60"
                },
                {
                  "disabled": true,
                  "description": {
                    "content": "",
                    "type": "text/plain"
                  },
                  "key": "X-RateLimit-Remaining",
                  "value": "59"
                }
              ],
              "body": "",
              "cookie": [],
              "_postman_previewlanguage": "text"
            }
          ],
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "4a4ed2b7-f349-49b6-ae10-82715108eace",
          "name": "Get Webhook Logs",
          "request": {
            "name": "Get Webhook Logs",
            "description": {
              "content": "Retrieves delivery log history for a specific webhook subscription. Shows delivery attempts, success/failure status, response codes, and retry counts.\n\nLog entries include:\n- `id` - Log entry ID\n- `event_type` - The event that was delivered\n- `delivery_id` - string, empty for normal deliveries\n- `success` - Boolean delivery status\n- `tries` - Number of delivery attempts\n- `status_code` - HTTP status code returned by the endpoint (integer or null)\n- `response` - HTTP response from the webhook endpoint\n- `response_time_ms` - Response time in milliseconds (integer or null)\n- `redispatched` - Whether the delivery was manually redispatched\n- `created_at` - Timestamp of delivery attempt\n- `updated_at` - Timestamp of the last update to the log entry\n\nThe event payload is not included in log entries.",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "api",
                "v2",
                "{{tenancy_id}}",
                "webhooks",
                ":webhook_id",
                "logs"
              ],
              "host": [
                "{{base_url}}"
              ],
              "query": [
                {
                  "disabled": true,
                  "description": {
                    "content": "integer - optional, the page number to return (default: 1)",
                    "type": "text/plain"
                  },
                  "key": "page",
                  "value": "1"
                },
                {
                  "disabled": true,
                  "description": {
                    "content": "integer - optional, the number of log entries per page (default: 50; values outside 1-100 are clamped to that range)",
                    "type": "text/plain"
                  },
                  "key": "perPage",
                  "value": "10"
                }
              ],
              "variable": [
                {
                  "type": "any",
                  "value": "",
                  "key": "webhook_id",
                  "disabled": false,
                  "description": {
                    "content": "(Required) ",
                    "type": "text/plain"
                  }
                }
              ]
            },
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "body": {},
            "auth": null
          },
          "response": [
            {
              "name": "Get Webhook Logs",
              "originalRequest": {
                "url": {
                  "path": [
                    "api",
                    "v2",
                    "{{tenancy_id}}",
                    "webhooks",
                    ":webhook_id",
                    "logs"
                  ],
                  "host": [
                    "{{base_url}}"
                  ],
                  "query": [
                    {
                      "disabled": true,
                      "description": {
                        "content": "integer - optional, the page number to return (default: 1)",
                        "type": "text/plain"
                      },
                      "key": "page",
                      "value": "1"
                    },
                    {
                      "disabled": true,
                      "description": {
                        "content": "integer - optional, the number of log entries per page (default: 50; values outside 1-100 are clamped to that range)",
                        "type": "text/plain"
                      },
                      "key": "perPage",
                      "value": "10"
                    }
                  ],
                  "variable": [
                    {
                      "disabled": false,
                      "description": {
                        "content": "(Required) ",
                        "type": "text/plain"
                      },
                      "type": "any",
                      "value": "",
                      "key": "webhook_id"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "description": {
                      "content": "Added as a part of security scheme: bearer",
                      "type": "text/plain"
                    },
                    "key": "Authorization",
                    "value": "Bearer <token>"
                  }
                ],
                "method": "GET",
                "body": {}
              },
              "status": "OK",
              "code": 200,
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                },
                {
                  "disabled": true,
                  "description": {
                    "content": "",
                    "type": "text/plain"
                  },
                  "key": "X-RateLimit-Limit",
                  "value": "60"
                },
                {
                  "disabled": true,
                  "description": {
                    "content": "",
                    "type": "text/plain"
                  },
                  "key": "X-RateLimit-Remaining",
                  "value": "59"
                }
              ],
              "body": "{\n    \"data\": [\n        {\n            \"id\": 248,\n            \"event_type\": \"Events\\\\Courses\\\\Completion_created\",\n            \"delivery_id\": \"\",\n            \"success\": true,\n            \"tries\": 1,\n            \"status_code\": 200,\n            \"response\": \"{\\\"message\\\":\\\"Workflow was started\\\"}\",\n            \"response_time_ms\": 152,\n            \"redispatched\": false,\n            \"created_at\": \"2026-04-16T05:16:32+00:00\",\n            \"updated_at\": \"2026-04-16T05:16:38+00:00\"\n        },\n        {\n            \"id\": 247,\n            \"event_type\": \"Events\\\\Courses\\\\Completion_archived\",\n            \"delivery_id\": \"\",\n            \"success\": false,\n            \"tries\": 1,\n            \"status_code\": 405,\n            \"response\": \"Client error: `POST https://example.com/webhook/e1a03fe3-be2b-490d-a23b-020793f2d046` resulted in a `405 Method Not Allowed` response:\\n<!doctype html><html lang=\\\"en\\\"><head><title>Example Domain</title><meta name=\\\"viewport\\\" content=\\\"width=device-width, ini (truncated...)\\n\",\n            \"response_time_ms\": 87,\n            \"redispatched\": false,\n            \"created_at\": \"2026-04-16T05:16:29+00:00\",\n            \"updated_at\": \"2026-04-16T05:16:32+00:00\"\n        }\n    ],\n    \"meta\": {\n        \"current_page\": 1,\n        \"per_page\": 10,\n        \"total\": 2,\n        \"last_page\": 1,\n        \"next\": null,\n        \"prev\": null\n    }\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            }
          ],
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "f2a300e3-83a0-4488-b675-1006b167cfdf",
          "name": "Redispatch Failed Webhook",
          "request": {
            "name": "Redispatch Failed Webhook",
            "description": {
              "content": "Retries a failed webhook delivery. Useful for recovering from temporary failures or after fixing configuration issues.\n\nThe webhook will be queued for immediate dispatch unless the original payload model no longer exists in the database.",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "api",
                "v2",
                "{{tenancy_id}}",
                "webhooks",
                ":webhook_id",
                "logs",
                ":log_id",
                "redispatch"
              ],
              "host": [
                "{{base_url}}"
              ],
              "query": [],
              "variable": [
                {
                  "type": "any",
                  "value": "",
                  "key": "webhook_id",
                  "disabled": false,
                  "description": {
                    "content": "(Required) ",
                    "type": "text/plain"
                  }
                },
                {
                  "type": "any",
                  "value": "",
                  "key": "log_id",
                  "disabled": false,
                  "description": {
                    "content": "(Required) ",
                    "type": "text/plain"
                  }
                }
              ]
            },
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "body": {},
            "auth": null
          },
          "response": [
            {
              "name": "Redispatch Failed Webhook",
              "originalRequest": {
                "url": {
                  "path": [
                    "api",
                    "v2",
                    "{{tenancy_id}}",
                    "webhooks",
                    ":webhook_id",
                    "logs",
                    ":log_id",
                    "redispatch"
                  ],
                  "host": [
                    "{{base_url}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "disabled": false,
                      "description": {
                        "content": "(Required) ",
                        "type": "text/plain"
                      },
                      "type": "any",
                      "value": "",
                      "key": "webhook_id"
                    },
                    {
                      "disabled": false,
                      "description": {
                        "content": "(Required) ",
                        "type": "text/plain"
                      },
                      "type": "any",
                      "value": "",
                      "key": "log_id"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "description": {
                      "content": "Added as a part of security scheme: bearer",
                      "type": "text/plain"
                    },
                    "key": "Authorization",
                    "value": "Bearer <token>"
                  }
                ],
                "method": "POST",
                "body": {}
              },
              "status": "OK",
              "code": 200,
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                },
                {
                  "disabled": true,
                  "description": {
                    "content": "",
                    "type": "text/plain"
                  },
                  "key": "X-RateLimit-Limit",
                  "value": "60"
                },
                {
                  "disabled": true,
                  "description": {
                    "content": "",
                    "type": "text/plain"
                  },
                  "key": "X-RateLimit-Remaining",
                  "value": "56"
                }
              ],
              "body": "{\n    \"data\": {\n        \"success\": true,\n        \"message\": \"Redispatch requested for log 246\",\n        \"event\": \"Events\\\\Courses\\\\Completion_created\"\n    }\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            }
          ],
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "4c8b784c-dd17-4e98-94c4-d3cff1a1b1eb",
          "name": "Relay Webhook Contents",
          "request": {
            "name": "Relay Webhook Contents",
            "description": {
              "content": "Returns a sample payload for the specified event type. Useful for testing webhook integrations without waiting for a real LMS event. This endpoint never delivers to your webhook subscriptions.\n\n**Body fields:**\n- `event` - required, the fully-qualified event name to sample (e.g., `Events\\\\Users\\\\Created`). Wildcard events (`*`, `Events\\\\Users\\\\*`) are rejected with a 422: \"Wildcard events are not allowed for relay.\"\n- `url` - optional, an HTTPS URL (same validation as webhook URLs). When omitted, no delivery is made and the sample payload is returned. When provided, the sample event is delivered to that URL and the response instead contains the delivery result: `{\"data\": {\"success\": true, \"data\": \"<raw response body string>\", \"status_code\": 200, \"response_time_ms\": 152}}`",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "api",
                "v2",
                "{{tenancy_id}}",
                "webhooks",
                "relay"
              ],
              "host": [
                "{{base_url}}"
              ],
              "query": [],
              "variable": []
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"event\": \"Events\\\\Courses\\\\Completion_created\"\n}",
              "options": {
                "raw": {
                  "headerFamily": "json",
                  "language": "json"
                }
              }
            },
            "auth": null
          },
          "response": [
            {
              "name": "Relay Webhook Contents",
              "originalRequest": {
                "url": {
                  "path": [
                    "api",
                    "v2",
                    "{{tenancy_id}}",
                    "webhooks",
                    "relay"
                  ],
                  "host": [
                    "{{base_url}}"
                  ],
                  "query": [],
                  "variable": []
                },
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "Accept",
                    "value": "application/json"
                  },
                  {
                    "description": {
                      "content": "Added as a part of security scheme: bearer",
                      "type": "text/plain"
                    },
                    "key": "Authorization",
                    "value": "Bearer <token>"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"event\": \"Events\\\\Courses\\\\Completion_created\"\n}",
                  "options": {
                    "raw": {
                      "headerFamily": "json",
                      "language": "json"
                    }
                  }
                }
              },
              "status": "OK",
              "code": 200,
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                },
                {
                  "disabled": true,
                  "description": {
                    "content": "",
                    "type": "text/plain"
                  },
                  "key": "X-RateLimit-Limit",
                  "value": "60"
                },
                {
                  "disabled": true,
                  "description": {
                    "content": "",
                    "type": "text/plain"
                  },
                  "key": "X-RateLimit-Remaining",
                  "value": "59"
                }
              ],
              "body": "{\n    \"data\": {\n        \"success\": true,\n        \"data\": {\n            \"event\": \"Events\\\\Courses\\\\Completion_created\",\n            \"payload\": {\n                \"completion\": {\n                    \"id\": 1,\n                    \"user_id\": 3,\n                    \"user\": {\n                        \"id\": 3,\n                        \"username\": \"john.smith@example.com\",\n                        \"email\": \"john.smith@example.com\",\n                        \"firstname\": \"John\",\n                        \"lastname\": \"Smith\"\n                    },\n                    \"userdata\": [],\n                    \"content_id\": 3,\n                    \"content_type\": \"Course\",\n                    \"content\": {\n                        \"id\": 3,\n                        \"fullname\": \"Example Course\",\n                        \"summary\": \"This is an example course\",\n                        \"timecreated\": 1730333561\n                    },\n                    \"contentdata\": [],\n                    \"certificate_link\": \"\",\n                    \"time_enrolled\": \"2026-04-15T23:02:59+00:00\",\n                    \"time_started\": \"2026-04-15T23:02:59+00:00\",\n                    \"time_completed\": \"2026-04-15T23:03:00+00:00\"\n                }\n            },\n            \"now\": 1776294179,\n            \"delivery_id\": \"\",\n            \"api_version\": \"2.0\"\n        }\n    }\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            }
          ],
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        }
      ]
    }
  ],
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{api_key}}",
        "type": "string"
      }
    ]
  },
  "event": [],
  "info": {
    "_postman_id": "437413f7-574c-431f-9a5e-f3df9c557cb2",
    "name": "Acorn Webhooks API",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
    "description": {
      "content": "**Overview**\n\nThe Acorn LMS's API is organised around REST. Our API has predictable resource-oriented URLs, accepts form-encoded request bodies, returns JSON-encoded responses, and uses standard HTTP response codes and authentication.\n\nTo start using the API, you will first need to setup your credentials. Acorn will provide you with a Base URL, Tenancy ID, Username and Initial Refresh Token. These can be used to access all API endpoints. To start this process, please contact [Acorn Support](https://help.acorn.works).\n\n**Rate Limiting**\n\nTo protect our API from abuse and ensure fair usage, we enforce a rate limit of **60 requests per minute per API key**. If an API key exceeds that limit, the server returns an HTTP 429 (Too Many Requests) response. If you have a use case that requires a higher rate limit please contact [Acorn Support](https://help.acorn.works).",
      "type": "text/plain"
    }
  }
}