Addresses
The identifier as a first-class resource — created before any message arrives, and the one place a customer's own admission decision lives.
Overview
An address is what an identifier names: a place a conversation can
happen — sometimes a person's DM, sometimes a room a Discord
server shares. It is project-scoped, keyed by the prefixed, self-describing
identifier a channel adapter produces (whatsapp:dm:<phone>,
discord:dm:<user_id>, discord:thread:<guild_id>:<channel_id>).
PUT /v1/projects/{project_id}/addresses/{identifier}
is the write a customer's own application makes when it learns something
about an identifier — a payment cleared, a plan lapsed, an abuse report. It is
a one-call upsert keyed by the identifier: no read first, and no 404 for one
that has never written, because at the moment a payment clears the customer's
backend knows the identifier and does not know whether naturali has ever seen
it.
See the OpenAPI spec for the full endpoint and schema reference, or browse it rendered under API Reference → Addresses.
Data Model
Address
| Field | Type | Description |
|---|---|---|
id | string | Public address ID. |
project_id | string | The owning project. |
identifier | string | The prefixed, self-describing channel identifier. |
display_name | string, nullable | A human-friendly name, as the channel reported it. |
actor_id | string, nullable | The runtime actor this address speaks as; null until it has needed one. |
action | string, nullable | This address's own decision — agent, message, silence, or null. Beats every route. |
agent_id | string, nullable | The agent that answers, when action is agent. |
text | string, nullable | The fixed text delivered, when action is message. |
repeat | string or object, nullable | every (default), once, or { after_seconds }. |
language | string, nullable | Preferred reply language. |
config | object, nullable | Conversation config. |
created_at | string (date-time) | |
updated_at | string (date-time) |
Key Concepts
The address's action beats everything
Resolution checks the address first: if it has an action, that wins
outright, ahead of every route and the channel
default. action: silence is how you
block someone — abuse, an erasure in flight. action: null forgets the
exception, so the route table decides again.
repeat, for a message action
Left alone, ten inbound messages produce ten identical refusals. every (the
default) delivers on every inbound and writes no state; once delivers once
then stays silent; { "after_seconds": N } delivers at most once per window.
Editing the text, or resolving to a different action, resets the clock
immediately.
Erasure is narrower than "erase this human"
DELETE /v1/projects/{project_id}/addresses/{identifier}
removes the address, its conversations, and its runtime actor and sessions.
Without a merge graph, naturali does not know that two identifiers are the
same person, so this is a promise about this address, not about a human
across every channel they have ever used.
Examples
Admit an identifier the moment a payment clears — one call, no prior read:
- CLI
- SDK
- curl
naturali set-address-action \
--project-id proj_V1StGXR8Z5jdHi6B \
--identifier instagram:dm:17841400000000000 \
--action agent \
--agent-id agent_V1StGXR8Z5jdHi6B
const { data: address } = await naturali.channels.setAddressAction({
path: {
project_id: 'proj_V1StGXR8Z5jdHi6B',
identifier: 'instagram:dm:17841400000000000',
},
body: { action: 'agent', agent_id: 'agent_V1StGXR8Z5jdHi6B' },
});
curl -X PUT https://api.naturali.ai/v1/projects/proj_V1StGXR8Z5jdHi6B/addresses/instagram%3Adm%3A17841400000000000 \
-H "Authorization: Bearer $NATURALI_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "action": "agent", "agent_id": "agent_V1StGXR8Z5jdHi6B" }'
Hold a non-subscriber with a paywall message instead of an agent, once:
- CLI
- SDK
- curl
naturali set-address-action \
--project-id proj_V1StGXR8Z5jdHi6B \
--identifier instagram:dm:17841400000000000 \
--action message \
--text 'Subscribe at https://example.com/pricing' \
--repeat once
await naturali.channels.setAddressAction({
path: {
project_id: 'proj_V1StGXR8Z5jdHi6B',
identifier: 'instagram:dm:17841400000000000',
},
body: {
action: 'message',
text: 'Subscribe at https://example.com/pricing',
repeat: 'once',
},
});
curl -X PUT https://api.naturali.ai/v1/projects/proj_V1StGXR8Z5jdHi6B/addresses/instagram%3Adm%3A17841400000000000 \
-H "Authorization: Bearer $NATURALI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"action": "message",
"text": "Subscribe at https://example.com/pricing",
"repeat": "once"
}'
Erase an address — its conversations, actor and sessions with it:
- CLI
- SDK
- curl
naturali delete-address \
--project-id proj_V1StGXR8Z5jdHi6B \
--identifier instagram:dm:17841400000000000
await naturali.channels.deleteAddress({
path: {
project_id: 'proj_V1StGXR8Z5jdHi6B',
identifier: 'instagram:dm:17841400000000000',
},
});
curl -X DELETE https://api.naturali.ai/v1/projects/proj_V1StGXR8Z5jdHi6B/addresses/instagram%3Adm%3A17841400000000000 \
-H "Authorization: Bearer $NATURALI_API_KEY"