# Domain registrant dossier

A paid `.vn` domain whose registrant details or dossier (ID card eKYC, an organisation's declaration) are not complete yet has an order but is **not registered** with VNNIC: status `Pending`. The four routes below let the customer's software see which domains are waiting, what is still missing, and update the registrant; once the dossier is complete Tino registers the domain automatically.

Updated: 2026-10-27.

A domain with an incomplete dossier is **not reserved**: someone else can still register it. Under Circular 48/2025/TT-BKHCN, "first come, first served" only applies to domains whose procedure is complete and paid. Remind customers to finish early.

## Routes and scopes

| Route | Purpose | Scope |
| --- | --- | --- |
| [`GET /v1/domains/pending`](/en/docs/api/get-domains-pending) | Domains not activated yet and what is left to do | `domains:registrant` |
| [`GET /v1/domains/{id}/registrant`](/en/docs/api/get-domains-id-registrant) | Registrant and dossier status of one waiting domain | `domains:registrant` |
| [`PUT /v1/domains/{id}/registrant`](/en/docs/api/put-domains-id-registrant) | Save the registrant (new details or another domain's registrant); Tino tries to register right away | `domains:registrant` |
| [`GET /v1/registrants`](/en/docs/api/get-registrants) | Registrants of the customer's running domains, to pick again | `domains:registrant` |

All four routes need `domains:registrant` (view and complete the registrant dossier of domains awaiting registration): this scope is only available to [personal API tokens](/en/docs/personal-tokens) with an IP restriction; OAuth apps and the MCP server are never granted it. The routes return the customer's own full registrant data (ID number, date of birth, phone, address): never write these fields to logs.

eKYC and declarations are done in Tino's Client Area (tino.vn), not through the API.

## Waiting domains

`GET /v1/domains/pending`, oldest first:

```json
{
  "domains": [
    {
      "id": 200001,
      "name": "example.vn",
      "status": "Pending",
      "subject_type": "ind",
      "ready": false,
      "actions": [{ "code": "ekyc", "message": "Chủ thể cần eKYC CCCD trong tài khoản này" }],
      "reason": "Chưa eKYC CCCD 001******001"
    }
  ]
}
```

| Field | Meaning |
| --- | --- |
| `subject_type` | `ind` individual · `org` organisation · `hkd` household business |
| `ready` | `true`: dossier complete, Tino is registering the domain (a few minutes) |
| `actions` | what the customer still has to do (table below); empty with `ready: false` means the declaration was submitted and awaits Tino's review |
| `reason` | why the latest registration attempt did not go through; may be `null`. ID numbers (runs of 9–13 digits) in the sentence are masked, keeping only the first 3 and last 3 digits |

No waiting domains: `{"domains": []}`. A registered domain leaves this list and becomes `Active` in `GET /v1/domain`.

`message` and `reason` are Vietnamese sentences meant for the customer.

## What is left to do

| `actions[].code` | Task |
| --- | --- |
| `fields` | Missing or invalid fields listed in `fields` (e.g. `["nationalid", "city"]`): fix them, then `PUT` |
| `owner_fields` | Same, for the owner of a household business |
| `ekyc`, `owner_ekyc` | The registrant (or owner) must complete eKYC with the declared ID card, in this same account |
| `ekyc_name`, `owner_ekyc_name` | The declared name differs from the eKYC name: correct it to match the ID card, then `PUT` |
| `ekyc_other_account`, `owner_ekyc_other_account` | The ID card was verified in another Tino account: use another registrant or contact Tino |
| `declaration` | Organisation: submit the signed declaration (or digitally sign the organisation dossier) in the Client Area |

## Reading the registrant

`GET /v1/domains/{id}/registrant`:

```json
{
  "domain": { "id": 200001, "name": "example.vn", "status": "Pending" },
  "subject_type": "ind",
  "registrant": {
    "firstname": "Van A", "lastname": "Nguyen", "companyname": "", "taxid": "", "householdsid": "",
    "nationalid": "001090000001", "birthday": "1990-01-01", "gender": "M", "email": "user@example.com",
    "phonenumber": "0900000001", "country": "VN", "state": "Thành phố Hồ Chí Minh", "city": "Phường Bến Thành", "ward": "",
    "address1": "123 Example Street", "address2": "", "postcode": "", "position": ""
  },
  "owner": null,
  "dossier": { "ekyc": "required", "declaration": "not_needed" },
  "actions": [{ "code": "ekyc", "message": "Chủ thể cần eKYC CCCD trong tài khoản này" }],
  "reason": "Chưa eKYC CCCD 001******001",
  "ready": false
}
```

- `state` and `city` are the **names** of the province / city and ward (post-merger list), not codes.
- `owner`: the household owner (name, ID number…) when `subject_type` is `hkd`; VNNIC checks the owner's eKYC. Other types: `null`.
- `dossier.ekyc`: `ok` · `required` · `name_mismatch` · `other_account` · `not_needed` (organisations, non-`.vn` extensions).
- `dossier.declaration` (organisations): `accepted` · `pending` (submitted, awaiting review) · `cancelled` (rejected) · `none` · `not_needed`. `dossier.signature`: `ok` (organisation dossier digitally signed for the tax code) · `none`.

## Reusing an earlier registrant

`GET /v1/registrants` returns the registrants of the customer's **running** domains, newest first, one row per person / organisation:

```json
{
  "registrants": [
    { "from_domain_id": 200002, "domain": "example.com.vn", "subject_type": "ind", "registrant": { "…": "as above" }, "owner": null, "ready": true, "actions": [] }
  ]
}
```

`ready: true`: the registrant completed eKYC (or digital signing) in this account, so a new domain can be registered right away. An organisation that only has a paper declaration on the old domain has `ready: false` and a `declaration` action: declarations belong to each domain and must be submitted again.

## Saving the registrant

`PUT /v1/domains/{id}/registrant`, JSON body, one of two forms:

```json
{ "from_domain_id": 200002 }
```

```json
{
  "registrant": {
    "firstname": "Van A", "lastname": "Nguyen", "nationalid": "001090000001", "phonenumber": "0900000001",
    "state": "Thành phố Hồ Chí Minh", "city": "Phường Bến Thành", "address1": "123 Example Street",
    "email": "user@example.com", "birthday": "1990-01-01", "gender": "M", "country": "VN"
  },
  "owner": null
}
```

- Send **every field** of the registrant: a field left out counts as empty; unknown fields are ignored.
- Required for `.vn`: `firstname`, `lastname`, `nationalid`, `phonenumber`, `state`, `city`, `address1`; organisations add `companyname`, `taxid`; household businesses add `householdsid` and `owner` (`firstname`, `lastname`, `nationalid`). Other extensions: `firstname`, `lastname`, `email`, `phonenumber`, `address1`, `city`, `country`.
- After saving, Tino tries to register right away and returns the new dossier (same shape as `GET`); read `actions` and `ready` again for the next step. Without another call, the system retries about every 5 minutes.
- Only for waiting domains. To change the registrant of an `Active` domain: [`PUT /v1/domain/{id}/contact`](/en/docs/api/put-domain-id-contact).

## Errors

Errors look like `{"error": ["<Vietnamese sentence>"]}` and can be shown to the customer as is.

| HTTP | Sentence | When |
| --- | --- | --- |
| 403 | `insufficient_scope` | the token lacks `domains:registrant` (an OAuth app's token, or a personal token without this scope) |
| 404 | Không tìm thấy tên miền chờ đăng ký | the domain is `Active`, cancelled, or not the customer's |
| 422 | Tên miền không tồn tại hoặc đã kích hoạt | `PUT` on a domain that is no longer waiting |
| 422 | Thiếu city (… fields) | a required field is missing |
| 422 | Trường state không hợp lệ | the value is not a string or is longer than 255 characters |
| 422 | Hộ kinh doanh cần thông tin chủ hộ (owner) | a household business without `owner` |
| 422 | Không dùng được chủ thể của tên miền #N | `from_domain_id` is not one of the customer's running domains |
