Skip to content
Getting Started

Quickstart

You need a connected Kirim organization with at least one approved WhatsApp Business number. If you haven’t onboarded yet, sign up at app.kirim.dev and connect your number first — the dashboard walks you through Meta’s embedded signup flow.

By the end of this page you’ll have:

  1. Issued an API key.
  2. Resolved your phone_number_id (Meta’s stable account identifier).
  3. Sent a text message to your own phone.
  4. Polled the message status and seen delivered.

Total time: under five minutes if Meta is in a cooperative mood.

  1. Issue an API key.

    In the Kirim dashboard, navigate to Developers → API Keys and click Create key. Give it a descriptive label (e.g. local-laptop or n8n-prod) and copy the plaintext value immediately — Kirim shows it exactly once.

    Terminal window
    # Store the key in your shell — never commit it.
    export KIRIM_KEY=kdv_live_xxxxxxxxxxxxxxxxxxxxxxxx
  2. Verify the key works.

    The /v1/me endpoint introspects your key and returns the organization context.

    Terminal window
    curl -sS https://api.kirim.chat/v1/me \
    -H "Authorization: Bearer $KIRIM_KEY"

    Expected response:

    {
    "data": {
    "organization": {
    "id": "org_…",
    "object": "organization",
    "name": "Your Org"
    },
    "api_key": {
    "id": "key_…",
    "object": "api_key",
    "label": "local-laptop",
    "last4": "abcd"
    },
    "rate_limits": {
    "tier": "default",
    "write_per_minute": 60,
    "read_per_minute": 600
    }
    },
    "request_id": "req_…"
    }
  3. Resolve your phone number ID.

    Kirim uses Meta-style path routing — sender lives in the URL, not the body. Look up your connected accounts and grab the phone_number_id:

    Terminal window
    curl -sS https://api.kirim.chat/v1/accounts \
    -H "Authorization: Bearer $KIRIM_KEY"
    {
    "data": [
    {
    "object": "account",
    "phone_number_id": "106540352242922",
    "phone_number": "+628111222333",
    "name": "Customer Support",
    "status": "connected"
    }
    ],
    "has_more": false,
    "next_cursor": null,
    "request_id": "req_…"
    }

    Stash the id — every per-account endpoint takes it as a path segment.

    Terminal window
    export PHONE_ID=106540352242922
  4. Send your first message.

    Replace +628123456789 with a phone number Meta has already received a message from in the past 24 hours — Meta only allows free-form text inside an open conversation window.

    // bun add @kirimdev/sdk
    import { Kirim } from '@kirimdev/sdk'
    const kirim = new Kirim({ apiKey: process.env.KIRIM_KEY! })
    const phone = kirim.phoneNumbers(process.env.PHONE_ID!)
    const msg = await phone.messages.send({
    messaging_product: 'whatsapp',
    to: '+628123456789',
    type: 'text',
    text: { body: 'Halo dari Kirim' },
    })
    console.log(msg.id) // -> msg_...

    The official SDK adds auto-retry, automatic Idempotency-Key, async pagination, and typed errors. Cache the per-phone client at module top-level for the common single-account case. See the SDK Quickstart for the full walkthrough.

    Expected response:

    {
    "data": {
    "id": "msg_01HXYZABCDEFGHJKMNPQRSTVWX",
    "object": "message",
    "to": "+628123456789",
    "type": "text",
    "status": "pending",
    "created_at": "2026-05-26T08:00:00.000Z"
    },
    "request_id": "req_…"
    }

    The recipient should receive the message within a few seconds.

  5. Poll the status.

    The send is asynchronous — status flips from pendingsentdeliveredread as Meta returns callbacks.

    Terminal window
    curl -sS \
    "https://api.kirim.chat/v1/$PHONE_ID/messages/msg_01HXYZABCDEFGHJKMNPQRSTVWX" \
    -H "Authorization: Bearer $KIRIM_KEY"
    {
    "data": {
    "id": "msg_01HXYZABCDEFGHJKMNPQRSTVWX",
    "object": "message",
    "status": "delivered",
    "to": "+628111111111",
    "type": "text",
    "created_at": ""
    },
    "request_id": ""
    }

    Polling is fine for a quickstart but wasteful at scale. Set up a webhook (next section) to receive message.status callbacks instead.

TypeScript SDK

@kirimdev/sdk wraps every endpoint with auto-retry, idempotency, async pagination, and typed errors. Read →

Subscribe to webhooks

Stop polling, start receiving events as they happen. Read →

Authentication deep dive

Key rotation, expiration, security guidance. Read →

Handle failed sends

Structured error envelope and stable error codes you can branch on. Read →

API Reference

Every endpoint, every parameter, every error code. Browse →

Recipes

End-to-end patterns for common workflows. Browse →