Support
Support agents, website chat, conversations, assignment, and resolution
The Support module powers website chat and the Admin support inbox. Storefront visitors start conversations through the storefront support API. Admin users create support agents, reply as staff, assign conversations, and resolve them.
Storefront Chat
/v1/storefront/support/conversations arky.support.startConversation() /v1/storefront/support/conversations/{conversationId}/messages arky.support.sendMessage() /v1/storefront/support/conversations/{conversationId} arky.support.getConversation() import { initialize } from "arky-sdk/storefront";
import {
clearDurableRequest,
getOrCreateDurableRequest,
withDurableRequestLock,
} from "arky-sdk/utils";
const arky = initialize("arky_pk_...");
const started = await arky.support.startConversation({
agent_key: "default",
channel_metadata: { page: window.location.pathname },
});
const credentials = {
conversation_id: started.conversation.id,
support_token: started.support_token,
};
const credentialsKey = `arky:support-conversation:${credentials.conversation_id}`;
const serializedCredentials = JSON.stringify(credentials);
localStorage.setItem(credentialsKey, serializedCredentials);
if (localStorage.getItem(credentialsKey) !== serializedCredentials) {
throw new Error("Support conversation credentials could not be saved");
}
const request = {
conversation_id: credentials.conversation_id,
input: { type: "text", content: "I need help with an order." },
} as const;
const storageKey = `arky:support-message:${credentials.conversation_id}`;
const next = await withDurableRequestLock(
storageKey,
"support message",
async () => {
const durable = getOrCreateDurableRequest(
storageKey,
request,
"support message",
);
const response = await arky.support.sendMessage({
conversation_id: request.conversation_id,
support_token: credentials.support_token,
message_id: durable.id,
input: request.input,
});
const recorded = response.messages.some(
(message) =>
message.id === durable.id &&
message.conversation_id === request.conversation_id &&
message.role === "user" &&
message.content === request.input.content,
);
if (!recorded)
throw new Error("Support response did not confirm the requested message");
clearDurableRequest(durable, "support message");
return response;
},
);
const current = await arky.support.getConversation(credentials);
startConversation() returns the raw 64-character lowercase hexadecimal support_token once. Persist it durably with
conversation_id; if that write cannot be verified, stop instead of continuing with a volatile
fallback. Follow-up sendMessage() and getConversation() calls require the pair. The SDK removes
support_token from the request payload and sends it only as X-Arky-Support-Token. Treat it as a
bearer credential: never put it in logs, metadata, URLs, query parameters, or request bodies.
message_id is required for every visitor message. Persist one message ID with the exact
message request, reuse it only when retrying that same request, and clear it only after the returned
conversation contains the matching user message. The utility helpers above fail closed when durable
browser storage or cross-tab locking is unavailable.
Parameters
| Name | Type | Description |
|---|---|---|
agent_key optional | string | Support agent key. Omit it to use the default active agent. |
channel_metadata optional | Record<string, unknown> | Storefront context saved with the conversation. |
Support Agents
/v1/stores/{storeId}/support/agents sdk.automation.support.createAgent() /v1/stores/{storeId}/support/agents sdk.automation.support.findAgents() /v1/stores/{storeId}/support/agents/{id} sdk.automation.support.updateAgent() /v1/stores/{storeId}/support/agents/{id} sdk.automation.support.deleteAgent() const agent = await sdk.automation.support.createAgent({
store_id: "store_abc123",
key: "default",
name: "Website Support",
status: "active",
entry_node_id: "hello",
nodes: {
hello: {
type: "message",
text: "Hi. How can we help?",
buttons: ["Talk to us"],
},
},
edges: [],
});
Support agents are store-scoped flow definitions. Nodes can send messages, collect input, hand off to AI mode, or hand off to human staff.
Admin Conversations
/v1/stores/{storeId}/support/conversations sdk.automation.support.findConversations() /v1/stores/{storeId}/support/conversations/{conversationId} sdk.automation.support.getConversation() /v1/stores/{storeId}/support/conversations/{conversationId}/reply sdk.automation.support.replyToConversation() /v1/stores/{storeId}/support/conversations/{conversationId}/assign sdk.automation.support.assignConversation() /v1/stores/{storeId}/support/conversations/{conversationId}/resolve sdk.automation.support.resolveConversation() import {
clearDurableRequest,
getOrCreateDurableRequest,
withDurableRequestLock,
} from "arky-sdk/utils";
const inbox = await sdk.automation.support.findConversations({
store_id: "store_abc123",
status: "escalated",
limit: 25,
});
await sdk.automation.support.assignConversation({
store_id: "store_abc123",
conversation_id: inbox.items[0].id,
account_id: "acct_staff_1",
});
const replyRequest = {
store_id: "store_abc123",
conversation_id: inbox.items[0].id,
content: "I can help with that.",
resolve: false,
};
const replyStorageKey = `arky:support-staff-reply:${replyRequest.store_id}:${replyRequest.conversation_id}`;
await withDurableRequestLock(
replyStorageKey,
"support staff reply",
async () => {
const durable = getOrCreateDurableRequest(
replyStorageKey,
replyRequest,
"support staff reply",
);
const response = await sdk.automation.support.replyToConversation({
...replyRequest,
message_id: durable.id,
});
const recorded = response.messages.some(
(message) =>
message.id === durable.id &&
message.store_id === replyRequest.store_id &&
message.conversation_id === replyRequest.conversation_id &&
message.role === "staff" &&
message.content === replyRequest.content,
);
if (!recorded)
throw new Error(
"Support response did not confirm the requested staff reply",
);
clearDurableRequest(durable, "support staff reply");
return response;
},
);
await sdk.automation.support.resolveConversation({
store_id: "store_abc123",
conversation_id: inbox.items[0].id,
});
Resolved conversations are closed. New visitor messages create or continue active conversations instead of reopening closed support state.
Staff replies also require a durable message_id. A retry of the exact same reply reuses that ID;
a different reply uses a different message ID.