---
title: "Contacts"
description: "The address book agents build as they correspond, plus allow and block rules."
canonical_url: "https://www.agent-identity.dev/docs/mail/contacts"
markdown_url: "https://www.agent-identity.dev/docs/mail/contacts.md"
last_updated: "2018-10-20"
x_farming_labs_generated_preamble: true
agent:
  tokenBudget: 700
  task: "Control who an agent will correspond with, and keep the addresses it has met."
  outcome: "Contacts accumulate as suggestions from real correspondence, and a rule decides whether a given address is allowed or blocked."
  appliesTo:
    package:
      - "@aid/api"
  prerequisites:
    - "An agent that is sending or receiving mail."
  files:
    - "apps/api/src/services/contacts.ts"
  sideEffects:
    - "A block rule takes effect immediately and applies to sends as well as inbound mail."
  verification:
    - description: "Confirm a rule is active."
      expect: "The rule appears in the contact-rules list, and a send to a blocked address is rejected rather than queued."
  rollback:
    - "Delete the rule to restore correspondence. Contacts already recorded are unaffected."
  failureModes:
    - symptom: "A send is rejected for a recipient that looks fine."
      resolution: "A block rule matches it. List the rules and remove the matching one, or send to a different address."
---

# Contacts
URL: /docs/mail/contacts
LLM index: /llms.txt
Description: The address book agents build as they correspond, plus allow and block rules.
Related: /docs/mail/receiving, /docs/mail/sending

<!-- farming-labs:agent-contract:start -->
## Agent Contract

Task: Control who an agent will correspond with, and keep the addresses it has met.
Outcome: Contacts accumulate as suggestions from real correspondence, and a rule decides whether a given address is allowed or blocked.

### Applies To

- Package: `@aid/api`

### Prerequisites

- An agent that is sending or receiving mail.

### Files

- `apps/api/src/services/contacts.ts`

### Side Effects

- A block rule takes effect immediately and applies to sends as well as inbound mail.

### Verification

- Confirm a rule is active.
  - Expected: The rule appears in the contact-rules list, and a send to a blocked address is rejected rather than queued.

### Rollback

- Delete the rule to restore correspondence. Contacts already recorded are unaffected.

### Failure Modes

- A send is rejected for a recipient that looks fine. — Recovery: A block rule matches it. List the rules and remove the matching one, or send to a different address.
<!-- farming-labs:agent-contract:end -->

# Contacts

Two related things live here: a contact record, which is an address book entry, and a
access rule, which decides whether mail to or from an address is allowed at all.

## Contacts

Contacts hold the full set of fields you would expect — names with prefix and suffix,
company and job title, multiple emails, phones, websites, addresses, dates, arbitrary
custom fields, and notes.

They arrive two ways. You create one explicitly:

```bash title="terminal"
curl -sS -X POST https://api.agent-identity.dev/v1/contacts \
  -H "authorization: Bearer $AID_KEY" \
  -H 'content-type: application/json' \
  -d '{
    "display_name": "Dana Reed",
    "company": "Example Co",
    "emails": [{"value":"dana@example.com","label":"work"}]
  }'
```

Or one appears on its own: when an agent receives mail from an address that is not
already on file, a contact is created with `status: "suggested"` and
`source_identity_id` set to the agent that saw it. Nothing is silently promoted — a
suggestion sits there until someone acts on it.

```bash title="terminal"
curl -sS "https://api.agent-identity.dev/v1/contacts?status=suggested" \
  -H "authorization: Bearer $AID_KEY"

curl -sS -X POST "https://api.agent-identity.dev/v1/contacts/$CONTACT_ID/approve" \
  -H "authorization: Bearer $AID_KEY"
```

Approve moves it to `saved`. Reject removes it. `PATCH /v1/contacts/:id` updates fields —
a `null` clears one, omitting it leaves it alone — and `DELETE /v1/contacts/:id` removes
the record.

Contact management requires an org key. An agent can cause a suggestion by receiving mail,
but cannot approve its own suggestions.

## Rules

Rules are the enforcement layer, and they are checked on send and on ingest rather than
being advisory.

```bash title="terminal"
curl -sS -X POST https://api.agent-identity.dev/v1/contact-rules \
  -H "authorization: Bearer $AID_KEY" \
  -H 'content-type: application/json' \
  -d '{"match_address":"spammer@example.com","action":"block"}'
```

`action` is `allow` or `block`. Omit `identity_id` for an organization-wide rule, or set
it to scope the rule to one agent.

A blocked recipient stops an outbound send before it is queued. A blocked sender means an
inbound message is stored but no `mail.received` event is appended — so an agent waiting
on that thread simply never wakes, which is the intended behaviour, but worth knowing
when you are debugging a wait that never fires.

`GET /v1/contact-rules` lists them; `DELETE /v1/contact-rules/:id` removes one.

- Contact writes (`create`, `update`, `delete`, `approve`, `reject`) require
  `actor.type === "user"`, i.e. an org key. An agent key gets `403` even for a contact its
  own traffic created.
- `PATCH /v1/contacts/:id` distinguishes absent from null: an omitted key leaves the field
  unchanged, an explicit `null` clears it. Do not send a full object with nulls unless you
  intend to clear those fields.
- `GET /v1/contacts?status=` accepts only `suggested` or `saved`; any other value is a
  `400`.
- Suggestion is idempotent by address — `suggestFromTraffic` first checks whether any
  contact in the org already holds that email and returns early if so. Repeated mail from
  a known sender does not create duplicates.
- A blocked *sender* still results in a stored message row; only the event is suppressed.
  Do not use "no event" as proof that nothing was received — check the inbound webhook's
  `blocked` counter.

## Sitemap

See the full [sitemap](/sitemap.md) for all pages.
Docs-scoped sitemap: [/docs/sitemap.md](/docs/sitemap.md).
Well-known sitemap: [/.well-known/sitemap.md](/.well-known/sitemap.md).
