Contact Tracking

📖

This page describes features extending the AI Gateway, which provides a unified API for accessing multiple AI providers. To learn more, see AI Gateway.

Associate requests with Contact identifiers for user-level observability and analytics.

📘

Contacts are orq.ai entities used to track project expenses, token usage, to learn more, see Contact Tracking.

Quick Start

const response = await openai.chat.completions.create({
  model: "openai/gpt-4o",
  messages: [{ role: "user", content: "How can I upgrade my account?" }],
  orq: {
    contact: {
      id: "user-12345",
      display_name: "John Smith",
      email: "[email protected]",
      metadata: {
        plan: "premium",
        signup_date: "2024-01-15",
      },
    },
  },
});

Configuration

ParameterTypeRequiredDescription
idstringYesUnique contact identifier
display_namestringNoHuman-readable contact name
emailstringNoContact email address
metadataobjectNoCustom key-value pairs for contact data
logo_urlstringNoURL to contact's profile image
tagsstring[]NoClassification tags for contact segmentation

Use Cases

ScenarioContact ID StrategyMetadata Example
User Analyticsuser-{userId}{"plan": "pro", "usage_tier": "high"}
Customer Supportsupport-{ticketId}{"priority": "high", "issue_type": "billing"}
A/B Testingtest-{userId}-{variant}{"experiment": "pricing-v2", "variant": "b"}
Multi-tenanttenant-{orgId}-{userId}{"org": "acme-corp", "role": "admin"}

Implementation Examples

User Session Tracking

// Track authenticated user interactions
const userSession = {
  userId: "user-12345",
  userProfile: await getUserProfile(userId),
};

const response = await openai.chat.completions.create({
  model: "openai/gpt-4o",
  messages: [{ role: "user", content: "Show me my recent orders" }],
  orq: {
    contact: {
      id: userSession.userId,
      display_name: userSession.userProfile.fullName,
      email: userSession.userProfile.email,
      metadata: {
        plan: userSession.userProfile.subscriptionPlan,
        last_login: userSession.userProfile.lastLogin,
        total_orders: userSession.userProfile.orderCount,
      },
      tags: [
        "authenticated",
        `plan-${userSession.userProfile.subscriptionPlan}`,
      ],
    },
  },
});

Support Ticket Integration

// Associate AI interactions with support tickets
const supportContext = {
  ticketId: "TICKET-789",
  customerId: "customer-456",
  customerInfo: await getCustomerInfo(customerId),
};

const response = await openai.chat.completions.create({
  model: "openai/gpt-4o",
  messages: [{ role: "user", content: "I need help with my billing issue" }],
  orq: {
    contact: {
      id: `support-${supportContext.ticketId}`,
      display_name: supportContext.customerInfo.name,
      email: supportContext.customerInfo.email,
      metadata: {
        ticket_id: supportContext.ticketId,
        customer_tier: supportContext.customerInfo.tier,
        issue_category: "billing",
        created_at: new Date().toISOString(),
      },
      tags: [
        "support",
        "billing-issue",
        `tier-${supportContext.customerInfo.tier}`,
      ],
    },
  },
});

Multi-Language Support

curl -X POST https://api.orq.ai/v2/proxy/chat/completions \
  -H "Authorization: Bearer $ORQ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-4o",
    "messages": [{"role": "user", "content": "I need technical assistance"}],
    "orq": {
      "contact": {
        "id": "enterprise-user-001",
        "display_name": "Alex Johnson",
        "email": "[email protected]",
        "metadata": {
          "company": "Enterprise Corp",
          "role": "technical_lead",
          "contract_tier": "enterprise"
        },
        "tags": ["enterprise", "technical"]
      }
    }
  }'
import openai
import json

client = openai.OpenAI(
    api_key=os.environ["ORQ_API_KEY"],
    base_url="https://api.orq.ai/v2/proxy"
)

