Link Codes#

Link codes enable users to connect their identities across multiple messaging platforms, creating a unified user profile.

Overview#

When a user contacts you on WhatsApp and later on Slack, they appear as two separate users. Link codes solve this by allowing users to prove they own both identities.

flowchart LR
    subgraph Before["Before Linking"]
        WA1["WhatsApp User<br/>+14155551234<br/>(User A)"]
        SL1["Slack User<br/>U12345678<br/>(User B)"]
    end

    subgraph After["After Linking"]
        subgraph Unified["Unified User"]
            WA2["WhatsApp<br/>+14155551234"]
            SL2["Slack<br/>U12345678"]
        end
    end

    Before --> After
  1. User requests a link code on Platform A
  2. Outeract generates a unique code and sends it to the user
  3. User sends the code on Platform B
  4. Outeract validates and links the two platform users to the same user

Code Format#

Link codes follow a specific format for security and usability:

DDDD-DDDD-DDDD-CCCC

Example: 1234-5678-9012-5924

  • 16 numeric digits (0-9 only)
  • Groups of 4 for readability
  • Last group is a checksum (sum of first 3 groups mod 10000)
  • Expires after a configurable time (default: 15 minutes)

GraphQL#

mutation GenerateLinkCode($platformUserId: UUID!) {
  generateLinkCode(
    platformUserId: $platformUserId
    expiryMinutes: 15
    maxUses: 1
  ) {
    code
    expiresAt
    event {
      id
      eventType
    }
  }
}

REST#

curl -X POST https://api.outeract.com/v1/link-codes \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "platform_user_id": "pu_abc123",
    "expiry_minutes": 15,
    "max_uses": 1
  }'

Response:

{
  "code": "1234-5678-9012-5924",
  "expires_at": "2024-01-15T10:45:00Z",
  "event_id": "evt_linkcode123"
}

Automatic Detection#

Enable automatic link code detection in your application settings:

mutation {
  updateApplication(
    config: {
      link_code_auto_detect: "enabled"
    }
  ) {
    id
    config
  }
}

When enabled, Outeract automatically detects link codes in incoming messages and processes them.

Manual Activation#

mutation ActivateLinkCode($code: String!, $platformUserId: UUID!) {
  activateLinkCode(
    code: $code
    platformUserId: $platformUserId
  ) {
    success
    user {
      id
      platformUsers {
        id
        externalId
        platformConnection {
          platformName
        }
      }
    }
  }
}
{
  "event_type": "link_code.generated",
  "payload": {
    "code": "1234-5678-9012-5924",
    "expiry_minutes": 15,
    "max_uses": 1,
    "uses": 0,
    "generated_by_platform_user_id": "pu_abc123"
  }
}
{
  "event_type": "link_code.activation",
  "payload": {
    "code": "1234-5678-9012-5924",
    "source_platform_user_id": "pu_abc123",
    "target_platform_user_id": "pu_xyz789",
    "merged_user_id": "user_merged123"
  }
}

Implementation Example#

async def handle_link_request(message, platform_user_id):
    # Generate link code
    result = await client.execute("""
        mutation GenerateLinkCode($platformUserId: UUID!) {
            generateLinkCode(platformUserId: $platformUserId) {
                code
                expiresAt
            }
        }
    """, {"platformUserId": platform_user_id})

    code = result["generateLinkCode"]["code"]
    expires = result["generateLinkCode"]["expiresAt"]

    # Send to user
    await send_message(
        platform_user_id,
        f"Your link code is: {code}\n\n"
        f"Enter this code on your other platform to link accounts.\n"
        f"This code expires in 15 minutes."
    )

Webhook Handler for Activation#

async def handle_webhook(event):
    if event["event_type"] == "link_code.activation":
        payload = event["payload"]

        # Notify on source platform
        await send_message(
            payload["source_platform_user_id"],
            "Your accounts have been linked successfully!"
        )

        # Notify on target platform
        await send_message(
            payload["target_platform_user_id"],
            "Link code accepted! Your accounts are now connected."
        )

User Experience#

User on WhatsApp:

User: "I want to link my Slack account"
Bot: "I'll generate a link code for you. Enter this code in Slack within 15 minutes:

1234-5678-9012-5924"

User on Slack:

User: "1234-5678-9012-5924"
Bot: "Account linked! Your WhatsApp and Slack are now connected.
Messages from either platform will appear in your unified inbox."

Configuration Options#

Code Expiry#

generateLinkCode(
  platformUserId: $id
  expiryMinutes: 30  # Default: 15
)

Usage Limits#

generateLinkCode(
  platformUserId: $id
  maxUses: 3  # Default: 1
)

Application-Level Settings#

{
  "link_code_auto_detect": "enabled",
  "link_code_default_expiry_minutes": 15,
  "link_code_default_max_uses": 1
}

Security Considerations#

1. Short Expiry Times#

Keep expiry times short (15-30 minutes) to reduce risk.

2. Single Use#

Default to single-use codes unless multi-use is needed.

3. Rate Limiting#

Limit code generation to prevent abuse:

# Built-in rate limit: 5 codes per user per hour

4. Checksum Validation#

Codes include a checksum to prevent typos and brute-force attempts.

Always inform users what linking means:

  • Unified message history
  • Shared context across platforms
  • Single user profile

Error Handling#

Invalid Code#

{
  "error": "INVALID_LINK_CODE",
  "message": "The link code is invalid or has expired"
}

Expired Code#

{
  "error": "LINK_CODE_EXPIRED",
  "message": "This link code has expired. Please generate a new one."
}

Already Used#

{
  "error": "LINK_CODE_USED",
  "message": "This link code has already been used."
}
{
  "error": "SELF_LINK_ATTEMPT",
  "message": "Cannot link a user to themselves."
}

Querying Linked Users#

Get User with All Platform Identities#

query GetLinkedUser($userId: UUID!) {
  user(id: $userId) {
    id
    name
    platformUsers {
      id
      externalId
      name
      platformConnection {
        id
        platformName
        name
      }
      createdAt
    }
  }
}

Find User by Any Platform Identity#

query FindUserByPlatform($externalId: String!, $platformConnectionId: UUID!) {
  platformUsers(
    filters: {
      externalId: { equals: $externalId }
      platformConnectionId: { equals: $platformConnectionId }
    }
  ) {
    edges {
      node {
        user {
          id
          name
          platformUsers {
            externalId
            platformConnection {
              platformName
            }
          }
        }
      }
    }
  }
}

Best Practices#

1. Clear Instructions#

Provide step-by-step instructions when generating codes.

2. Visual Formatting#

Format codes with dashes for readability: 1234-5678-9012-5924

3. Confirmation Messages#

Confirm successful linking on both platforms.

4. Handle Edge Cases#

  • User already linked
  • Expired codes
  • Invalid format

5. Privacy Notice#

Explain what data will be shared between platforms before linking.