Build on BotCrafter

One API key lets any app you run — a clinic system, a booking tool, a POS — send WhatsApp messages, send approved templates, and build bots on behalf of a BotCrafter account. One webhook gets every reply sent straight back to you. This page covers both sides.

Base URLhttps://api.botcrafter.inThis is the live production API. Every path below is relative to it.
  1. Create an accountSign up for BotCrafter with a business name, email, and password. This becomes the account everything below acts on — every message sent and every flow built through the API belongs to this account, exactly as if you'd done it from the dashboard yourself.
  2. Generate an API keyFrom Settings → API key, generate a key. It's shown once — store it somewhere safe. Regenerating immediately invalidates the previous key, so treat rotation as a real cutover, not a casual refresh.
  3. Connect a WhatsApp numberFrom Connections → WhatsApp, connect the number you'll send from. This gives you a connection_id — every send call below needs it, since an account can have more than one number connected.

Core concepts

Authentication

Every request — to the API or in place of a dashboard login — is authenticated the same way: a bearer token in the Authorization header.

header
Authorization: Bearer botcrafter_••••••••••••••••••••••••••••••••

There's one active key per account. It carries the full authority of the account owner — sending, publishing bots, everything on this page — so hand it only to apps you trust, and store it the way you'd store a database password, not a client-side config value.

Core concepts

Response format

Every response, success or failure, is the same envelope.

200 OK
{
  "success": true,
  "data": { "sent": true }
}
4xx / 5xx
{
  "success": false,
  "error": "invalid API key"
}

Check success before touching data — don't infer failure from an empty body.

Core concepts

The 24-hour window

This is a WhatsApp platform rule, not a BotCrafter one — it governs which of the two send endpoints below you can use.

WhatsApp only allows free-form messages within 24 hours of the customer's last message to you. Outside that window, the only way to reach them is a pre-approved template — a fixed message shape Meta has reviewed in advance. Sending a template is also how you re-open the window: once a customer replies, you can send free-form again for another 24 hours.

Inside the 24h windowOutside the 24h window
Free-form text
Send a message
WorksRejected by Meta
Approved template
Send a template
WorksWorks

API reference

Sending & building

Four things an integration typically does: send a message, send a template, and build or publish a bot flow.

POST/api/v1/notify

Sends a free-form text message through a connected number.

Requirement

Only works within 24 hours of the customer's last inbound message. See The 24-hour window.

Body

FieldType
connection_idstringRequired
tostring, E.164Required
messagestringRequired
curl
# cURL
curl -X POST https://api.botcrafter.in/api/v1/notify \
  -H "Authorization: Bearer $BOTCRAFTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "connection_id": "8e2c...f01a",
    "to": "+15551234567",
    "message": "Hi Jane — your 3pm appointment is confirmed."
  }'

POST/api/v1/integrations/templates/:id/send

Sends an approved template — the way to reach someone outside the 24h window, or to guarantee delivery regardless of when they last wrote in.

Requirement

The template's status must be approved. Templates are created and submitted for Meta's review from the dashboard; check status with List templates first.

Body

FieldType
connection_idstringRequired
tostring, E.164Required
parametersstring[]Optional
card_parametersstring[][]Optional, carousels only
curl
# cURL — parameters fill the template's {{1}}, {{2}}... in order
curl -X POST https://api.botcrafter.in/api/v1/integrations/templates/tmpl_9f21/send \
  -H "Authorization: Bearer $BOTCRAFTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "connection_id": "8e2c...f01a",
    "to": "+15551234567",
    "parameters": ["Jane", "Friday 3:00 PM"]
  }'

GET/api/v1/integrations/templates

Lists every template on the account, so you can find an approved one's id before sending it.

200 OK
{
  "success": true,
  "data": [
    {
      "id": "tmpl_9f21",
      "name": "appointment_reminder",
      "language": "en_US",
      "category": "UTILITY",
      "status": "approved"
    }
  ]
}

status is one of draft pending approved rejected — only approved can be sent.

Build & publish a flow

A bot flow is built the same way whether it comes from the visual builder or from your own app: create it, shape its graph, point it at a number, publish it. These five calls are that lifecycle.

POST/api/v1/integrations/flows

Creates an empty flow.

