Fency.ai
Sessions

Sessions

How the React SDK uses short-lived client tokens created by your server.

A session is how your backend controls access to the Fency APIs. Your server creates the session with a secret key and passes a short-lived clientToken to the webapp. The React SDK uses that token to call Fency. It never sees the secret key and cannot widen what the session allows.

Here are the sessions you can create today:

FieldPurpose
createStreamCreates a clientToken allowing the webapp to create a new stream it can listen to. This is a bootstrapping session and is always required.
createAgentTaskCreates a clientToken allowing the webapp to start an agent task such as chat, memory search, explore memories, or explore product. Required whenever the webapp starts a task.
createAgentTaskFileDownloadCreates a clientToken allowing the webapp to download a file produced by an agent task. Create this session when the user downloads a file.
getAgentTaskResponseCreates a clientToken allowing the webapp to fetch the response of a completed agent task. Create this session when the webapp needs the finished result.
submitManualActionResultCreates a clientToken allowing the webapp to submit the result of a manual action. Create this session when a task is waiting for a human or browser action result.

How it works

  1. Client SDK initiates the request: When the React SDK needs to make API requests (e.g. for creating a new stream), it calls the fetchCreateStreamClientToken function you pass to FencyProvider, which requests a client token from your server endpoint (e.g. /api/stream-client-token).
  2. Server creates a session: Your backend receives the request and calls the Fency API with your secret key. The API returns a session object that includes a clientToken, which your endpoint returns to the frontend.
  3. SDK uses the token: The React SDK receives the clientToken and uses it to authenticate with the Fency.ai API.

Your server creates the session the same way every time. Only the request body changes.

// server route handler (e.g. POST /api/agent-task-session)
const secretKey = process.env.FENCY_SECRET_KEY

if (!secretKey) {
    throw new Error('FENCY_SECRET_KEY is not defined.')
}

