Skip to content
i-Connect
  • Features
  • Solutions
  • Pricing
  • Security
  • Help
  • About
  • Contact
Sign in Talk to sales
  • Features
  • Solutions
  • Pricing
  • Security
  • Help
  • About
  • Contact
Talk to sales Sign in

Help / Developers

API keys, the public API and webhooks

Last updated: 2 November 2026

On this page
  1. API keys
  2. Basics
  3. Endpoints
  4. Webhooks
  5. Verifying webhook signatures
  6. Lists, calendars and bookings
  7. Dynamic Flows: data requests

On this page

  1. API keys
  2. Basics
  3. Endpoints
  4. Webhooks
  5. Verifying webhook signatures
  6. Lists, calendars and bookings
  7. Dynamic Flows: data requests

Add contacts, send approved templates and enrol people in sequences from your own systems, and get signed events back when things happen.

The public API and webhooks are plan features, and need the Owner or Admin role to set up. If API keys says the API isn't switched on for your organisation, write to support@i-connect.world.

API keys

  • Create keys in Settings → API keys. Give each system its own key, with only the scopes it needs, an optional list of IP addresses it may call from, and an optional expiry date.
  • The key is shown once. i-Connect stores only a hash of it. If you lose it, rotate the key.
ScopeLets the key
contacts.readRead contacts
contacts.writeCreate and update contacts (and record consent)
messages.send.templateSend template messages
messages.readRead message status
sequences.enrollEnrol contacts in sequences
forms.submitSubmit forms
bookings.readRead lists, calendars, free slots and bookings
bookings.writeMake and cancel bookings
lists.writeChange lists and calendars
orders.readRead products and orders
orders.writePlace orders and mark them paid, shipped, delivered or cancelled
products.writeAdd and change products and stock

Basics

  • Base URL https://api.i-connect.world/public/v1. JSON in and out. Phone numbers in international format, e.g. +919876543210.
  • Authenticate every call with a key from API keys: Authorization: Bearer ic_live_…. Keys work only here (not on the dashboard API), only for their scopes and, if you set one, only from their IP list.
  • Limits: 20 requests a second per key, bursts of 50. Over that you get 429 with Retry-After: 1.
  • Errors are application/problem+json with a stable code to branch on:
{ "type": "https://i-connect.world/problems/template-not-approved", "title": "The template isn't approved (PENDING)",
  "status": 409, "code": "TEMPLATE_NOT_APPROVED", "requestId": "…" }

Idempotency. Send Idempotency-Key: <your unique id> (required on POST /messages). Repeating a key with the same body returns the first response with Idempotent-Replayed: true; with a different body you get 422; while the first is still running, 409. Keys are kept 24 hours; a request that failed frees its key.

Endpoints

POST /contacts

Scope: contacts.write (Create and update contacts (and record consent))

Creates or updates a contact by phone. Consent is recorded only with the exact wording the person agreed to.

curl https://api.i-connect.world/public/v1/contacts \
  -H "Authorization: Bearer $IC_KEY" -H "Content-Type: application/json" \
  -d '{"phone":"+919876543210","name":"Asha Rao","tags":["website"],
       "attributes":{"city":"Pune"},
       "consent":{"purpose":"MARKETING","text":"Yes, send me offers on WhatsApp","ip":"203.0.113.7"}}'

Returns contactId, created, consentOutcome and any skippedFields.

GET /contacts/{phone}

Scope: contacts.read (Read contacts)

One contact, with tags, attributes and consent state.

POST /contacts/{phone}/tags

Scope: contacts.write (Create and update contacts (and record consent))

{ "tags": ["hot-lead", "2bhk"] }

POST /messages

Scope: messages.send.template (Send template messages)

Queues an approved template to one person (answer 202). The dashboard's checks apply: consent and opt-outs, quiet hours and the frequency cap. Leave out channelId if you have one number.

curl https://api.i-connect.world/public/v1/messages \
  -H "Authorization: Bearer $IC_KEY" -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-10234-packed" \
  -d '{"to":"+919876543210",
       "template":{"name":"order_status_update","language":"en","variables":{"1":"Asha","2":"#10234"}}}'

Returns { "outboxId", "status", "contactId" }.

GET /messages/{outboxId}

Scope: messages.read (Read message status)

