Webhook Events Reference

Complete reference for all 14 TitanCard webhook events with payload examples

Last updated: January 16, 2026

TitanCard webhooks deliver real-time HTTP POST notifications when events occur in your account. This reference documents all available events, their payload structures, and how to verify webhook signatures.

Webhook Payload Structure

Every webhook delivers a JSON payload with this structure:

json
{
  "event": "connection.created",
  "timestamp": 1705420800000,
  "data": {
    // Event-specific data
  }
}

HTTP Headers

Each webhook request includes these headers:

text
Content-Type: application/json
X-Webhook-Signature: sha256=abc123...
X-Webhook-Event: connection.created
User-Agent: TitanCard-Webhooks/1.0

Signature Verification

Always verify the X-Webhook-Signature header to ensure webhooks are authentic. The signature is an HMAC-SHA256 hash of the request body using your webhook secret.

Node.js / JavaScript

javascript
const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, secret) {
  const expectedSignature = 'sha256=' + 
    crypto.createHmac('sha256', secret)
      .update(payload)
      .digest('hex');
  
  // Use timing-safe comparison to prevent timing attacks
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

// Express.js example
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const isValid = verifyWebhookSignature(req.body, signature, process.env.WEBHOOK_SECRET);
  
  if (!isValid) {
    return res.status(401).json({ error: 'Invalid signature' });
  }
  
  const event = JSON.parse(req.body);
  // Handle the event...
  res.status(200).json({ received: true });
});

Python

python
import hmac
import hashlib

