Skip to content

Contacts

Contacts manage your agent's address book with multi-channel identity support.

Overview

Features:

  • Multi-channel identity (email, phone, social)
  • Cross-gateway memory - Same contact shares memories across all channels
  • Cross-gateway history - Search conversations across all platforms
  • Tags and metadata
  • Identity resolution
  • Contact grouping
  • History tracking

Contact Fields

FieldDescription
nameContact name
emailEmail address
phonePhone number
telegramTelegram username
whatsappWhatsApp number
twitterTwitter/X handle
external_idExternal system ID
notesFree-form notes
tagsJSON array of tags
metadataJSON metadata

Creating Contacts

Via Dashboard

  1. Navigate to Contacts
  2. Click Add Contact
  3. Fill in details
  4. Save

Via API

bash
curl -X POST https://your-domain.com/api/agents/{id}/contacts \
  -H "Content-Type: application/json" \
  -d '{
    "name": "John Doe",
    "email": "[email protected]",
    "phone": "+1234567890",
    "telegram": "@johndoe",
    "tags": ["customer", "vip"],
    "metadata": {
      "company": "Acme Corp",
      "plan": "enterprise"
    }
  }'

Managing Contacts

List Contacts

bash
curl "https://your-domain.com/api/agents/{id}/contacts?limit=50"

Search Contacts

bash
curl "https://your-domain.com/api/agents/{id}/contacts?search=john"

Get Contact

bash
curl https://your-domain.com/api/agents/{id}/contacts/{contactId}

Update Contact

bash
curl -X PUT https://your-domain.com/api/agents/{id}/contacts/{contactId} \
  -d '{
    "name": "John D. Doe",
    "tags": ["customer", "vip", "enterprise"]
  }'

Delete Contact

bash
curl -X DELETE https://your-domain.com/api/agents/{id}/contacts/{contactId}

Identity Resolution

Uranus automatically resolves identities across channels:

┌─────────────────────────────────────────────────────────┐
│                  Incoming Message                        │
│                                                          │
│   Email: [email protected]
│   or                                                     │
│   Phone: +1234567890                                    │
│   or                                                     │
│   Telegram: @johndoe                                    │
└────────────────────────┬────────────────────────────────┘


┌─────────────────────────────────────────────────────────┐
│               Identity Resolution                        │
│                                                          │
│   1. Search by email                                    │
│   2. Search by phone                                    │
│   3. Search by telegram                                 │
│   4. Search by whatsapp                                 │
│   5. Search by twitter                                  │
│   6. Search by external_id                              │
└────────────────────────┬────────────────────────────────┘


┌─────────────────────────────────────────────────────────┐
│                 Resolved Contact                         │
│                                                          │
│   ID: contact-123                                       │
│   Name: John Doe                                        │
│   Email: [email protected]
│   Phone: +1234567890                                    │
│   Telegram: @johndoe                                    │
└─────────────────────────────────────────────────────────┘

Tags

Organize contacts with tags:

json
{
  "tags": ["customer", "vip", "west-coast"]
}

Filter by Tag

bash
curl "https://your-domain.com/api/agents/{id}/contacts?tag=vip"

Common Tags

  • customer - Paying customers
  • prospect - Potential customers
  • vip - High-value contacts
  • support - Support contacts
  • partner - Business partners

Metadata

Store custom data:

json
{
  "metadata": {
    "company": "Acme Corp",
    "industry": "Technology",
    "plan": "enterprise",
    "mrr": 5000,
    "contract_end": "2025-12-31"
  }
}

Cross-Gateway Memory

When the same contact messages your agent through different channels (Telegram, WhatsApp, Email, etc.), their memories and preferences are shared automatically.

How It Works

Contact: John Doe
├── Telegram: @johndoe
├── WhatsApp: +1234567890
└── Email: [email protected]

Memory stored: "John prefers dark mode"

Available across ALL channels

Memory Scoping

The agent stores two types of memories:

ScopeKey PatternExample
Contact-specificmemory:contact:{contactId}:{key}User preferences, facts about them
Agent-widememory:{key}General knowledge, settings

