Context Links are buttons in the conversation sidebar that open external URLs with contact and conversation details filled in. Agents click them to jump to CRMs, billing systems, or internal dashboards without copy-pasting identifiers.
URL template variables
These placeholders are replaced with the current contact's details when an agent clicks the link.
| Variable | Description |
|---|---|
{{email}} |
Contact's email |
{{phone}} |
Contact's phone number |
{{phone_country_code}} |
Contact's phone country code |
{{external_user_id}} |
Contact's external user ID |
{{contact_id}} |
Contact's internal libredesk ID |
{{first_name}} |
Contact's first name |
{{last_name}} |
Contact's last name |
{{conversation_uuid}} |
UUID of the current conversation |
{{token}} |
Encrypted token containing all fields (requires secret) |
All values except {{contact_id}} and {{conversation_uuid}} are URL-encoded automatically.
Examples
Simple lookup by email:
https://crm.example.com/contacts?email={{email}}
Multiple parameters:
https://billing.example.com/customer?ext_id={{external_user_id}}&email={{email}}
Internal dashboard with conversation context:
https://dashboard.internal/lookup?contact={{contact_id}}&conv={{conversation_uuid}}
Encrypted token:
https://api.example.com/auth/libredesk?token={{token}}
The receiving system decrypts the token to get all contact and agent fields in one payload, without exposing them in the URL.
Encrypted token
When you use {{token}}, libredesk generates an AES-256-GCM encrypted, time-limited token containing all the above fields plus agent_id, agent_email, iat, and exp. The receiving system decrypts it with the shared secret.
Decrypting the token
import base64, json, time
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
def decrypt_context_token(token, secret):
raw = base64.b64decode(token)
nonce = raw[:12]
ciphertext = raw[12:]
aesgcm = AESGCM(secret.encode('utf-8'))
plaintext = aesgcm.decrypt(nonce, ciphertext, None)
return json.loads(plaintext)
# Usage
secret = "your-32-character-shared-secret!" # exactly 32 characters
payload = decrypt_context_token(token_from_url, secret)
if payload["exp"] < time.time():
raise ValueError("Token has expired")
print(payload["email"], payload["conversation_uuid"])