Where the message is: status, a skipReason if it wasn't sent, WhatsApp's id and delivered / read times.

POST /sequences/{id}/enroll

Scope: sequences.enroll (Enrol contacts in sequences)

{ "phone": "+919876543210" }

Returns outcome (enrolled, or why not) and enrollmentId.

POST /forms/{id}/submissions

Scope: forms.submit (Submit forms)

Submits a live form server-side, with the same validation and consent rules as the hosted page (answer 201).

{ "phone": "+919876543210", "values": { "name": "Asha Rao", "budget": "60-80L" }, "consent": true }

Webhooks

  • Add an endpoint in Settings → Webhooks: your server's HTTPS URL (HTTPS only; private and internal addresses are refused) and the events you want.
  • Each endpoint has a signing secret, shown once. Rotate signing secret gives you a new one.
  • Settings → Webhooks also keeps a delivery log for each endpoint.
EventSent when
message.receivedA customer sends a message
message.statusA message is delivered, read or fails
contact.createdA contact is created
contact.opted_outA contact opts out
form.submittedA form is submitted
flow.completedA WhatsApp Flow is completed
campaign.completedA broadcast finishes
conversation.assignedA conversation is assigned
sequence.stepA sequence reaches a “Call webhook” step
booking.createdA slot is booked
booking.cancelledA booking is cancelled
order.placedAn order is placed
order.paidAn order is marked paid
order.status_changedAn order is packed, shipped, delivered or cancelled

Verifying webhook signatures

Each delivery is a POST with a JSON body { "id", "type", "createdAt", "orgId", "data" } and these headers: X-iConnect-Event, X-iConnect-Event-Id (the same on retries: use it to ignore duplicates), X-iConnect-Delivery and

X-iConnect-Signature: t=1760166000,v1=5f1c…e9

v1 is the hex HMAC-SHA256 of t + "." + raw body with the endpoint's signing secret. Check it on the raw bytes, before parsing:

// Node.js (Express: app.post(path, express.raw({ type: "application/json" }), handler))
import crypto from "node:crypto";

function verify(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  const age = Math.abs(Date.now() / 1000 - Number(parts.t));
  if (!parts.t || !parts.v1 || age > 300) return false;
  const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}

Answer 2xx within 5 seconds and do the work afterwards. Anything else is retried after 1 minute, 5 minutes, 30 minutes, 2 hours and 6 hours; after 10 failures in a row the endpoint is marked failing and the owner is told.

Lists, calendars and bookings

The lists and calendars your booking Flows read (see Bookings and calendars). Keep them in step with your own booking system through these calls: Flows read them live, show only free slots, and a slot is never booked past its places.

curl -X PUT https://api.i-connect.world/public/v1/lists/doctors \
  -H "Authorization: Bearer $IC_KEY" -H "Content-Type: application/json" \
  -d '{"name":"Doctors","items":[{"id":"dr_mehta","title":"Dr. Mehta (General)"},
                                 {"id":"dr_rao","title":"Dr. Rao (ENT)"}]}'

A calendar, for PUT /calendars/appointments:

{ "name": "Appointments", "timezone": "Asia/Kolkata", "daysAhead": 14, "minNoticeMinutes": 60,
  "itemListKey": "doctors", "itemDays": { "dr_rao": ["MONDAY", "WEDNESDAY", "FRIDAY"] },
  "closedDates": ["2026-11-12"], "bookedTag": "appt-booked", "cancelledTag": "appt-cancelled",
  "contactFields": { "date": "appointment_date", "time": "appointment_slot", "item": "doctor" },
  "slots": [ { "id": "morning", "title": "Morning (9–12)", "start": "09:00",
               "days": ["MONDAY","TUESDAY","WEDNESDAY","THURSDAY","FRIDAY","SATURDAY"], "capacity": 6 } ] }

PUT /lists/{key}

Scope: lists.write (Change lists and calendars)

