--- description: A guide on how to build custom hooks in Directus. readTime: 7 min read --- # Custom API Hooks > Custom API Hooks allow running custom logic when a specified event occurs within your project. There are different > types of events to choose from. ## Extension Entrypoint The entrypoint of your hook is the `index` file inside the `src/` folder of your extension package. It exports a register function to register one or more event listeners. Example of an entrypoint: ```js export default ({ filter, action }) => { filter('items.create', () => { console.log('Creating Item!'); }); action('items.create', () => { console.log('Item created!'); }); }; ``` ## Events Your hook can trigger on a variety of different events. An event is defined by its type and its name. There are five event types to choose from: - [Filter](#filter) - [Action](#action) - [Init](#init) - [Schedule](#schedule) - [Embed](#embed) Use filter hooks when you want the hook to fire before the event. Use action hooks when you want the hook to fire after the event. ### Filter Filter hooks act on the event's payload before the event is fired. They allow you to check, modify, or cancel an event. Below is an example of canceling a `create` event by throwing a standard Directus exception. ```js export default ({ filter }, { exceptions }) => { const { InvalidPayloadException } = exceptions; filter('items.create', async (input) => { if (LOGIC_TO_CANCEL_EVENT) { throw new InvalidPayloadException(WHAT_IS_WRONG); } return input; }); }; ``` The filter register function receives two parameters: - The event name - A callback function that is executed whenever the event fires. The callback function itself receives three parameters: - The modifiable payload - An event-specific meta object - A context object The context object has the following properties: - `database` — The current database transaction - `schema` — The current API schema in use - `accountability` — Information about the current user ::: warning Performance Filters can impact performance when not carefully implemented, as they are executed in a blocking manner. This applies in particular to filters firing on `read` events, where a single request can result in a large amount of database reads. ::: ### Action Action hooks execute after a defined event and receive data related to the event. Use action hooks when you need to automate responses to CRUD events on items or server actions. The action register function receives two parameters: - The event name - A callback function that is executed whenever the event fires. The callback function itself receives two parameters: - An event-specific meta object - A context object The context object has the following properties: - `database` — The current database transaction - `schema` — The current API schema in use - `accountability` — Information about the current user ### Init Init hooks execute at a defined point within the life cycle of Directus. Use init hook objects to inject logic into internal services. The init register function receives two parameters: - The event name - A callback function that is executed whenever the event fires. The callback function itself receives one parameter: - An event-specific meta object ### Schedule Schedule hooks execute at certain points in time rather than when Directus performs a specific action. This is supported through [`node-cron`](https://www.npmjs.com/package/node-cron). To set up a scheduled event, provide a cron statement as the first parameter to the `schedule()` function. For example `schedule('15 14 1 * *', <...>)` (at 14:15 on day-of-month 1) or `schedule('5 4 * * sun', <...>)` (at 04:05 on Sunday). Below is an example of registering a schedule hook. ```js import axios from 'axios'; export default ({ schedule }) => { schedule('*/15 * * * *', async () => { await axios.post('http://example.com/webhook', { message: 'Another 15 minutes passed...' }); }); }; ``` ### Embed Inject custom JavaScript or CSS into the `
` and `` tags within the Data Studio. The embed register function receives two parameters: - The position to embed, either `head` or `body`. - The value to embed, either a string or a function that returns a string. Below is an example of registering embed hooks. ```js export default ({ embed }, { env }) => { // Google Tag Manager Example embed( 'head', () => ` ` ); // Sentry Example embed( 'head', '' ); embed( 'body', () => `` ); }; ``` ## Available Events ### Filter Events | Name | Payload | Meta | | ----------------------------- | ------------------------------- | ------------------------------------ | | `request.not_found` | `false` | `request`, `response` | | `request.error` | The request errors | -- | | `database.error` | The database error | `client` | | `auth.login` | The login payload | `status`, `user`, `provider` | | `auth.jwt` | The auth token | `status`, `user`, `provider`, `type` | | `authenticate` | The empty accountability object | `req` | | `(