Ana içeriğe geç

iletiMerkezi Webhooks

Webhooks deliver real-time status updates for the messages you sent via send-sms. You configure a URL in the panel; iletiMerkezi POSTs to that URL on every status change (acceptance, delivery, failure). Webhooks are more efficient and lower-latency than polling get-report.

Setup

  1. Open panel.iletimerkezi.comSettings → API → Notification URL (Turkish: "Bildirim Adresi").
  2. Enter your webhook URL (e.g., https://yourdomain.com/api/iletimerkezi/webhook) and click Add to save.
  3. The URL must be HTTPS and reachable from the public internet. iletiMerkezi servers will POST to it.

Only one webhook URL per account is supported. If you need to dispatch the same report to multiple destinations, fan out from your webhook handler.

Once the URL is set, every send-sms order's delivery reports flow into it automatically — no extra API call needed.

Request

For each message status update, iletiMerkezi POSTs to your URL with:

POST https://yourdomain.com/api/iletimerkezi/webhook
Content-Type: application/json
{
  "report": {
    "id": 1599558518,
    "packet_id": 104525848,
    "status": "accepted",
    "to": "+905XXXXXXXXX",
    "body": "Message text"
  }
}

Fields

  • report.id (integer): unique ID of a single message inside an order.
  • report.packet_id (integer): the order ID this message belongs to. Matches order.id returned by send-sms; all webhook events from one order share this packet_id.
  • report.status (string): message status (see table below).
  • report.to (string): recipient number with +90 prefix.
  • report.body (string): the message text that was sent.

Status values (report.status)

| Value | Meaning | |---|---| | accepted | Message was accepted and queued for delivery | | delivered | Message was successfully delivered to the recipient | | undelivered | Message could not be delivered (off network, blacklist, format, etc.) |

get-report returns numeric codes (110, 111, 112); webhooks send string values (accepted, delivered, undelivered). For one message you typically receive accepted first, then either delivered or undelivered.

Response

Your endpoint should reply with 2xx (e.g., 200 OK). A non-2xx response can cause iletiMerkezi to flag the webhook as failed; respond with 200 quickly and process work asynchronously.

HTTP/1.1 200 OK
Content-Type: application/json

{"received": true}

Security

iletiMerkezi webhooks currently do not send an HMAC signature or X-Signature-style header; the payload is the raw report object. You must enforce at least one verification layer on the receiver side in production.

Recommended pattern: secret token in the URL. Configure the webhook URL in the panel with a token query parameter; your handler compares that token against a stored value and rejects mismatches with 401. This is the same pattern our internal services use to consume iletiMerkezi DLRs.

POST https://yourdomain.com/api/iletimerkezi/webhook?token=SECRET_VALUE
// Handler example (Node/Express)
app.post('/api/iletimerkezi/webhook', (req, res) => {
  if (req.query.token !== process.env.WEBHOOK_TOKEN) {
    return res.status(401).end();
  }
  // ... process payload
  res.status(200).json({ received: true });
});

Extra defenses:

  • Treat the webhook URL like a secret — keep it in env vars, do not commit it.
  • HTTPS is enforced by the panel; HTTP URLs are rejected.
  • Match incoming report.packet_id against an order ID you wrote to your own DB. Silently drop reports you can't match (see "Multi-app filtering" below).

Native HMAC signing is a roadmap candidate; it does not exist today. The URL-token convention is the real protection layer right now.

Common pitfalls

  • All SMS on the account land on a single webhook URL (multi-app filtering). If the same iletiMerkezi account is shared by multiple apps, you will receive DLRs that do not belong to your app. On the receiver side, look for an app-specific marker inside report.body (e.g., your short-link domain iim.to/..., a campaign tag, an order-ID prefix) and silently 200 OK anything that doesn't match. Otherwise you will write orphan DLRs into your DB and treat them as your own.

    // Practical example: short-link domain as the marker
    if (!report.body.includes('iim.to')) {
      return new Response('OK', { status: 200 });  // not ours, drop silently
    }
  • The same report.id can arrive more than once; write idempotently. Carrier or iletiMerkezi-side retries can repeat a status update. Practical pattern: on the first callback, write delivery_received_at + status; on subsequent callbacks, only refresh the status (don't touch the timestamp). Idempotency key: report.id + report.status.

  • packet_id equals the send-sms order.id. Use it to correlate webhooks with the originating order; multiple message webhooks from the same order share this packet_id.

  • accepted is not "delivered". It means "accepted, queued". Wait for delivered for actual delivery; an undelivered webhook is the failure terminus.

  • Respond fast. Push DB writes and downstream API calls onto a background queue, then return 200 from the webhook handler immediately. A slow handler triggers retries.

  • HTTPS only. HTTP URLs are not accepted by the panel. Use ngrok or a cloudflared tunnel for local development.

  • No webhook = polling. If the webhook URL is empty, you can only learn the delivery state via get-report. Webhooks are recommended in production; you can keep polling as a fallback.

Related

Last updated: 2026-04-29 · Türkçe