> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://developers.alephant.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developers.alephant.io/_mcp/server.

# Hook Extensions

> Connect governed external endpoints to document ingestion, document push, and query processing hook points.

Hook Extensions POST a defined JSON payload to an administrator-managed endpoint and validate the returned JSON object before the pipeline uses it. Treat every hook as an outbound data boundary and a synchronous dependency.

Hooks have three backend hard boundaries: the management router and HTTP executor come from the enterprise-capable (EE) server, the deployment must be single-tenant, and every management endpoint requires full Admin Panel access. Community-only execution returns a no-op result, and the management dependency rejects multi-tenant deployments. The current web UI also applies its Enterprise tier check and reads `hooks_enabled`, but the server derives that setting from `not MULTI_TENANT`; the current license and tier middleware are pass-through rather than independent backend gates.

## Endpoint and authentication contract

| Setting      | Contract                                                                               | Boundary                                                                                |
| ------------ | -------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
| Endpoint URL | OpenCore sends an HTTP `POST` with `Content-Type: application/json`.                   | Use an approved endpoint and do not rely on redirects; the client does not follow them. |
| API key      | Optional in the backend contract; the current create form requires it.                 | When configured, OpenCore sends `Authorization: Bearer <HOOK_API_KEY>`.                 |
| Response     | A successful call must return a 2xx status and a JSON object valid for the hook point. | Non-JSON, arrays, HTTP errors, timeouts, and schema failures are hook failures.         |
| Activation   | Only one active, non-deleted configuration for a hook point is executed.               | An absent, inactive, or endpoint-less hook is skipped.                                  |

Never reuse an end-user token as the Hook API key. Rotate the key through the Admin Panel, verify the endpoint again, and prevent request or response bodies from entering error logs.

## Document Ingestion

This hook runs for every document after internal validation and before indexing writes. All top-level input fields are required; fields described as nullable may carry `null`.

| Input field           | Type           | Meaning                                                                                                                       |
| --------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `document_id`         | string         | Unique read-only document identifier; response changes are ignored.                                                           |
| `title`               | string or null | Document title.                                                                                                               |
| `semantic_identifier` | string         | Human-readable identifier such as a file name or page title.                                                                  |
| `source`              | string         | Read-only connector source; response changes are ignored.                                                                     |
| `sections`            | array          | Ordered text or image sections. Each item carries nullable `text`, `link`, and `image_file_id`; the image bytes are not sent. |
| `metadata`            | object         | String keys mapped to arrays of strings.                                                                                      |
| `doc_updated_at`      | string or null | Source update time in ISO 8601 UTC form when known.                                                                           |
| `primary_owners`      | array or null  | Owner objects with nullable `display_name` and `email`.                                                                       |
| `secondary_owners`    | array or null  | Secondary owner objects with the same shape.                                                                                  |

| Output field       | Required          | Effect                                                                              |
| ------------------ | ----------------- | ----------------------------------------------------------------------------------- |
| `sections`         | Yes, but nullable | Reorders, drops, or rewrites sections. `null` or an empty array drops the document. |
| `rejection_reason` | No                | Logged when the document is dropped; a generic reason is used when omitted.         |

The default timeout is **30 seconds** and the default fail strategy is **hard**. A hard endpoint or validation failure prevents that document from being indexed. A soft failure ignores the Hook result and continues with the original document.

## Document Push

This hook runs only after the entire batch has completed its vector database writes and `post_index` work. OpenCore then iterates the successfully indexed public documents and pushes each one. It runs only in single-tenant deployments, and `from_beginning=True` skips Document Push entirely. When the environment-configured document-push sink is set, that sink takes precedence and this managed Hook is not called.

| Input field      | Type           | Meaning                                             |
| ---------------- | -------------- | --------------------------------------------------- |
| `document_id`    | string         | Unique document identifier.                         |
| `title`          | string or null | Document title.                                     |
| `content`        | string         | Full text content with text sections concatenated.  |
| `source`         | string         | Connector source.                                   |
| `url`            | string or null | Canonical source URL when available.                |
| `doc_updated_at` | string or null | Source update time in ISO 8601 UTC form when known. |
| `metadata`       | object         | String keys mapped to arrays of strings.            |

