> ## Documentation Index
> Fetch the complete documentation index at: https://docs.layercode.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Send JSON data from the client

> Forward events to your frontend to your agent backend without interrupting the live conversation

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](/api-reference/webhook-sse-api#response-data), which are also sent to the client as `response.data` events.

## Vanilla JS example

```html send-data.html theme={null}
<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

```tsx app/components/OrderActions.tsx theme={null}
'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:

```ts Express theme={null}
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](/sdk-reference/react-sdk)):

```ts theme={null}
new LayercodeClient({
  /* ... */
  onDataMessage: (data) => {
    console.log('Received from backend:', data);
  }
});
```
