# 4.2.6.1 Working with events

{% hint style="success" %}
All technical concepts related to Events are collated in this [README](https://github.com/opencrvs/opencrvs-core/blob/develop/packages/commons/src/events/README.md)
{% endhint %}

Using concepts introduced in the README above, along with an understanding of the [metadata](https://github.com/opencrvs/opencrvs-core/blob/develop/packages/commons/src/events/EventMetadata.ts) properties associated with an event, you can configure any type of event you like in OpenCRVS.

## Serving events to OpenCRVS Core

Events that are configured in your countryconfig service are made available to core from [this](https://github.com/opencrvs/opencrvs-countryconfig/blob/0fc50a9d21d2c7525e5b8e3b8f1cd7c0ca7a7328/src/api/custom-event/handler.ts#L23) endpoint.

Examples for [birth](https://github.com/opencrvs/opencrvs-countryconfig/blob/develop/src/form/v2/birth/index.ts) and [death](https://github.com/opencrvs/opencrvs-countryconfig/blob/develop/src/form/v2/death/index.ts) are provided, along with an example [tennis club membership](https://github.com/opencrvs/opencrvs-countryconfig/blob/develop/src/form/tennis-club-membership.ts) event (just to demonstrate the flexibility of OpenCRVS as a general registry showing usage of more form components).

Your first configuration is probably going to be: to comment out the tennis club membership example event from this handler and any mention of the `tennis-club-membership` Event ID from associated user scopes in the [roles.ts](https://roles.tshttps/github.com/opencrvs/opencrvs-countryconfig/blob/0fc50a9d21d2c7525e5b8e3b8f1cd7c0ca7a7328/src/data-seeding/roles/roles.ts#L29) file.

## Configuring a new v2 event with `EventConfigInput`

In OpenCRVS ≥ 1.9, each event in your **country configuration** is defined in the `src/form/v2` directory.

The central building block is an **`EventConfigInput`** object – a Zod-validated input shape for the `EventConfig` type in `opencrvs-core` (`packages/commons/src/events`). This object captures, for a single event:

* the **event identifier** (critical)
* the **declaration form** (what users fill in to declare the event) with the associated **review** form used in *Declare* and *Validate* event.
* the **search form** (the fields available in *Search for a record*) and **deduplication** algorithm query
* the **summary configuration** (what you see in the record “card” when you click an item in a workqueue or search result)
* the **title, template**, **label**, and **dateOfEvent** field mapping
* the **print certificate form** (the fields available in *Print Certificate*)
* the **correction form** (the fields available in *Correct Record*)

Core reads an array of these configs from your countryconfig `/custom-event` endpoint and uses them to power the event flows described in the events README

### Where v2 event configs live

All v2 events are defined under:

```
src/form/v2/
```

> ✅ When adding a new v2 event, **only** work inside `src/form/v2`.\
> Ignore the legacy `src/form/<event>` directories used in v1.8 – the v2 engine is completely separate.

The **birth** event at `src/form/v2/birth/index.ts` is your reference implementation for how to construct an `EventConfigInput` for an event.

***

## Configure the declaration form

The **declaration form** configuration is a complex subject. Covered in the next section [4.2.6.2 Configure an event declaration form](/setup/3.-installation/3.2-set-up-your-own-country-configuration/3.2.7-configure-declaration-forms/4.2.6.2-configure-an-event-declaration-form.md)

***

### Configure the search form

Next, configure the **search form** portion of `EventConfigInput`, which controls the **“Search for a record”** UI for this event.

Conceptually, the search form is:

* A set of **search fields** (e.g. name, registration number, event date range, place).
* Grouped into **basic / advanced** panels if desired.
* Mapped to backend query parameters or index fields.

Typical design:

* **Quick search**
  * A small set of highly discriminative fields (e.g. registration number, national ID, or name + date of event).
* **Advanced search**
  * Additional filters (location, informant type, status, office, etc.).

**Process:**

1. Decide which fields users genuinely need to search on for this event.
   * Start from what is actually stored and indexed in Core.
2. Re-use existing field definitions where it makes sense (e.g. same labels and message IDs) but remember:
   * Search fields typically don’t need the heavy validation of the declaration form.
   * They do need to map reliably to backend query fields.
3. Define the search form structure for the event, using whichever v2 helpers `birth` uses for its search config.

In the `EventConfigInput`:

```ts
export const yourEventConfig: EventConfigInput = {
  // ...
  searchForm: buildSearchForm(),           // fields & groups used in “Search for a record”
  // ...
}
```

When **Core** loads this config, it uses it to render the search UI for that event and construct the query payload for the *Search for a record* flow.

***

### Configure the summary (workqueue / search result card)

Finally, configure the **summary** portion of `EventConfigInput` – the little “card” you see when you:

* click a record in a **workqueue**, or
* select a record from the **search results** and view its details. [documentation.opencrvs.org](https://documentation.opencrvs.org/product-specifications/core-functions?utm_source=chatgpt.com)

This summary usually shows:

* key identity info (names)
* event specifics (event date, place)
* registration details (registration number, office)
* current status (Registered, Requires updates, etc.)

**Process:**

1. Identify the *minimal* set of fields that allow a registrar to:
   * confirm they have the right record, and
   * quickly assess its status.
2. Map each summary item to an underlying field path or handlebar (often the same as used for certificates and FHIR mappings).
3. Arrange them in a sensible order and grouping (e.g. top line: name and registration number; second line: event date and place; third line: status and office).

In the `EventConfigInput`:

```ts
export const yourEventConfig: EventConfigInput = {
  // ...
  summary: buildSummaryConfig(),           // fields shown in record “card”
}
```

When Core renders a **workqueue** or **search results**, it uses this summary config to build the compact record view.

***

## Configuring **Actions** inside `EventConfigInput`

Every v2 event must define an **`actions`** array inside its `EventConfigInput`.\
These actions tell OpenCRVS Core **what workflows are available for this event**, and which **forms** are used during each workflow step.

The `actions` array has multiple responsibilities:

1. **Configure the “review” form used when reviewing a completed declaration**
2. **Configure the “print” form used when printing a certificate**
3. **Configure the “correction” form used when requesting a correction**
4. **Configure the deduplication query for detecting duplicate events via Elasticsearch**

This makes `actions` one of the most important parts of an event’s configuration.

### What each action represents

OpenCRVS Core defines a fixed set of **ActionTypes** (e.g. `READ`, `DECLARE`, `VALIDATE`, `REGISTER`, `PRINT_CERTIFICATE`, `REQUEST_CORRECTION`, etc.).\
Each event chooses which of those actions it supports, and optionally:

* the **form** used for that action
* the **deduplication query**
* the **label** for buttons, menus and logs

The action objects in the `actions` array look like this:

```ts
actions: [
  {
    type: ActionType.READ,
    label: { ... },
    review: REVIEW_FORM
  },
  {
    type: ActionType.PRINT_CERTIFICATE,
    label: { ... },
    printForm: CERTIFICATE_COLLECTOR_FORM
  },
  {
    type: ActionType.REQUEST_CORRECTION,
    label: { ... },
    correctionForm: CORRECTION_FORM
  },
  {
    type: ActionType.DECLARE,
    label: { ... },
    review: REVIEW_FORM,
    deduplication: {
      id: '...',
      label: { ... },
      query: dedupConfig
    }
  }
]
```

Let’s break down what each kind of action is for.

***

## **Action Type 1: Review Form**

#### “Used when reviewing a completed declaration”

Actions such as:

* `READ`
* `DECLARE`
* `VALIDATE`
* `REGISTER`

…include a:

```ts
review: <FORM>
```

This **review form** is displayed when:

* a registrar opens a declaration to check data before submitting it
* a validator reviews the record
* a registration officer is confirming the final registration

This form typically shows all collected data in a read-only or semi-editable manner with consistent grouping.

For example:

```ts
{
  type: ActionType.READ,
  label: { ... },
  review: BIRTH_DECLARATION_REVIEW
}
```

***

## **Action Type 2: Print Certificate Form**

#### “Used when printing (collecting) a certificate”

When a registration is complete, registrars may issue a certificate.

Actions of type:

* `PRINT_CERTIFICATE`

…must define a:

```ts
printForm: <FORM>
```

This **print form** captures any additional fields required *only at the time of certificate issuance*, such as:

* identity of the person collecting the certificate
* proof of identity
* certificate serial number (if applicable to the country)
* certificate fees associated

Example:

```ts
{
  type: ActionType.PRINT_CERTIFICATE,
  label: { ... },
  printForm: BIRTH_CERTIFICATE_COLLECTOR_FORM
}
```

***

## **Action Type 3: Correction Form**

#### “Used when performing corrections after registration”

Corrections require a separate workflow from declaration.

Actions of type:

* `REQUEST_CORRECTION`

…must define a:

```ts
correctionForm: <FORM>
```

This form captures **all required fields** when someone requests modifications *after* the event is registered, e.g.:

* reason for correction
* supporting documentation
* identity of the requester
* corrected fields

Example:

```ts
{
  type: ActionType.REQUEST_CORRECTION,
  label: { ... },
  correctionForm: CORRECTION_FORM
}
```

This ensures all countries can enforce their specific legal requirements for post-registration changes.

***

## **Deduplication configuration**

#### “Defines the Elasticsearch query used to detect duplicates”

Some actions (e.g. `DECLARE`, `VALIDATE`, `REGISTER`) may include a **deduplication** section:

```ts
deduplication: {
  id: 'birth-deduplication',
  label: { ... },
  query: dedupConfig
}
```

This has three parts:

| Property    | Purpose                                                                                                                                                                                                                                                |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **`id`**    | A unique identifier for this deduplication configuration                                                                                                                                                                                               |
| **`label`** | User-facing label (e.g. “Detect duplicate”)                                                                                                                                                                                                            |
| **`query`** | The actual Elasticsearch query used to find potential duplicate registrations, configured using these [helpers](https://github.com/opencrvs/opencrvs-core/blob/625cd2662a5101caac5a1f7b26a6c8ed77c27246/packages/commons/src/events/deduplication.ts). |

#### How it works

When a user triggers an action that includes a dedupe config:

1. Core takes the event data from the form
2. Runs the `dedupConfig` Elasticsearch query
3. Displays a list of possible duplicates before continuing

Typical dedupe fields include:

* person’s name
* date of event
* place of event

This prevents:

* double registration
* clerical duplication
* fraud

You may define **multiple** dedupe-enabled actions if your workflow requires checking duplicates at different stages.

***

### Testing your new event end-to-end

After wiring everything up:

1. **Run OpenCRVS Core + your countryconfig** (as per usual dev setup).
2. Hit the `/custom-event` endpoint and confirm:
   * Your new event appears with the correct `eventType` / key / version.
   * `declarationForm`, `searchForm` and `summary` sections are present in the payload.
3. In the UI:
   * **Declare** the new event and walk through all sections/groups:
     * required/optional fields behave as expected
     * conditionals and validation work
   * **Register** the event, **reviewing, printing** and **correcting** it. Verify forms / views / certificates behave as expected.
   * Use **Search for a record**:
     * confirm your new search form appears,
     * filters apply correctly and return the expected records.
   * Click a result / workqueue item:
     * confirm the **summary card** matches your configuration.

***

#### Further reading:

An explanation regarding how events are stored in the [database](https://github.com/opencrvs/opencrvs-core/blob/develop/packages/events/DATABASE.md).

#### OpenCRVS API Documentation

<https://api.opencrvs.org/develop/events/index.html>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://documentation.opencrvs.org/setup/3.-installation/3.2-set-up-your-own-country-configuration/3.2.7-configure-declaration-forms/4.2.7.1-configuring-an-event-form.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
