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 --> AfterHow Link Codes Work#
- User requests a link code on Platform A
- Outeract generates a unique code and sends it to the user
- User sends the code on Platform B
- 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-CCCCExample: 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)
Generating Link Codes#
generateLinkCode returns a link_code.generated event; the code itself is in the event’s payload. Pass sendToUser: true to have Outeract deliver the code to the user on their platform automatically.
mutation GenerateLinkCode($identityId: UUID!) {
generateLinkCode(
identityId: $identityId
expiryMinutes: 15
maxUses: 1
) {
id
eventTypeName
payload
}
}Response:
{
"data": {
"generateLinkCode": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"eventTypeName": "link_code.generated",
"payload": {
"code": "1234-5678-9012-5924",
"expiry_minutes": 15,
"max_uses": 1,
"uses": 0
}
}
}
}Activating Link Codes#
Automatic Detection#
Enable automatic link code detection in your application settings in the console: set link_code_auto_detect to enabled.
When enabled, Outeract automatically detects link codes in incoming messages and processes them.
Manual Activation#
redeemLinkCode merges the two user accounts and returns a link_code.activation event:
mutation RedeemLinkCode($code: String!, $identityId: UUID!) {
redeemLinkCode(
code: $code
identityId: $identityId
) {
id
eventTypeName
payload
}
}Link Code Events#
link_code.generated#
{
"event_type": "link_code.generated",
"payload": {
"code": "1234-5678-9012-5924",
"expiry_minutes": 15,
"max_uses": 1,
"uses": 0,
"generated_by_identity_id": "pu_abc123"
}
}link_code.activation#
{
"event_type": "link_code.activation",
"payload": {
"code": "1234-5678-9012-5924",
"source_identity_id": "pu_abc123",
"target_identity_id": "pu_xyz789",
"merged_user_id": "user_merged123"
}
}Implementation Example#
Bot Flow for Link Code Generation#
async def handle_link_request(message, identity_id):
# Generate link code
result = await client.execute("""
mutation GenerateLinkCode($identityId: UUID!) {
generateLinkCode(identityId: $identityId) {
id
payload
}
}
""", {"identityId": identity_id})
code = result["generateLinkCode"]["payload"]["code"]
# Send to user
await send_message(
identity_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_identity_id"],
"Your accounts have been linked successfully!"
)
# Notify on target platform
await send_message(
payload["target_identity_id"],
"Link code accepted! Your accounts are now connected."
)User Experience#
Requesting a Link Code#
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"Activating a Link Code#
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(
identityId: $id
expiryMinutes: 30 # Default: 15
)Usage Limits#
generateLinkCode(
identityId: $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 hour4. Checksum Validation#
Codes include a checksum to prevent typos and brute-force attempts.
5. User Consent#
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."
}Self-Link Attempt#
{
"error": "SELF_LINK_ATTEMPT",
"message": "Cannot link a user to themselves."
}Querying Linked Users#
Get User with All Platform Identities#
query GetLinkedUser($userId: UUID!) {
users(userIds: [$userId]) {
edges {
node {
id
name
identities {
id
externalId
identityType
platformConnection {
id
platformName
}
createdAt
}
}
}
}
}Find User by Any Platform Identity#
query FindUserByPlatform($externalId: String!) {
identities(externalIds: [$externalId]) {
id
externalId
identityType
user {
id
name
identities {
externalId
identityType
}
}
}
}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.