Return a JSON object; `{}` is sufficient because Document Push does not consume response fields. The default timeout is **30 seconds** and the default strategy is **soft**, so failures are logged and iteration normally continues. If an Administrator overrides the strategy to hard, a failure can mark or raise the batch as failed at this late stage: successful documents have already been written, `post_index` has completed, and earlier pushes in the iteration may already have succeeded.

## Query Processing

This hook runs on the raw user query before the chat message is saved. Its input rejects unknown fields.

| Input field       | Type           | Meaning                                                      |
| ----------------- | -------------- | ------------------------------------------------------------ |
| `query`           | string         | Raw query exactly as entered by the user.                    |
| `user_email`      | string or null | Submitting user's email, or `null` when unauthenticated.     |
| `chat_session_id` | string         | Existing chat session UUID as a lowercase hyphenated string. |

| Output field        | Required | Effect                                                                                  |
| ------------------- | -------- | --------------------------------------------------------------------------------------- |
| `query`             | No       | Replaces the query. Missing, `null`, empty, or whitespace-only values reject the query. |
| `rejection_message` | No       | User-facing rejection text; a generic message is used when omitted.                     |

The default timeout is **5 seconds** and the default strategy is **hard** because the user is waiting synchronously. A hard failure blocks the query and shows an error. A soft failure ignores the Hook result and continues with the original query.

## Timeout and failure strategy

The Admin Panel accepts a timeout greater than `0` and at most `600` seconds. Use the per-point default unless the endpoint has a measured reason to differ.

| Hook point         | Default          | Hard failure                                                                                              | Soft failure                                             |
| ------------------ | ---------------- | --------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
| Document Ingestion | 30 seconds, hard | Document is not indexed.                                                                                  | Original document continues.                             |
| Document Push      | 30 seconds, soft | Batch fails late, after successful document writes and `post_index`; earlier pushes may already have run. | Failure is logged and document-push iteration continues. |
| Query Processing   | 5 seconds, hard  | Query is blocked.                                                                                         | Original query continues.                                |

Soft mode does not make an invalid response valid; it only determines what the pipeline does after failure. Failed executions are recorded, while successful executions are not added to the failure log.

## Configure and operate

1. Confirm the enterprise-capable server is running in single-tenant mode and the operator has full Admin Panel access. Then confirm the current web UI exposes **Admin Panel → Hook Extensions**; its Enterprise tier and `hooks_enabled` checks are UI conditions, not additional backend license enforcement.
2. Choose one hook point and deploy an endpoint that accepts its exact input model and returns its exact output model.
3. Set a display name, endpoint URL, API key, fail strategy, and timeout. Creation validates reachability and authentication.
4. Test with representative non-sensitive input, then activate the Hook and monitor endpoint latency and failed execution records.
5. To change the endpoint, policy, timeout, or key, update the Hook and validate again before relying on it.

## Verify

1. Return `{}` from a test endpoint and confirm Document Push accepts it, while the transforming hooks reject responses missing their required effective content.
2. For Document Ingestion, reorder sections, then return an empty section list and confirm the test document is dropped with the intended reason.
3. For Query Processing, rewrite a test query, then return whitespace and confirm the query is rejected before a message is saved.
4. Simulate a timeout, HTTP error, non-JSON response, and wrong JSON shape under both hard and soft strategies.
5. Deactivate the Hook and confirm the original pipeline continues without an outbound call.

## Related pages

* [Enterprise Integrations](/opencore/governance/enterprise-integrations) explains the overall conditional integration boundary.
* [Data Flows](/opencore/governance/data-flows) explains when documents and queries cross processing boundaries.
* [Connectors & Indexing](/opencore/knowledge/connectors) explains connector and indexing lifecycle.
* [Usage, Identity & Security](/opencore/governance/usage-and-security) covers secret and access controls.