Authenticate a widget user by your own user id
curl --request POST \
--url http://localhost:8080/widget/authenticate-user-by-external-id \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"external_id": "<string>",
"email": "[email protected]",
"mcp_access": {
"server_ids": [
"3c90c3cc-0d44-4b50-8888-8dd25736052a"
],
"account_id": "<string>"
},
"name": "<string>",
"avatar_url": "<string>",
"phone": "<string>",
"customData": {},
"chat_context": "<string>",
"http_action_overrides": {
"query_params": {},
"path_params": {},
"body_params": {},
"headers": {}
}
}
'import requests
url = "http://localhost:8080/widget/authenticate-user-by-external-id"
payload = {
"external_id": "<string>",
"email": "[email protected]",
"mcp_access": {
"server_ids": ["3c90c3cc-0d44-4b50-8888-8dd25736052a"],
"account_id": "<string>"
},
"name": "<string>",
"avatar_url": "<string>",
"phone": "<string>",
"customData": {},
"chat_context": "<string>",
"http_action_overrides": {
"query_params": {},
"path_params": {},
"body_params": {},
"headers": {}
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
external_id: '<string>',
email: '[email protected]',
mcp_access: {server_ids: ['3c90c3cc-0d44-4b50-8888-8dd25736052a'], account_id: '<string>'},
name: '<string>',
avatar_url: '<string>',
phone: '<string>',
customData: {},
chat_context: '<string>',
http_action_overrides: {query_params: {}, path_params: {}, body_params: {}, headers: {}}
})
};
fetch('http://localhost:8080/widget/authenticate-user-by-external-id', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_PORT => "8080",
CURLOPT_URL => "http://localhost:8080/widget/authenticate-user-by-external-id",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'external_id' => '<string>',
'email' => '[email protected]',
'mcp_access' => [
'server_ids' => [
'3c90c3cc-0d44-4b50-8888-8dd25736052a'
],
'account_id' => '<string>'
],
'name' => '<string>',
'avatar_url' => '<string>',
'phone' => '<string>',
'customData' => [
],
'chat_context' => '<string>',
'http_action_overrides' => [
'query_params' => [
],
'path_params' => [
],
'body_params' => [
],
'headers' => [
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "http://localhost:8080/widget/authenticate-user-by-external-id"
payload := strings.NewReader("{\n \"external_id\": \"<string>\",\n \"email\": \"[email protected]\",\n \"mcp_access\": {\n \"server_ids\": [\n \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n ],\n \"account_id\": \"<string>\"\n },\n \"name\": \"<string>\",\n \"avatar_url\": \"<string>\",\n \"phone\": \"<string>\",\n \"customData\": {},\n \"chat_context\": \"<string>\",\n \"http_action_overrides\": {\n \"query_params\": {},\n \"path_params\": {},\n \"body_params\": {},\n \"headers\": {}\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("http://localhost:8080/widget/authenticate-user-by-external-id")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"external_id\": \"<string>\",\n \"email\": \"[email protected]\",\n \"mcp_access\": {\n \"server_ids\": [\n \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n ],\n \"account_id\": \"<string>\"\n },\n \"name\": \"<string>\",\n \"avatar_url\": \"<string>\",\n \"phone\": \"<string>\",\n \"customData\": {},\n \"chat_context\": \"<string>\",\n \"http_action_overrides\": {\n \"query_params\": {},\n \"path_params\": {},\n \"body_params\": {},\n \"headers\": {}\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("http://localhost:8080/widget/authenticate-user-by-external-id")
http = Net::HTTP.new(url.host, url.port)
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"external_id\": \"<string>\",\n \"email\": \"[email protected]\",\n \"mcp_access\": {\n \"server_ids\": [\n \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n ],\n \"account_id\": \"<string>\"\n },\n \"name\": \"<string>\",\n \"avatar_url\": \"<string>\",\n \"phone\": \"<string>\",\n \"customData\": {},\n \"chat_context\": \"<string>\",\n \"http_action_overrides\": {\n \"query_params\": {},\n \"path_params\": {},\n \"body_params\": {},\n \"headers\": {}\n }\n}"
response = http.request(request)
puts response.read_body{
"token": "<string>",
"contact": {
"id": "<string>"
}
}{
"statusCode": 123,
"message": "<string>",
"error": "<string>"
}Contacts
Authenticate a widget user by your own user id
Get a verified widget contact token for a user identified by your own user ID. Use when several of your users can share an email or phone, or when users can change them.
POST
/
widget
/
authenticate-user-by-external-id
Authenticate a widget user by your own user id
curl --request POST \
--url http://localhost:8080/widget/authenticate-user-by-external-id \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"external_id": "<string>",
"email": "[email protected]",
"mcp_access": {
"server_ids": [
"3c90c3cc-0d44-4b50-8888-8dd25736052a"
],
"account_id": "<string>"
},
"name": "<string>",
"avatar_url": "<string>",
"phone": "<string>",
"customData": {},
"chat_context": "<string>",
"http_action_overrides": {
"query_params": {},
"path_params": {},
"body_params": {},
"headers": {}
}
}
'import requests
url = "http://localhost:8080/widget/authenticate-user-by-external-id"
payload = {
"external_id": "<string>",
"email": "[email protected]",
"mcp_access": {
"server_ids": ["3c90c3cc-0d44-4b50-8888-8dd25736052a"],
"account_id": "<string>"
},
"name": "<string>",
"avatar_url": "<string>",
"phone": "<string>",
"customData": {},
"chat_context": "<string>",
"http_action_overrides": {
"query_params": {},
"path_params": {},
"body_params": {},
"headers": {}
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
external_id: '<string>',
email: '[email protected]',
mcp_access: {server_ids: ['3c90c3cc-0d44-4b50-8888-8dd25736052a'], account_id: '<string>'},
name: '<string>',
avatar_url: '<string>',
phone: '<string>',
customData: {},
chat_context: '<string>',
http_action_overrides: {query_params: {}, path_params: {}, body_params: {}, headers: {}}
})
};
fetch('http://localhost:8080/widget/authenticate-user-by-external-id', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_PORT => "8080",
CURLOPT_URL => "http://localhost:8080/widget/authenticate-user-by-external-id",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'external_id' => '<string>',
'email' => '[email protected]',
'mcp_access' => [
'server_ids' => [
'3c90c3cc-0d44-4b50-8888-8dd25736052a'
],
'account_id' => '<string>'
],
'name' => '<string>',
'avatar_url' => '<string>',
'phone' => '<string>',
'customData' => [
],
'chat_context' => '<string>',
'http_action_overrides' => [
'query_params' => [
],
'path_params' => [
],
'body_params' => [
],
'headers' => [
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "http://localhost:8080/widget/authenticate-user-by-external-id"
payload := strings.NewReader("{\n \"external_id\": \"<string>\",\n \"email\": \"[email protected]\",\n \"mcp_access\": {\n \"server_ids\": [\n \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n ],\n \"account_id\": \"<string>\"\n },\n \"name\": \"<string>\",\n \"avatar_url\": \"<string>\",\n \"phone\": \"<string>\",\n \"customData\": {},\n \"chat_context\": \"<string>\",\n \"http_action_overrides\": {\n \"query_params\": {},\n \"path_params\": {},\n \"body_params\": {},\n \"headers\": {}\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("http://localhost:8080/widget/authenticate-user-by-external-id")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"external_id\": \"<string>\",\n \"email\": \"[email protected]\",\n \"mcp_access\": {\n \"server_ids\": [\n \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n ],\n \"account_id\": \"<string>\"\n },\n \"name\": \"<string>\",\n \"avatar_url\": \"<string>\",\n \"phone\": \"<string>\",\n \"customData\": {},\n \"chat_context\": \"<string>\",\n \"http_action_overrides\": {\n \"query_params\": {},\n \"path_params\": {},\n \"body_params\": {},\n \"headers\": {}\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("http://localhost:8080/widget/authenticate-user-by-external-id")
http = Net::HTTP.new(url.host, url.port)
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"external_id\": \"<string>\",\n \"email\": \"[email protected]\",\n \"mcp_access\": {\n \"server_ids\": [\n \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n ],\n \"account_id\": \"<string>\"\n },\n \"name\": \"<string>\",\n \"avatar_url\": \"<string>\",\n \"phone\": \"<string>\",\n \"customData\": {},\n \"chat_context\": \"<string>\",\n \"http_action_overrides\": {\n \"query_params\": {},\n \"path_params\": {},\n \"body_params\": {},\n \"headers\": {}\n }\n}"
response = http.request(request)
puts response.read_body{
"token": "<string>",
"contact": {
"id": "<string>"
}
}{
"statusCode": 123,
"message": "<string>",
"error": "<string>"
}Call this endpoint from your backend with an API key that has the
widget:write scope. It returns the same verified token as Authenticate contact. Pass that token to the widget through user.token.
- Matching: the contact is found by
external_idalone. Email and phone are optional details on the contact: they can change, and several contacts can share them. - First call: a new contact is created with the
external_idand the details you send, even when another contact already has the same email or phone. - Later calls: the contact with that
external_idis updated with the details you send, such as a new email or phone. - Other ways in: email, phone, and messaging channels, and Authenticate contact, keep identifying people by email or phone. They never match a contact that has an
external_id, so a message from the same address belongs to a separate contact. - Validation:
external_idis required, can’t be blank, and is at most 255 characters.
http_action_overrides for your AI actions and mcp_access for personal connections.
external_id identifies the contact. It is different from the widget’s user.externalId option, which only scopes session history in the browser.Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Body
application/json
The user's stable id in your system. The contact is matched by this id alone, so email and phone can change or be shared with other contacts.
Required string length:
1 - 255Pattern:
^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$Show child attributes
Show child attributes
Available options:
en, fr, de, nl, pl, pt, es, it, ru, ja, ko, zh, ar, tr, sv, da, no, fi, el, cs, hu, th, vi, id, he, hi, uk, ro, bg, hr, sk, sl, sr, et, lv, lt, is, ga, ms, tl, fa, bn, ta, te, ur, sw, zu, af, sq, hy, az, eu, be, bs, ca, cy, ku, ckb, kmr Show child attributes
Show child attributes
Show child attributes
Show child attributes
Was this page helpful?