Set up entity hooks
Setting up an entity hook involves three steps:
- Configure a notification channel.
- Create an entity hook action.
- Implement the logic to process the hook and respond.
1. Configure a notification channel
Hooks send notifications through the specialized entity feed. To receive these notifications, configure a notification channel by sending a POST request with the endpoint details.
Here's an example for an HTTP notification channel:
- CLI
- cURL
np notification channel create \
--body '{
"source": ["entity"],
"nrn": "organization=1:account=2:namespace=3",
"type": "http",
"configuration": {
"url": "https://yourdomain.com/url-you-configured"
}
}'
curl -L -X POST 'https://api.nullplatform.com/notification/channel' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"source": ["entity"],
"nrn": "organization=1:account=2:namespace=3",
"type": "http",
"configuration": {
"url": "https://yourdomain.com/url-you-configured"
}
}'
For more channel types and delivery options, see the Notifications documentation.
2. Create an entity hook action
An entity hook action declares that you want to receive notifications for a specific event on an entity type. Create an entity hook action with the event and scope you want to subscribe to:
- CLI
- cURL
np entity-hook action create \
--body '{
"nrn": "organization=1:account=2:namespace=3:application=4",
"entity": "scope",
"action": "scope:create",
"dimensions": {
"environment": "staging",
"country": "us"
},
"when": "before",
"type": "hook",
"on": "create"
}'
curl -L -X POST 'https://api.nullplatform.com/entity_hook/action' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"nrn": "organization=1:account=2:namespace=3:application=4",
"entity": "scope",
"action": "scope:create",
"dimensions": {
"environment": "staging",
"country": "us"
},
"when": "before",
"type": "hook",
"on": "create"
}'
Required parameters:
entity: The type of entity the hook applies to (application,scope,deployment).action: The event to subscribe to (for example,application:create,scope:write,deployment:delete).when: Whether the hook runsbeforeorafternullplatform's internal processing.type: The nature of the hook. Currently onlyhookis supported.on: The lifecycle event that triggers the hook:create,update, ordelete.
See the Entity hook API for the full parameter reference.
3. Implement hook processing
Once the hook action is configured, nullplatform starts sending notifications to your channel. Each notification carries a callback_url that points to the hook request: the record of that firing, which you can read at any time and respond to once your logic has run. Each notification has this format:
{
"id": "1180cd02-1c36-4274-8e7a-4483b87e8f2e",
"source": "entity",
"event": "scope:create",
"created_at": "2025-02-13T14:20:43.088Z",
"notification": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"entity": "scope",
"entity_id": "5",
"nrn": "organization=1:account=2:namespace=3:application=4:scope=5",
"callback_url": "https://api.nullplatform.com/entity_hook/550e8400-e29b-41d4-a716-446655440000",
"type": "hook",
"when": "before",
"on": "create"
}
}
Responding to a hook
You need an ops role to perform this action.
After processing the hook, send a PATCH request to the callback_url from the notification:
{
"status": "success",
"messages": [
{
"level": "info",
"message": "Information from the hook",
"timestamp": 1740406453123
},
{
"level": "warning",
"message": "Warning report",
"timestamp": 1740406527890
},
{
"level": "error",
"message": "The hook has failed",
"timestamp": 1740406604567
}
]
}
The status field controls how nullplatform handles the outcome:
| Status | Description |
|---|---|
success | Hook logic executed successfully. The entity operation proceeds. |
failed | Operation failed entirely. The entity enters an error state. |
recoverable_failure | Partial failure. The entity remains valid but some changes may not have been applied. Relevant for update hooks. |
cancelled | Entity operation halted because conditions were not met. |
The messages array is optional. Include it to give developers visibility into the hook's execution results.
Updating the entity from the hook
A before-hook can also hand data back to the entity it's gating. Add a callback_body object to the same PATCH request. When nullplatform resumes the entity operation, it merges those fields into the update it sends to the entity.
{
"status": "success",
"callback_body": {
"repository_url": "https://github.com/my-org/my-service",
"tags": {
"provisioned_by": "platform-hook"
}
}
}
For example, a before-hook on application:create can decide which repository the application lives in. The application is then created in the repository your hook chose, not in the one the developer typed.
Keep these rules in mind:
callback_bodyaccepts any field the entity's update endpoint accepts. There's no fixed list: whatever you'd send in aPATCHto that entity works here.- Fields nullplatform sets itself win. The entity
statusthat moves the operation forward can't be overridden fromcallback_body. You can add fields, but you can't change how nullplatform resumes the entity. callback_bodymust be a JSON object. Anything else is rejected with a400, and the hook stays pending so you can retry.- It's stored with the hook request and returned when you read the hook request, so you can always check what a hook handed back.
- It applies to whatever update runs for the
statusyou send. Most hooks use it withsuccess, but the merge also happens forfailed,recoverable_failure, andcancelled.
Optional: filter which events reach your endpoint
By default, the hook fires on every matching event for the entity, action, and dimensions you set. If you want to react only to some of those events (for example, only when a deployment fully switches traffic, or only when a scope is being stopped), you don't filter the hook itself. You filter the notification channel that the hook delivers through.
The hook stays generic; the channel decides which events get through. See Conditional firing for the filter syntax, supported operators, and worked examples.