Create persona
Creates a persona and grants the caller create/read/update on it in the same transaction. THE ADDRESS FIELDS ARE ACCEPTED AND SILENTLY DROPPED. CreatePersonaInput embeds ActualAddress and RegAddress, but the record it is copied into, models.Persona, is PersonaData + BaseModel and has no address fields at all — so actual_street, reg_city and the rest are decoded, ignored by commonutil.Populate, and never stored. The 201 body will not contain them either. Store an address through the record type that owns one. invite is decoded — the Invite member has no json tag, but encoding/json matches an object key to a field name case-insensitively — and then nothing reads it. This is the ONLY route that validates a persona. The two PUT routes run no validator at all, so a name or date of birth the create refuses can still be written by an update.
Authorization
bearerAuth In: header
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Body of POST /v1/personas. NOTE the address members: CreatePersonaInput embeds ActualAddress and RegAddress, but they are copied into models.Persona, which has no address fields — so every actual_* and reg_* key is accepted, ignored and never stored, and never appears in the response. The house-number keys are actual_house and reg_house; actual_house_number and reg_house_number, which earlier revisions of this spec declared, are the Go field names and match nothing on the wire. invite is decoded — Invite has no json tag, but encoding/json matches object keys to field names case-insensitively — and nothing reads the value.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/v1/personas" \ -H "Content-Type: application/json" \ -d '{ "first_name": "string", "last_name": "string", "date_of_birth": "2019-08-24" }'{
"first_name": "string",
"last_name": "string",
"date_of_birth": "2019-08-24",
"date_of_death": "2019-08-24",
"nationality": "string",
"hash_id": "string",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"active": true,
"metadata": {},
"created_at": "2019-08-24T14:15:22Z",
"created_by": "ee824cad-d7a6-4f48-87dc-e8461a9201c4",
"modified_at": "2019-08-24T14:15:22Z",
"modified_by": "e8d4374d-93a1-4e98-a6c6-fdcf00c5059f"
}{
"status": 400,
"message": "First name is required",
"code": "personas_m.first_name_required",
"class": "validation"
}{
"status": 401,
"message": "Unauthorized",
"code": "common.unauthorized",
"class": "business"
}{
"status": 403,
"message": "No access to the record",
"code": "common.rbac_no_rec_access",
"class": "business"
}{
"status": 429,
"message": "Rate limit exceeded",
"code": "rate_limits_m.exceeded",
"class": "temporary",
"retryable": true
}{
"status": 500,
"message": "Internal server error",
"code": "common.server_error",
"class": "business"
}{
"overall_status": "unhealthy",
"message": "Service is shutting down",
"timestamp": "2026-08-27T15:04:05Z"
}Links with the persona record type ON EITHER SIDE, as a BARE ARRAY — no envelope and no pagination. No query parameter is read. THE RESULT IS RBAC-SCOPED, not the complete set. A caller holding read_all on the link record type gets every link whose rec_type_x or rec_type_y is the persona type. Any other caller gets only links touching a persona the caller or one of their roles holds a grant on in rbac.record_permissions — so two callers legitimately see different arrays, and a client must not cache this as the full list. The empty responses differ in shape: a caller with grants but no matching links gets [], while a caller with no persona grants at all short-circuits before the query and gets null.
Next Page