def verify_webhook_signature(payload: bytes, signature: str, secret: str) -> bool:
    expected = 'sha256=' + hmac.new(
        secret.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(signature, expected)

# Flask example
@app.route('/webhook', methods=['POST'])
def webhook():
    signature = request.headers.get('X-Webhook-Signature')
    if not verify_webhook_signature(request.data, signature, WEBHOOK_SECRET):
        return {'error': 'Invalid signature'}, 401
    
    event = request.json
    # Handle the event...
    return {'received': True}, 200

Card Events

card.created

Triggered when a new business card is created.

json
{
  "event": "card.created",
  "timestamp": 1705420800000,
  "data": {
    "card_id": "k57abc123def",
    "name": "John Smith",
    "slug": "john-smith",
    "title": "Software Engineer",
    "company": "Acme Inc",
    "email": "john@acme.com",
    "card_type": "professional",
    "created_at": 1705420800000
  }
}

card.updated

Triggered when card details are modified.

json
{
  "event": "card.updated",
  "timestamp": 1705420800000,
  "data": {
    "card_id": "k57abc123def",
    "name": "John Smith",
    "slug": "john-smith",
    "title": "Senior Software Engineer",
    "company": "Acme Inc",
    "changed_fields": ["title"],
    "updated_at": 1705420800000
  }
}

card.deleted

Triggered when a card is deleted.

json
{
  "event": "card.deleted",
  "timestamp": 1705420800000,
  "data": {
    "card_id": "k57abc123def",
    "slug": "john-smith",
    "deleted_at": 1705420800000
  }
}

card.viewed

Triggered when someone views your card profile.

json
{
  "event": "card.viewed",
  "timestamp": 1705420800000,
  "data": {
    "card_id": "k57abc123def",
    "card_slug": "john-smith",
    "view_source": "qr",
    "viewer_country": "United States",
    "viewer_city": "San Francisco",
    "total_views": 142,
    "viewed_at": 1705420800000
  }
}

card.shared

Triggered when your card is shared via QR code, NFC tap, or link copy.

json
{
  "event": "card.shared",
  "timestamp": 1705420800000,
  "data": {
    "card_id": "k57abc123def",
    "card_name": "John Smith",
    "card_slug": "john-smith",
    "share_source": "nfc",
    "total_views": 142,
    "total_shares": 28,
    "viewer_country": "United States",
    "viewer_city": "San Francisco",
    "shared_at": 1705420800000
  }
}

Connection Events

connection.created

Triggered when you make a new connection (most common event for CRM sync).

json
{
  "event": "connection.created",
  "timestamp": 1705420800000,
  "data": {
    "id": "j57xyz789ghi",
    "first_name": "Jane",
    "last_name": "Doe",
    "full_name": "Jane Doe",
    "email": "jane@example.com",
    "phone": "+1-555-123-4567",
    "company": "Tech Corp",
    "title": "Product Manager",
    "website": "https://techcorp.com",
    "linkedin": "https://linkedin.com/in/janedoe",
    "twitter": "@janedoe",
    "address": "San Francisco, CA",
    "notes": "Met at TechCrunch Disrupt",
    "tags": ["conference", "product"],
    "source": "qr_scan",
    "direction": "inbound",
    "status": "new",
    "message": "Great meeting you!",
    "meeting_event": "TechCrunch Disrupt 2026",
    "meeting_location": "San Francisco, CA",
    "meeting_date": 1705420800000,
    "meeting_method": "in_person",
    "created_at": 1705420800000,
    "updated_at": null,
    "last_contacted_at": null
  }
}

connection.updated

Triggered when connection details are modified.

json
{
  "event": "connection.updated",
  "timestamp": 1705420800000,
  "data": {
    "id": "j57xyz789ghi",
    "first_name": "Jane",
    "last_name": "Doe",
    "full_name": "Jane Doe",
    "email": "jane@example.com",
    "phone": "+1-555-123-4567",
    "company": "Tech Corp",
    "title": "Senior Product Manager",
    "notes": "Promoted in Q1 2026",
    "tags": ["conference", "product", "follow-up"],
    "status": "contacted",
    "updated_at": 1705420800000,
    "last_contacted_at": 1705420800000
  }
}

connection.deleted

Triggered when a connection is archived or permanently deleted.

json
{
  "event": "connection.deleted",
  "timestamp": 1705420800000,
  "data": {
    "id": "j57xyz789ghi",
    "email": "jane@example.com",
    "full_name": "Jane Doe",
    "deleted_at": 1705420800000
  }
}

connection.tagged

Triggered when tags are added to or removed from a connection.

json
{
  "event": "connection.tagged",
  "timestamp": 1705420800000,
  "data": {
    "id": "j57xyz789ghi",
    "full_name": "Jane Doe",
    "email": "jane@example.com",
    "tags": ["vip", "conference", "product"],
    "tags_added": ["vip"],
    "tags_removed": [],
    "tagged_at": 1705420800000
  }
}

connection.status_changed

Triggered when a connection's pipeline status changes (e.g., new → contacted → qualified).

json
{
  "event": "connection.status_changed",
  "timestamp": 1705420800000,
  "data": {
    "id": "j57xyz789ghi",
    "full_name": "Jane Doe",
    "email": "jane@example.com",
    "company": "Tech Corp",
    "previous_status": "contacted",
    "new_status": "qualified",
    "changed_at": 1705420800000
  }
}

Reminder Events

reminder.created

Triggered when a follow-up reminder is scheduled for a connection.

json
{
  "event": "reminder.created",
  "timestamp": 1705420800000,
  "data": {
    "id": "r89reminder123",
    "connection_id": "j57xyz789ghi",
    "scheduled_for": 1705507200000,
    "message": "Follow up about partnership opportunity",
    "status": "pending",
    "type": "follow_up",
    "contact_name": "Jane Doe",
    "contact_email": "jane@example.com",
    "contact_company": "Tech Corp"
  }
}

reminder.due

Triggered when a scheduled reminder becomes due.

json
{
  "event": "reminder.due",
  "timestamp": 1705507200000,
  "data": {
    "id": "r89reminder123",
    "connection_id": "j57xyz789ghi",
    "scheduled_for": 1705507200000,
    "message": "Follow up about partnership opportunity",
    "status": "due",
    "type": "follow_up",
    "contact_name": "Jane Doe",
    "contact_email": "jane@example.com",
    "contact_company": "Tech Corp"
  }
}

Other Events

note.added

Triggered when a note is added to a connection.

json
{
  "event": "note.added",
  "timestamp": 1705420800000,
  "data": {
    "id": "n12note456",
    "connection_id": "j57xyz789ghi",
    "note_content": "Had a great call discussing Q2 plans. She's interested in our enterprise offering.",
    "contact_name": "Jane Doe",
    "contact_email": "jane@example.com",
    "added_at": 1705420800000
  }
}

enrichment.completed

Triggered when contact data enrichment completes for a connection.

json
{
  "event": "enrichment.completed",
  "timestamp": 1705420800000,
  "data": {
    "connection_id": "j57xyz789ghi",
    "enriched_fields": ["linkedin", "company", "title", "location"],
    "status": "success",
    "provider": "clearbit",
    "completed_at": 1705420800000
  }
}

Field Reference

Common fields across connection events and their data types:

text
Field                  Type      Description
──────────────────────────────────────────────────────────────────────
id                     string    Unique connection identifier
first_name             string    Contact's first name
last_name              string    Contact's last name
full_name              string    Computed: first_name + last_name
email                  string    Primary email address
phone                  string    Phone number with country code
company                string    Company or organization name
title                  string    Job title
website                string    Company or personal website URL
linkedin               string    LinkedIn profile URL
twitter                string    Twitter/X handle or URL
address                string    City, state, or full address
notes                  string    User notes about the connection
tags                   array     Array of tag strings
source                 string    How connected: qr_scan, nfc, manual, import
direction              string    inbound (they found you) or outbound
status                 string    Pipeline status: new, contacted, qualified, etc.
message                string    Initial message from connection
meeting_event          string    Event name where you met
meeting_location       string    Location where you met
meeting_date           number    Unix timestamp of meeting
meeting_method         string    in_person, virtual, phone, email
created_at             number    Unix timestamp when created
updated_at             number    Unix timestamp when last updated
last_contacted_at      number    Unix timestamp of last contact

Error Handling

Your webhook endpoint should:

  • Return a 2xx status code within 30 seconds
  • Handle duplicate events idempotently (use the event timestamp)
  • Return 401 if signature verification fails
  • Return 400 for malformed payloads

Retry Behavior

If your endpoint doesn't respond with 2xx, TitanCard will:

  • Retry up to 3 times with exponential backoff (1min, 5min, 15min)
  • Mark the webhook as 'failed' after 5 consecutive failures
  • Stop sending events until you reactivate the webhook

Testing Webhooks

Tips for testing your webhook integration:

  • Use ngrok or similar to expose localhost for testing
  • Check Settings > Webhooks for delivery logs and error details
  • Use the 'Test' button to send a sample payload
  • Verify signature validation works before going to production

Need help? See the Zapier Guide or Make Guide for step-by-step integration tutorials, or contact support@titancard.com.

Ready to get started?

Create your digital business card in minutes. Join thousands of professionals already using TitanApp.

Get Started Free

Was this page helpful?

Documentation | TitanCard | TitanCard