export async function POST() {
    const response = await fetch('https://api.fency.ai/v1/sessions', {
        method: 'POST',
        headers: {
            Authorization: `Bearer ${secretKey}`,
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({
            createAgentTask: {
                taskType: 'STREAMING_CHAT_COMPLETION',
            },
        }),
    })

    const data = await response.json()
    return new Response(JSON.stringify(data), {
        status: response.status,
        headers: { 'Content-Type': 'application/json' },
    })
}

Examples

Swap the body for the session you need. Each guardRails.memoryTypes entry uses exactly one scope: memoryIds, match, or includeAll.

createStream

{
    createStream: {},
}

createAgentTask (STREAMING_CHAT_COMPLETION)

{
    createAgentTask: {
        taskType: 'STREAMING_CHAT_COMPLETION',
        metadata: {
            userId: 'usr_...',
        },
    },
}

createAgentTask (STRUCTURED_CHAT_COMPLETION)

{
    createAgentTask: {
        taskType: 'STRUCTURED_CHAT_COMPLETION',
        metadata: {
            userId: 'usr_...',
        },
    },
}

createAgentTask (MEMORY_CHAT)

{
    createAgentTask: {
        taskType: 'MEMORY_CHAT',
        metadata: {
            userId: 'usr_...',
        },
        guardRails: {
            memoryTypes: [
                {
                    memoryTypeId: 'mty_...',
                    match: {
                        organization_id: 'org_...',
                        tags: ['renewal', 'enterprise'],
                    },
                    metadata: [
                        {
                            key: 'renewal_date',
                            visible: true,
                            description: 'ISO-8601 date the contract auto-renews',
                        },
                        {
                            key: 'internal_notes',
                            visible: false,
                        },
                    ],
                },
                {
                    memoryTypeId: 'mty_...',
                    memoryIds: ['mem_...', 'mem_...'],
                    metadata: [
                        {
                            key: 'renewal_date',
                            visible: true,
                            description: 'ISO-8601 date the contract auto-renews',
                        },
                    ],
                },
                {
                    memoryTypeId: 'mty_...',
                    includeAll: true,
                },
            ],
        },
    },
}

createAgentTask (MEMORY_SEARCH)

{
    createAgentTask: {
        taskType: 'MEMORY_SEARCH',
        metadata: {
            userId: 'usr_...',
        },
        guardRails: {
            memoryTypes: [
                {
                    memoryTypeId: 'mty_...',
                    match: {
                        organization_id: 'org_...',
                        tags: ['renewal', 'enterprise'],
                    },
                    metadata: [
                        {
                            key: 'renewal_date',
                            visible: true,
                            description: 'ISO-8601 date the contract auto-renews',
                        },
                        {
                            key: 'internal_notes',
                            visible: false,
                        },
                    ],
                },
                {
                    memoryTypeId: 'mty_...',
                    memoryIds: ['mem_...', 'mem_...'],
                    metadata: [
                        {
                            key: 'renewal_date',
                            visible: true,
                            description: 'ISO-8601 date the contract auto-renews',
                        },
                    ],
                },
                {
                    memoryTypeId: 'mty_...',
                    includeAll: true,
                },
            ],
        },
    },
}

createAgentTask (EXPLORE_MEMORIES)

{
    createAgentTask: {
        taskType: 'EXPLORE_MEMORIES',
        conversationId: 'cnv_...',
        metadata: {
            userId: 'usr_...',
        },
        background: 'You help users find relevant contracts from document content and metadata.',
        examples: [
            {
                query: 'Which parents lack a matching child?',
                approach: 'Use keywordSearch parentForEach and filter empty search_matching_memory_ids.',
            },
        ],
        allowedActions: ['renderPieChart', 'renderTimeseriesChart'],
        guardRails: {
            memoryTypes: [
                {
                    memoryTypeId: 'mty_...',
                    match: {
                        organization_id: 'org_...',
                        tags: ['renewal', 'enterprise'],
                    },
                    metadata: [
                        {
                            key: 'renewal_date',
                            visible: true,
                            description: 'ISO-8601 date the contract auto-renews',
                        },
                        {
                            key: 'internal_notes',
                            visible: false,
                        },
                    ],
                },
                {
                    memoryTypeId: 'mty_...',
                    memoryIds: ['mem_...', 'mem_...'],
                    metadata: [
                        {
                            key: 'renewal_date',
                            visible: true,
                            description: 'ISO-8601 date the contract auto-renews',
                        },
                    ],
                },
                {
                    memoryTypeId: 'mty_...',
                    includeAll: true,
                },
            ],
        },
    },
}

createAgentTask (EXPLORE_PRODUCT)

{
    createAgentTask: {
        taskType: 'EXPLORE_PRODUCT',
        conversationId: 'cnv_...',
        metadata: {
            userId: 'usr_...',
        },
        allowedActions: ['setTheme', 'applyFilter'],
        guardRails: {
            memoryTypes: [
                {
                    memoryTypeId: 'mty_...',
                    match: {
                        tenant_id: 'ten_...',
                    },
                    metadata: [
                        {
                            key: 'sku',
                            visible: true,
                            description: 'Store SKU used to look up the product',
                        },
                        {
                            key: 'cost_price',
                            visible: false,
                        },
                    ],
                },
                {
                    memoryTypeId: 'mty_...',
                    memoryIds: ['mem_...', 'mem_...'],
                },
                {
                    memoryTypeId: 'mty_...',
                    includeAll: true,
                },
            ],
        },
    },
}

createAgentTaskFileDownload

{
    createAgentTaskFileDownload: {
        agentTaskFileId: 'atf_...',
    },
}

getAgentTaskResponse

{
    getAgentTaskResponse: {
        agentTaskId: 'ata_...',
    },
}

submitManualActionResult

{
    submitManualActionResult: {
        agentTaskId: 'ata_...',
        actionCallId: 'aca_...',
    },
}

See Guardrails, Allowed actions, Background, Examples, Conversation, and the integration examples for how those fields work and for React wiring.

Security

Client tokens are scoped to a single session and expire after use or when the session ends. They never expose your secret key. By creating sessions on your server, you maintain full control over who can obtain client tokens and can enforce your own authentication and rate limiting before creating sessions.

On this page