When recalling memories, contact-specific memories take priority.

Using Memory Tools

javascript
// Remember something about the current contact
await tools.remember({
  key: "coffee_preference",
  value: "oat milk latte",
  category: "preference"
});

// Recall across any channel
const pref = await tools.recall({ key: "coffee_preference" });
// Returns: "oat milk latte" regardless of which gateway they're using

Cross-Gateway Conversation History

Search conversation history across all channels for a contact:

javascript
// Search across all gateways (default)
await tools.recallConversation({
  query: "discussed pricing",
  scope: "contact",  // Searches across Telegram, WhatsApp, etc.
  limit: 10
});

// Search only current conversation
await tools.recallConversation({
  query: "discussed pricing",
  scope: "conversation",  // Only current channel
  limit: 10
});

System Prompt Integration

The agent automatically receives contact memories in its system prompt:

## What You Remember

**About this person (across all channels):**
- coffee_preference: oat milk latte
- timezone: PST
- communication_style: prefers brief responses

**General context:**
- company_hours: 9am-5pm EST

Conversations

Link contacts to conversations:

Contact
  └── Conversation 1 (Email)
  └── Conversation 2 (Telegram)
  └── Conversation 3 (WhatsApp)

Get Contact Conversations

bash
curl "https://your-domain.com/api/agents/{id}/conversations?contact_id={contactId}"

Integration

With Workflows

json
{
  "type": "lookup-contact",
  "data": {
    "email": "{{message.from}}"
  },
  "output": "contact"
}

With Chat

Contact context is available in conversations:

System: Current contact: John Doe ([email protected])
        Tags: customer, vip
        Company: Acme Corp

With Gateways

Route messages based on contact:

json
{
  "type": "send-message",
  "data": {
    "contact_id": "{{contact.id}}",
    "message": "Hello {{contact.name}}!",
    "channel": "{{contact.preferred_channel}}"
  }
}

Import/Export

Import Contacts

bash
curl -X POST https://your-domain.com/api/agents/{id}/contacts/import \
  -F "[email protected]"

CSV format:

csv
name,email,phone,telegram,tags
John Doe,[email protected],+1234567890,@johndoe,"customer,vip"
Jane Smith,[email protected],+0987654321,@janesmith,prospect

Export Contacts

bash
curl "https://your-domain.com/api/agents/{id}/contacts/export?format=csv" > contacts.csv

Access Control

Uranus supports tag-based access control that lets you define what each contact can and cannot do when interacting with your agent. Access profiles are linked to contacts through tags, allowing fine-grained control over tool access, data visibility, and conversation scope.

Access Profiles

An access profile defines a set of permissions. Each profile has:

FieldDescription
tagThe contact tag this profile applies to (e.g., vip, support, restricted)
priorityNumeric priority for conflict resolution (higher wins)
descriptionHuman-readable description of the profile's purpose
allowedToolCategoriesTool categories the contact can use (e.g., ["browser", "memory"])
deniedToolCategoriesTool categories explicitly blocked
allowedToolClustersSpecific tool clusters permitted
deniedToolClustersSpecific tool clusters blocked
canAccessConversationHistoryWhether the contact's conversations can reference past history
canAccessContactsWhether the agent can use contact-related tools during this contact's session
canAccessMemoriesWhether the agent can read/write memories for this contact

Default Profile

The special * profile acts as a fallback for any contact that does not have an explicit profile tag. This ensures every contact has a baseline set of permissions, even if no specific profile has been assigned.

json
{
  "tag": "*",
  "priority": 0,
  "description": "Default permissions for all contacts",
  "allowedToolCategories": ["memory", "calendar"],
  "deniedToolCategories": ["browser", "payments"],
  "canAccessConversationHistory": true,
  "canAccessContacts": false,
  "canAccessMemories": true
}

Profile Merging