contact_data = {
    "id": "user-67890",
    "display_name": "Maria Garcia",
    "email": "[email protected]",
    "metadata": {
        "preferred_language": "es",
        "timezone": "America/Mexico_City",
        "subscription_status": "active"
    },
    "tags": ["spanish-speaker", "premium-user"]
}

response = client.chat.completions.create(
    model="openai/gpt-4o",
    messages=[{"role": "user", "content": "¿Cómo puedo cambiar mi plan?"}],
    extra_body={
        "orq": {
            "contact": contact_data
        }
    }
)

Advanced Patterns

Dynamic Contact Resolution

interface ContactProfile {
  id: string;
  name: string;
  email: string;
  plan: "free" | "pro" | "enterprise";
  metadata?: Record<string, any>;
}

async function resolveContact(userId: string): Promise<ContactProfile> {
  const user = await database.users.findById(userId);
  const subscription = await database.subscriptions.findByUserId(userId);

  return {
    id: `user-${userId}`,
    name: user.fullName,
    email: user.email,
    plan: subscription.plan,
    metadata: {
      signup_date: user.createdAt,
      last_active: user.lastActiveAt,
      feature_flags: user.featureFlags,
      usage_this_month: await getUsageMetrics(userId),
    },
  };
}

const contact = await resolveContact(currentUserId);

const response = await openai.chat.completions.create({
  model: "openai/gpt-4o",
  messages: [{ role: "user", content: userMessage }],
  orq: { contact },
});

Batch Contact Processing

const batchRequests = [
  { userId: "user1", message: "How do I reset my password?" },
  { userId: "user2", message: "What's my current usage?" },
  { userId: "user3", message: "Can I upgrade my plan?" },
];

const responses = await Promise.all(
  batchRequests.map(async (req) => {
    const userProfile = await getUserProfile(req.userId);

    return openai.chat.completions.create({
      model: "openai/gpt-4o",
      messages: [{ role: "user", content: req.message }],
      orq: {
        contact: {
          id: req.userId,
          display_name: userProfile.name,
          email: userProfile.email,
          metadata: {
            request_batch: "batch-001",
            processed_at: new Date().toISOString(),
          },
          tags: ["batch-processing", `plan-${userProfile.plan}`],
        },
      },
    });
  }),
);

Contact Analytics

Usage Tracking

// Track feature usage per contact
const trackFeatureUsage = async (contactId, feature, context = {}) => {
  const response = await openai.chat.completions.create({
    model: "openai/gpt-4o",
    messages: [{ role: "user", content: "Analyze my data" }],
    orq: {
      contact: {
        id: contactId,
        metadata: {
          feature_used: feature,
          usage_context: context,
          session_id: generateSessionId(),
          timestamp: new Date().toISOString(),
        },
        tags: ["feature-tracking", `feature-${feature}`],
      },
    },
  });

  return response;
};

// Usage
await trackFeatureUsage("user-123", "data-analysis", {
  dataset_size: "large",
  complexity: "medium",
});

Personalization Context

// Provide personalized responses based on contact data
const getPersonalizedResponse = async (contactId, query) => {
  const contact = await getContactProfile(contactId);

  const systemPrompt = `
    You are assisting ${contact.display_name}, a ${contact.metadata.plan} plan user.
    Their preferences: ${JSON.stringify(contact.metadata.preferences)}
    Tailor your response to their experience level and subscription benefits.
  `;

  return await openai.chat.completions.create({
    model: "openai/gpt-4o",
    messages: [
      { role: "system", content: systemPrompt },
      { role: "user", content: query },
    ],
    orq: {
      contact: {
        id: contactId,
        display_name: contact.display_name,
        email: contact.email,
        metadata: {
          ...contact.metadata,
          personalization_enabled: true,
        },
        tags: ["personalized", `plan-${contact.metadata.plan}`],
      },
    },
  });
};

Performance Optimization

Contact Data Caching

// Cache contact profiles to reduce database calls
const contactCache = new Map();
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes

async function getCachedContact(contactId) {
  const cached = contactCache.get(contactId);

  if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
    return cached.data;
  }

  const contact = await fetchContactProfile(contactId);
  contactCache.set(contactId, {
    data: contact,
    timestamp: Date.now(),
  });

  return contact;
}

Metadata Optimization

// Optimize metadata for frequently accessed fields
const optimizeContactMetadata = (fullProfile) => {
  // Only include essential metadata to reduce payload size
  return {
    plan: fullProfile.subscription.plan,
    tier: fullProfile.subscription.tier,
    features: fullProfile.enabledFeatures.slice(0, 5), // Limit array size
    last_active: fullProfile.lastActiveAt,
  };
};

const contact = {
  id: userId,
  display_name: user.name,
  email: user.email,
  metadata: optimizeContactMetadata(userProfile),
  tags: [`plan-${userProfile.plan}`, "active-user"],
};

Troubleshooting

IssueCauseSolution
Contact not appearing in analyticsMissing or invalid contact IDEnsure contact.id is provided and unique
Metadata not updatingContact cache not refreshedClear contact cache or reduce TTL
Performance degradationToo much metadata per requestLimit metadata to essential fields only
Duplicate contactsInconsistent ID formatStandardize contact ID generation

Validation Examples

// Validate contact configuration
function validateContact(contact) {
  const errors = [];

  if (!contact.id) {
    errors.push("Contact ID is required");
  }

  if (contact.id.length > 255) {
    errors.push("Contact ID too long (max 255 chars)");
  }

  if (contact.email && !isValidEmail(contact.email)) {
    errors.push("Invalid email format");
  }

  if (contact.metadata && Object.keys(contact.metadata).length > 20) {
    errors.push("Too many metadata fields (max 20)");
  }

  if (contact.tags && contact.tags.length > 10) {
    errors.push("Too many tags (max 10)");
  }

  return errors;
}

// Usage
const contact = { id: "user-123", display_name: "John" };
const errors = validateContact(contact);

if (errors.length > 0) {
  throw new Error(`Contact validation failed: ${errors.join(", ")}`);
}

Best Practices

  1. Consistent IDs: Use predictable contact ID patterns across your application
  2. Essential Metadata: Include only relevant metadata to minimize payload size
  3. Tag Strategy: Use tags for filtering and segmentation, not detailed data
  4. Privacy Compliance: Ensure contact data handling meets privacy requirements
  5. Performance: Cache contact profiles to reduce database lookups
  6. Validation: Always validate contact data before sending requests

Limitations

LimitationDescriptionWorkaround
Contact ID LengthMaximum 255 charactersUse shorter, meaningful identifiers
Metadata SizeRecommended maximum 20 fieldsGroup related data into nested objects
Tag CountMaximum 10 tags per contactUse hierarchical tagging strategy
Email ValidationBasic format validation onlyImplement additional validation client-side
Data PersistenceContact data not stored permanentlyMaintain contact profiles in your system

Integration Examples

CRM Integration

// Sync with CRM systems
const syncWithCRM = async (contactId, interactions) => {
  const crmContact = await crm.contacts.get(contactId);

  const response = await openai.chat.completions.create({
    model: "openai/gpt-4o",
    messages: [{ role: "user", content: "Update my preferences" }],
    orq: {
      contact: {
        id: contactId,
        display_name: crmContact.name,
        email: crmContact.email,
        metadata: {
          crm_id: crmContact.id,
          lead_score: crmContact.leadScore,
          last_interaction: crmContact.lastInteraction,
          deal_stage: crmContact.currentDealStage,
        },
        tags: ["crm-synced", `stage-${crmContact.currentDealStage}`],
      },
    },
  });

  // Update CRM with AI interaction
  await crm.activities.create({
    contactId: crmContact.id,
    type: "ai_interaction",
    description: "AI assistant interaction",
    timestamp: new Date(),
  });

  return response;
};