Appearance
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
| Field | Description |
|---|---|
name | Contact name |
email | Email address |
phone | Phone number |
telegram | Telegram username |
whatsapp | WhatsApp number |
twitter | Twitter/X handle |
external_id | External system ID |
notes | Free-form notes |
tags | JSON array of tags |
metadata | JSON metadata |
Creating Contacts
Via Dashboard
- Navigate to Contacts
- Click Add Contact
- Fill in details
- 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 customersprospect- Potential customersvip- High-value contactssupport- Support contactspartner- 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 channelsMemory Scoping
The agent stores two types of memories:
| Scope | Key Pattern | Example |
|---|---|---|
| Contact-specific | memory:contact:{contactId}:{key} | User preferences, facts about them |
| Agent-wide | memory:{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 usingCross-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 ESTConversations
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 CorpWith 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,prospectExport Contacts
bash
curl "https://your-domain.com/api/agents/{id}/contacts/export?format=csv" > contacts.csvAccess 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:
| Field | Description |
|---|---|
tag | The contact tag this profile applies to (e.g., vip, support, restricted) |
priority | Numeric priority for conflict resolution (higher wins) |
description | Human-readable description of the profile's purpose |
allowedToolCategories | Tool categories the contact can use (e.g., ["browser", "memory"]) |
deniedToolCategories | Tool categories explicitly blocked |
allowedToolClusters | Specific tool clusters permitted |
deniedToolClusters | Specific tool clusters blocked |
canAccessConversationHistory | Whether the contact's conversations can reference past history |
canAccessContacts | Whether the agent can use contact-related tools during this contact's session |
canAccessMemories | Whether 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
priorityvalue 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
- Navigate to Contacts
- Open the Access tab
- Click Add Profile to create a new access profile
- Set the tag, priority, description, and permission flags
- 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
tagfield. 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-profilesCreate 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}/accessResponse:
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:
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.
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").
Conversation recall scope: When
canAccessConversationHistoryis false, the agent cannot search or reference past conversations for that contact. WhencanAccessMemoriesis false, memory recall and storage tools are disabled. WhencanAccessContactsis 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.
