Skip to main content
Layercode supports more than voice or text replies. When you need to pass button clicks, form submissions, or other UI state to your agent backend mid-turn, emit a client.response.data event from the client SDK. The payload arrives at your webhook as a data event without interrupting the current turn. The webhook can respond with a regular JSON response (not an SEE stream like other webhook event types), which is then delivered immediately back to the client as a response.data event. This data flow is in addition to the ability of other webhook event types (like message or session.start) returning response.data SEE events, which are also sent to the client as response.data events.

Vanilla JS example

send-data.html
<button id="confirm-order" type="button">Confirm order</button>

<script type="module">
  import LayercodeClient from 'https://cdn.jsdelivr.net/npm/@layercode/js-sdk@latest/dist/layercode-js-sdk.esm.js';

  const client = new LayercodeClient({
    agentId: 'your-agent-id',
    authorizeSessionEndpoint: '/api/authorize'
  });

  await client.connect();

  document.getElementById('confirm-order')?.addEventListener('click', () => {
    client.sendClientResponseData({
      action: 'confirm_order',
      orderId: 'ORD-12345',
      timestamp: Date.now()
    });
  });
</script>
What happens:
  • The current turn continues uninterrupted.
  • The payload is forwarded as a data webhook event with the session/turn identifiers.

React example

app/components/OrderActions.tsx
'use client';
import { useLayercodeAgent } from '@layercode/react-sdk';

export function OrderActions() {
  const { status, sendClientResponseData } = useLayercodeAgent({
    agentId: process.env.NEXT_PUBLIC_LAYERCODE_AGENT_ID!,
    authorizeSessionEndpoint: '/api/authorize'
  });

  const handleConfirm = () => {
    sendClientResponseData({
      action: 'confirm_order',
      orderId: 'ORD-12345',
      timestamp: Date.now()
    });
  };

  return (
    <button type="button" onClick={handleConfirm} disabled={status !== 'connected'}>
      Confirm order
    </button>
  );
}

Backend example

When the client emits client.response.data, your webhook receives a data event. Respond with plain JSON (not SSE messages) using type: "response.data". The payload is delivered to the client and surfaced via the onDataMessage callback. The snippet below only handles the data event for clarity:
Express
import express from 'express';

const app = express();
app.use(express.json());

app.post('/agent', async (req, res) => {
  const { type, turn_id, data } = req.body;

  if (type === 'data') {
    // Return normal JSON with type "response.data"
    // This is received on the client in onDataMessage(...)
    return res.json({
      type: 'response.data',
      turn_id,
      content: { status: 'received', echo: data }
    });
  }

  // ...handle other event types (e.g. 'message', 'session.start') with SSE responses
});
On the client, read this via onDataMessage (the same applies to the React SDK):
new LayercodeClient({
  /* ... */
  onDataMessage: (data) => {
    console.log('Received from backend:', data);
  }
});