curl
curl -X POST $BASE_URL/api/v1/integrations/flows \
  -H "Authorization: Bearer $BOTCRAFTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Appointment reminder" }'
# → { "success": true, "data": { "id": "flow_c81a" } }
GET/api/v1/integrations/flows

Lists every flow on the account — id, name, status, and which number it's assigned to.

GET/api/v1/integrations/flows/:id

Fetches one flow, including its full graph — the node/edge shape the builder produces.

PUT/api/v1/integrations/flows/:id

Replaces the flow's name and graph.

curl
curl -X PUT $BASE_URL/api/v1/integrations/flows/flow_c81a \
  -H "Authorization: Bearer $BOTCRAFTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Appointment reminder",
    "graph": {
      "nodes": [
        { "id": "n1", "type": "trigger", "position": {"x":0,"y":0}, "data": {} },
        { "id": "n2", "type": "message", "position": {"x":0,"y":160},
          "data": { "text": "Hi {{contact.name}}, this is a reminder about your visit." } }
      ],
      "edges": [ { "id": "e1", "source": "n1", "target": "n2" } ]
    }
  }'
PUT/api/v1/integrations/flows/:id/connection

Assigns which connected number the flow runs on.

curl
curl -X PUT $BASE_URL/api/v1/integrations/flows/flow_c81a/connection \
  -H "Authorization: Bearer $BOTCRAFTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "connection_id": "8e2c...f01a" }'
POST/api/v1/integrations/flows/:id/publish

Publishes a draft flow — it starts running for real customers on its assigned number.

Order matters

Publish after the graph is built and a connection is assigned — an unpublished flow never runs, no matter how it was created.


Webhooks

Receiving messages

There's no "check for new messages" endpoint to poll — instead, your app gets every inbound WhatsApp event pushed to it the moment it happens.

  1. Pick a URL on your own appSomething like https://your-app.example.com/webhooks/botcrafter that accepts a POST with a JSON body. It needs to be publicly reachable — BotCrafter has to be able to call it.
  2. Register it in the dashboardUnder Settings → Connections → Your own backend, set that URL and choose a secret (min. 8 characters — you invent this, it isn't issued to you). Use Test to confirm delivery works before relying on it.
  3. Verify and handle deliveriesEvery delivery carries an HMAC signature made with that same secret — see Verifying signatures below.

Delivery

Field
POST to your target URL
Content-Type: application/json
X-Wabot-Signature: sha256=<hex>HMAC-SHA256 of the raw body
request body
{
  "event": "message.received",
  "timestamp": "2026-08-22T10:04:11Z",
  "data": {
    "connection_id": "8e2c...f01a",
    "from": "+15551234567",
    "contact_name": "Jane Doe",
    "type": "text",
    "body": "Can I reschedule to Monday?",
    "media_url": ""
  }
}

Respond with any 2xx quickly. A non-2xx or a timeout is logged as a failed delivery — there's no retry queue yet, so don't do slow work before responding; queue it and respond first.

Verifying signatures

Same convention as Stripe and GitHub: recompute the HMAC yourself and compare.

node.js
const crypto = require('crypto');

function isValid(rawBody, signatureHeader, secret) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(rawBody) // the raw, unparsed request body
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(expected), Buffer.from(signatureHeader)
  );
}

Verify against the raw request body — parsing to JSON and re-serializing before hashing will produce a mismatch.

Event types

EventFires when
message.receivedA customer sends any inbound message on a connected number.

More event types (delivery receipts, flow-triggered events) are on the roadmap — the envelope shape above is designed so handling a new one is just a new event switch case, not a new integration.


Reference

Errors

Status codes you'll actually see from these endpoints.

200Success.
201Created — a new flow.
400Malformed request — a required field is missing, or a business rule was violated (e.g. publishing a flow with no connection).
401Missing or invalid API key.
404The template or flow ID doesn't exist on this account.
409Conflict — e.g. a template with that name and language already exists.
500Something failed on our side. Safe to retry.
502WhatsApp/Meta rejected the send — error carries their message verbatim, e.g. a send outside the 24h window with no template.

No rate limit is enforced today — that's a trust extended to you, not a guarantee for the future. Build as if reasonable throttling could show up later.