> For the complete documentation index, see [llms.txt](https://documentation.opencrvs.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://documentation.opencrvs.org/v2.1/technical/guides/configuration/action-triggers/action-confirmation.md).

# Action confirmation

Accepting or rejecting an action from the country configuration

When a user performs an action on a record, OpenCRVS Core first records it as **requested** and calls the event action trigger `POST /trigger/events/{eventType}/actions/{actionType}` on your country configuration server. The country configuration decides whether the action goes ahead. This is known as **action confirmation**.

The following actions support action confirmation:

* `NOTIFY`, `DECLARE`, `EDIT`, `REGISTER`, `REJECT`, `ARCHIVE`, `UNARCHIVE`
* `PRINT_CERTIFICATE`, `CUSTOM`
* `REQUEST_CORRECTION`, `APPROVE_CORRECTION`, `REJECT_CORRECTION`

The reference country configuration registers a catch-all route that answers `200` for every event action. Add a more specific route to intercept one:

```typescript
server.route({
  method: 'POST',
  path: `/trigger/events/birth/actions/${ActionType.REGISTER}`,
  handler: onBirthRegisterHandler,
  options: {
    tags: ['api', 'events'],
    description: 'Confirms birth registrations'
  }
})
```

***

#### 1. Synchronous confirmation

Answer the trigger request directly:

| Response   | Result                                |
| ---------- | ------------------------------------- |
| `HTTP 200` | The action is accepted immediately.   |
| `HTTP 400` | The action is rejected immediately.   |
| `HTTP 202` | The action stays pending (see below). |

A registration must return the registration number when it is accepted:

```typescript
return h.response({ registrationNumber: generateRegistrationNumber() }).code(200)
```

When several actions are submitted together — for example declare and register in one go — the intermediate actions must be answered synchronously.

***

#### 2. Asynchronous confirmation

Return `HTTP 202` when the decision is not available yet, for example while waiting for a national ID system. The action stays in the **Requested** state, and the user who started it is unassigned from the record. Accept or reject it later by calling Core's `accept` or `reject` endpoint for that action type.

**Credentials**

{% hint style="danger" %}
Do not call `accept` or `reject` with the token Core sent to your trigger. That token only proves the request came from Core — it carries no scopes.
{% endhint %}

Call Core with **your country configuration's own system client**. The client needs:

| Scope                  | Needed to               |
| ---------------------- | ----------------------- |
| `record.action.accept` | Accept a pending action |
| `record.action.reject` | Reject a pending action |

For example, `{ type: 'record.action.accept', options: { event: ['birth', 'death'] } }`, encoded as `type=record.action.accept&event=birth,death`.

The scope of the action itself (for example `record.register`) does not allow anyone to confirm it, and a user's token is refused whatever scopes it carries. A client with these scopes cannot be created from the Integrations page — register it from your country configuration. See [Create a client](/v2.1/technical/guides/configuration/integrations/create-a-client.md#process-of-creation-via-the-country-configuration).

{% hint style="danger" %}
Never grant `record.action.accept` or `record.action.reject` to a user role. Anyone who can both request an action and confirm it can, for example, register a record without your country configuration being involved. Core does not stop you from doing this — grant these scopes only to integrations.
{% endhint %}

**Rules Core applies**

* A confirmation is refused with `CONFLICT: User is assigned to this event` while any user is assigned to the record. The requesting user is unassigned as soon as you return `202`, so this only happens if someone assigns themselves while your confirmation is pending. Wait until nobody is assigned, then retry.
* The `actionId` must be a pending action of the matching type. Any other action id is refused.

**Accepting**

```typescript
import { createClient } from '@opencrvs/toolkit/api'

// systemToken: obtained with your own client_id and client_secret,
// see Authenticate a client
const client = createClient(`${GATEWAY_URL}/events`, `Bearer ${systemToken}`)

await client.event.actions.register.accept.mutate({
  ...action, // action input
  transactionId: uuidv4(),
  eventId,
  actionId,
  registrationNumber: generateRegistrationNumber() // REGISTER only
})
```

**Rejecting**

```typescript
await client.event.actions.register.reject.mutate({
  transactionId: uuidv4(),
  eventId,
  actionId
})
```

Replace `register` with the action type you are confirming, for example `archive` or `printCertificate`. To obtain `systemToken`, see [Authenticate a client](/v2.1/technical/guides/configuration/integrations/authenticate-a-client.md).

{% hint style="info" %}
Before OpenCRVS 2.1, a country configuration could confirm an action with the requesting user's token, or with a token obtained through the OAuth token-exchange grant. Both have been removed, together with the `record.confirm-registration` and `record.reject-registration` scopes and the `CONFIG_ACTION_CONFIRMATION_TOKEN_EXPIRY_SECONDS` auth environment variable.
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://documentation.opencrvs.org/v2.1/technical/guides/configuration/action-triggers/action-confirmation.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
