Working with End Users
An End User is a person in your application who sends and receives messages through Surge's embeddable UI components. End Users are distinct from Dashboard Users (people who log in to hq.surge.app). If you're building a SaaS platform where your customers interact with Surge-powered messaging, your customers' customers are End Users.
What an End User is
End Users are provisioned via the Surge API and belong to a specific account. They're used in two ways:
- Embedded UI: the inbox and conversation components authenticate as a specific End User, showing that user's conversations and sending messages on their behalf
- Message attribution: messages sent or received on behalf of an End User include a
user_idfield, so you can trace activity back to the individual
End Users do not have Surge passwords or sessions. Authentication for embedded components goes through a short-lived JWT that your server generates.
Provision an End User
Create an End User via the API before you mount any components for them:
from surge import Surge
surge = Surge()
user = surge.users.create(
account_id="{account_id}",
first_name="Jordan",
last_name="Patel",
metadata={"internal_user_id": "u_9887"},
)import Surge from "@surgeapi/node";
const surge = new Surge();
const user = await surge.users.create("{account_id}", {
first_name: "Jordan",
last_name: "Patel",
metadata: { internal_user_id: "u_9887" },
});require "surge_api"
surge = SurgeAPI::Client.new
user = surge.users.create(
"{account_id}",
first_name: "Jordan",
last_name: "Patel",
metadata: { "internal_user_id" => "u_9887" }
)client = Surge.Client.new(System.get_env("SURGE_API_KEY"))
{:ok, user} =
Surge.Users.create(client, "{account_id}", %{
first_name: "Jordan",
last_name: "Patel",
metadata: %{internal_user_id: "u_9887"}
})curl -X POST https://api.surge.app/accounts/{account_id}/users \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"first_name": "Jordan",
"last_name": "Patel",
"metadata": {
"internal_user_id": "u_9887"
}
}'{
"id": "usr_01jrzhe8d9enptypyx360pcmxu",
"first_name": "Jordan",
"last_name": "Patel",
"metadata": {
"internal_user_id": "u_9887"
}
}Store the returned id alongside the user's record in your database. You'll use it to generate component tokens and attribute messages.
Generate a component token
Your server generates a short-lived JWT for each user session. The JWT scopes the embedded component to that specific user's data.
The simplest path is the token endpoint:
response = surge.users.create_token(user_id="{user_id}")
token = response.tokenconst response = await surge.users.createToken("{user_id}");
const token = response.token;response = surge.users.create_token("{user_id}")
token = response.token{:ok, token} = Surge.Users.create_token(client, "{user_id}", %{})curl -X POST https://api.surge.app/users/{user_id}/tokens \
-H "Authorization: Bearer YOUR_API_KEY"{
"token": "eyJhbGciOiJFZERTQSIsImtpZCI6InNnbl8wMWouLi4ifQ..."
}Return this token to your frontend and use it to mount the component. Generate a new token on each page load, tokens are short-lived.
Typical vertical SaaS flow
- When a customer signs up for your SaaS product, create a Surge End User via
POST /accounts/{account_id}/users. Store theid. - When that customer loads a page in your app that includes embedded messaging, your server calls
POST /users/{user_id}/tokensto get a fresh JWT. - Your frontend receives the JWT and mounts the Surge Inbox or Conversation component with it.
- The component shows only that user's conversations and sends messages attributed to them.
# On page load, server-side
@app.get("/api/surge-token")
async def get_surge_token(current_user: User):
response = surge.users.create_token(id=current_user.surge_user_id)
return {"token": response.token}// In the browser
const { token } = await fetch("/api/surge-token").then(r => r.json());
SurgeEmbed.mount("inbox", {
target: document.getElementById("surge-inbox"),
token,
});List and manage End Users
# List users in an account
for user in surge.users.list(account_id="{account_id}"):
print(user.id)
# Update a user
surge.users.update("{user_id}", first_name="Jordan M.")
# Delete a user
surge.users.delete("{user_id}")// List users in an account
for await (const user of await surge.users.list("{account_id}")) {
console.log(user.id);
}
// Update a user
await surge.users.update("{user_id}", { first_name: "Jordan M." });
// Delete a user
await surge.users.delete("{user_id}");# List users in an account
page = surge.users.list("{account_id}")
page.data.each { |u| puts u.id }
# Update a user
surge.users.update("{user_id}", first_name: "Jordan M.")
# Delete a user
surge.users.delete("{user_id}")# Surge.Users.list isn't typed in the Elixir SDK yet — use the raw client.
{:ok, page} =
Surge.Client.request(client, :get, "/accounts/{account_id}/users")
Enum.each(page["data"], fn u -> IO.puts(u["id"]) end)
# Update a user
{:ok, _} = Surge.Users.update(client, "{user_id}", %{first_name: "Jordan M."})
# Delete a user
{:ok, _} = Surge.Users.delete(client, "{user_id}")# List users in an account
curl "https://api.surge.app/accounts/{account_id}/users" \
-H "Authorization: Bearer YOUR_API_KEY"
# Update a user
curl -X PATCH https://api.surge.app/users/{user_id} \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "first_name": "Jordan M." }'
# Delete a user
curl -X DELETE https://api.surge.app/users/{user_id} \
-H "Authorization: Bearer YOUR_API_KEY"Deleting an End User removes their Surge record but does not delete message history.