When a contact has multiple tags that each match a profile, the profiles are merged together using the following rules:

  • Boolean flags (canAccessConversationHistory, canAccessContacts, canAccessMemories): merged with OR logic. If any matching profile grants access, the contact gets access.
  • List fields (allowedToolCategories, allowedToolClusters): merged as a union. The contact gets access to all categories/clusters allowed by any of their profiles.
  • Denied lists (deniedToolCategories, deniedToolClusters): also merged as a union. Denied entries take precedence over allowed entries.
  • Conflicts: when two profiles disagree, the profile with the highest priority value wins.

For example, a contact tagged ["vip", "support"] would receive the combined permissions of both the vip and support profiles.

Managing Profiles in the UI

  1. Navigate to Contacts
  2. Open the Access tab
  3. Click Add Profile to create a new access profile
  4. Set the tag, priority, description, and permission flags
  5. Save the profile

Profiles appear as a list sorted by priority, with the * default profile shown at the bottom.

Assigning Profiles to Contacts

Profiles are assigned to contacts through tags. There are two ways to link a profile to a contact:

  • Tag input: In the contact edit dialog, add a tag that matches an existing access profile's tag field. The profile is applied automatically.
  • Profile picker dropdown: When editing a contact, use the profile picker dropdown to browse available profiles and assign them. This adds the corresponding tag to the contact.

A contact can have multiple profile tags, and all matching profiles are merged (see Profile Merging above).

API Endpoints

Manage access profiles programmatically:

List Profiles

bash
curl https://your-domain.com/api/agents/{id}/access-profiles

Create Profile

bash
curl -X POST https://your-domain.com/api/agents/{id}/access-profiles \
  -H "Content-Type: application/json" \
  -d '{
    "tag": "restricted",
    "priority": 10,
    "description": "Limited access for new contacts",
    "allowedToolCategories": ["memory"],
    "deniedToolCategories": ["browser", "payments", "code"],
    "canAccessConversationHistory": false,
    "canAccessContacts": false,
    "canAccessMemories": true
  }'

Update Profile

bash
curl -X PUT https://your-domain.com/api/agents/{id}/access-profiles/{profileId} \
  -H "Content-Type: application/json" \
  -d '{
    "allowedToolCategories": ["memory", "calendar"],
    "canAccessConversationHistory": true
  }'

Delete Profile

bash
curl -X DELETE https://your-domain.com/api/agents/{id}/access-profiles/{profileId}

Get Effective Access for a Contact

Returns the merged access profile computed from all of a contact's tags:

bash
curl https://your-domain.com/api/agents/{id}/contacts/{contactId}/access

Response:

json
{
  "allowedToolCategories": ["memory", "calendar", "browser"],
  "deniedToolCategories": ["payments"],
  "canAccessConversationHistory": true,
  "canAccessContacts": false,
  "canAccessMemories": true,
  "appliedProfiles": ["vip", "support", "*"]
}

How Access Control Integrates with the Agent

Access control is enforced at three levels during agent execution:

  1. Tool filtering: Before the agent sees its available tools, tools are filtered based on the contact's effective access profile. Denied tool categories and clusters are removed entirely, so the agent cannot call them.

  2. System prompt injection: Restriction instructions are injected into the agent's system prompt, informing it of the current contact's access level. This ensures the agent understands boundaries even for conversational responses (e.g., "I'm not able to help with payment-related requests for your account").

  3. Conversation recall scope: When canAccessConversationHistory is false, the agent cannot search or reference past conversations for that contact. When canAccessMemories is false, memory recall and storage tools are disabled. When canAccessContacts is false, contact lookup and listing tools are hidden.

Best Practices

1. Consistent Formatting

Normalize data:

  • Phone: E.164 format (+1234567890)
  • Email: lowercase
  • Social: without @ prefix

2. Use Tags Wisely

Create a tagging strategy:

  • Keep tags simple
  • Use consistent naming
  • Document tag meanings

3. Regular Cleanup

Maintain data quality:

  • Merge duplicates
  • Remove stale contacts
  • Update outdated info

4. Privacy Compliance

Respect privacy:

  • Track consent
  • Honor opt-outs
  • Secure data access

5. Enrich Data

Add context over time:

  • Interaction history
  • Preferences
  • Purchase history

API Reference

See Contacts API for complete endpoint documentation.