---
title: "Create a person by hand"
method: POST
path: "/api/v1/ackdb/persons"
tags: ["ackDB"]
---

# Create a person by hand

`POST /api/v1/ackdb/persons`

## Request

- Base URL: `http://localhost:3009`
- URL: `http://localhost:3009/api/v1/ackdb/persons`
- Auth: HTTP bearer

The split-runbook primitive: when two humans were fused onto one person (a shared inbox, a bad key), delete the offending key, create the second human here, then re-point their edge with `PATCH /contacts/{contactId} { personId }`.

Key types must be person-scope (`linkedin_url`, `email_address`, or a universal type registered with `scope: person`). Values are normalized (lowercased email / canonical LinkedIn) and validated: blank or null-sentinel values and role inboxes (`info@`, `sales@`, …) are **422** — a mailbox is not a human. A key already owned by another person is **409** naming the owner: keys are first-writer-wins and are never re-pointed.

**Email is a fallback anchor (#575).** If the submitted keys include BOTH a `linkedin_url` and an `email_address`, the email key is DROPPED at mint (the person is anchored by linkedin; the email would be a recyclable global pointer). The response then carries a `suppressed: { keyType, values, stored: false, reason }` block — this door has no contact edge, so a dropped email is not stored anywhere. An email-ONLY create still keeps the email as its sole anchor.

No creation event is emitted (a person mint is bookkeeping, like an ingest-auto-created company); an audit log is written instead.

## Request body

- AckdbPersonCreateRequest: Manual person create. All fields are optional — a person with no keys is a legal singleton.
  - `name` string, nullable
  - `avatarUrl` string, nullable: Photo URL (http(s) only). ackDB stores the link, never the bytes.
  - `keys` object[]: Durable keys to claim. Person-scope types only; values are normalized and validated.
    - `externalIdType` string, required
    - `externalIdValue` string, required

## Response `201`

`{ data: { person, keys } }` — the new person and its stored (normalized) keys.

- object
  - `data` unknown, required

## Other responses

- `400`: Malformed body (name not a string, keys not an array, …).
- `409`: A key already belongs to another person — the response names the owner.
- `422`: Not a person-scope key type, or a blank/garbage/role-inbox key value.

---

[API](https://skmtc.dev/floqer/apis/floqer-public-api.md) - [All operations](https://skmtc.dev/floqer/apis/floqer-public-api/llms.txt) - [OpenAPI document](https://skmtc.dev/floqer/apis/floqer-public-api/revisions/fce50dc07b20?raw)
