In this tutorial you'll build a tiny web chat widget where:
- The frontend is a simple HTML/JS chat UI.
- The backend uses:
- An LLM (example: OpenAI) with tool calling.
- The Block API as the implementation of the
book_appointmenttool.
The goal is to show that:
"From a webchat, it only takes a small tool + one HTTP call to use Block to book across any platform."
You'll need:
- Node.js 18+
- An OpenAI API key (or another LLM that supports tools / function calling)
- A Block API key and basic familiarity with your Block docs at https://useblock.tech/docs
- A Block connection ID (created via the Block developer portal)
We'll keep everything in a single Node project for minimal setup:
block-webchat-tutorial/
package.json
server.js
.env.example
public/
index.html
styles.css
app.js
mkdir block-webchat-tutorial
cd block-webchat-tutorial
npm init -y
npm install express cors dotenv openaiCreate a .env.example:
cat > .env.example << 'EOF'
OPENAI_API_KEY=sk-...
BLOCK_API_KEY=block_key_...
BLOCK_API_BASE_URL=https://api.useblock.tech
CONNECTION_ID=conn_...
PORT=3000
DEFAULT_PROVIDER="Get this from the connected booking system"
EOFThen create your real .env and fill in the values:
cp .env.example .env
# edit .env with your keys + correct Block base URLThis file:
- Serves the static chat UI from
/public. - Exposes
POST /api/chat. - Uses OpenAI with a tool called
book_appointment. - When the LLM calls the tool, the server:
- Calls the Block API to book
- Polls for job completion (Block actions are async)
- Feeds the result back into the LLM
- Returns the final, user-friendly answer.
The Block API uses an async execution pattern:
-
POST
/v1/actions- Submit the booking action- Returns a
jobIdimmediately (HTTP 202) - Request format:
{ "action": "BookAppointment", "connectionId": "conn_abc123", "payload": { "datetime": "2025-11-15T14:00:00-08:00", "provider": "Carl Morris", "service": "60 Minute Massage", "customer": { "firstName": "Jane", "lastName": "Doe", "phone": "+12065551212" }, "note": "Optional note" } }
- Returns a
-
GET
/v1/jobs/{jobId}- Poll for job status- Returns job status:
queued,in_progress,success, orerror - When status is
success, theresultfield contains the booking details
- Returns job status:
The bookAppointmentViaBlock function in server.js handles both steps automatically.
A super simple chat widget layout:
See public/index.html for the complete HTML structure.
Minimal styling so it feels like a widget, not a raw page:
See public/styles.css for the complete CSS.
This script:
- Manages the chat history in the browser.
- Sends message + history to
/api/chat. - Renders the reply.
See public/app.js for the complete implementation.
npm run dev
# or, if you didn't add a script yet:
# node server.jsThen open:
http://localhost:3000
Try prompts like:
- "I'd like a haircut next Tuesday afternoon."
- "Can you book an AC maintenance visit for tomorrow at 3pm? My name is Alex, phone is 555-123-4567."
You should see:
- The assistant asking follow-ups until it has name, phone, service, and time.
- A tool call → your server calls the Block API via
bookAppointmentViaBlock. - A confirmation message summarizing the booked appointment.
Make sure your .env file contains:
BLOCK_API_KEY- Your Block API key (starts withblock_key_)CONNECTION_ID- Your Block connection ID (starts withconn_)
The job polling has a 2-minute timeout. If bookings take longer, you may need to:
- Increase the timeout in
bookAppointmentViaBlock - Use webhooks instead of polling (see Block docs)
Your API key may be invalid or expired. Check your Block developer portal.
- Add more tools (e.g.,
get_availability) - Implement webhook handling instead of polling
- Style the chat widget to match your brand
- Deploy to a hosting service (Vercel, Railway, etc.)
- Set up chat history persistence
MIT
Note: This tutorial application uses the Block API, which is subject to the Block Integration API Terms of Service. By using this code with the Block API, you agree to comply with those terms.