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": "john@example.com",
    "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: john@example.com                               │
│   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: john@example.com                               │
│   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: john@example.com

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 (john@example.com)
        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 "file=@contacts.csv"

CSV format:

csv
name,email,phone,telegram,tags
John Doe,john@example.com,+1234567890,@johndoe,"customer,vip"
Jane Smith,jane@example.com,+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.