Creates or replaces a list. Names are at most 30 characters (WhatsApp's limit); ids are yours, or made from the name. Turning an item off keeps it on old bookings but stops offering it.

PUT /lists/{key}/items/{itemId}

Scope: lists.write (Change lists and calendars)

Adds or changes one item: { "title": "Dr. Rao (ENT)", "active": false }. DELETE on the same path removes it.

PUT /calendars/{key}

Scope: lists.write (Change lists and calendars)

Creates or replaces a calendar: time slots with their places, days ahead, minimum notice, closed dates, places per item of a list (with the days each item can be booked), the tags added on booking and cancellation, and the contact fields every booking fills.

GET /calendars/{key}/availability?from=&to=&item=

Scope: bookings.read (Read lists, calendars, free slots and bookings)

Places per day and slot: capacity, booked and free. item is required when the calendar counts places per item. Up to 90 days per call.

POST /bookings

Scope: bookings.write (Make and cancel bookings)

Books a slot made outside WhatsApp (phone, walk-in, your own app) so Flows stop offering it. A full or closed slot answers 409 SLOT_UNAVAILABLE. Send an Idempotency-Key to retry safely. A new phone number becomes a contact.

GET /bookings?calendar=&from=&to=&status=&phone=

Scope: bookings.read (Read lists, calendars, free slots and bookings)

Bookings in date order (up to 500), with the item and slot names as booked, where each was made (FLOW, API, DASHBOARD) and your externalRef. GET /bookings/{id} returns one.

POST /bookings/{id}/cancel

Scope: bookings.write (Make and cancel bookings)

Frees the place: { "reason": "Patient called" }. Cancelling twice is harmless.

A booking, for POST /bookings:

{ "calendar": "appointments", "item": "dr_mehta", "date": "2026-11-03", "slot": "morning",
  "phone": "+919876543210", "name": "Asha Rao", "externalRef": "PMS-10234", "note": "First visit" }

The webhook events booking.created and booking.cancelled carry the contact and a booking object: calendar, item, date, slot, start time, source, name, phone and your externalRef.

Dynamic Flows: data requests

A WhatsApp Flow screen set to Load from your system asks the flow's webhook endpoint for its data while the person fills the flow in, for example the free slots for the service they chose. The request is signed like every webhook (X-iConnect-Event: flow.data_request) and is not retried: the person is waiting.

{ "type": "flow.data_request", "requestId": "…", "test": false,
  "flow": { "id": "…", "name": "Book a visit" }, "screen": "SLOT",
  "answers": { "service": "repair" },
  "contact": { "id": "…", "phone": "+919876543210", "name": "Asha Rao" },
  "flowToken": "ft_…" }

Answer 2xx within 5 seconds with every key the screen uses: options as a list of id and title (titles up to 30 characters; up to 200 options for a dropdown, 20 for radio buttons and checkboxes), texts as strings. Other keys are ignored. Or answer with an error to show that message on the previous screen instead.

{ "data": { "intro": "Times for tomorrow",
            "slots": [ { "id": "t10", "title": "10:00" }, { "id": "t11", "title": "11:00" } ] } }

{ "error": "No slots left today" }

If your server is slow, fails or answers with the wrong shape, the person sees “Sorry, we couldn't load this right now” and the flow builder shows why. Test lookup in the builder sends a request with "test": true. The first screen of a flow can't load data: ask something first.

Related articles

  • Set up i-Connect, step by stepFrom a new account to your first WhatsApp message: the six steps and what each one needs.
  • Connect your WhatsApp numberConnect a number with Facebook in Meta's own window, or manually with its IDs and a system-user token, and what each check means.
  • Keep using the WhatsApp Business appUse the phone app and i-Connect on the same number, and what changes when you do.

Still stuck? Write to support@i-connect.world with your organisation's name and what you see on screen.

i-Connect

WhatsApp messaging your customers agreed to, on the Official WhatsApp Business Platform (Cloud API).

Product

  • Features
  • Solutions
  • Pricing
  • Security
  • Help centre
  • Sign in

Company

  • About
  • Contact
  • Grievance Officer
  • Legal

Legal

  • Privacy Policy
  • Terms of Service
  • Data Deletion Instructions
  • Refund & Cancellation Policy
  • Acceptable Use & Messaging Policy

Contact

  • support@i-connect.world
  • sales@i-connect.world
  • privacy@i-connect.world

i-Connect is a product of Layap Infotech Private Limited.

CIN U72900HR2016PTC065513 · 1071, Sector-47, Gurgaon, Haryana, India, 122001

WhatsApp is a trademark of WhatsApp LLC. i-Connect is not affiliated with, endorsed or sponsored by Meta Platforms, Inc. or WhatsApp LLC.

© 2026 Layap Infotech Private Limited

Colour theme