Developers
Contents
On this page

Using the API

Idempotency

A retried request must not add a second visit.

Networks fail in the worst place: after we added the visit and before you heard back. Retry blindly and the person is in the line twice. Send an Idempotency-Key and a retry is answered with the visit the first request made.

The Idempotency-Key header#

POST /v1/visits honours it. Every other write is safe to repeat by its nature — a second completed is a 409, never a second completion — except Call next, which is not; see Handling errors.

  • Any string of 1 to 255 characters that is unique per visit you mean to add: a UUID, or your own record's id such as crm-visit-1042.
  • Make it once, before the first try, and send the same one on every retry.
  • Keys belong to the business, not to the API key, so a retry still works after rotating keys.
POST /v1/visits with an Idempotency-Key

curl

curl -X POST "https://business.linemeup.in/api/v1/visits" \
  -H "Authorization: Bearer $LINEMEUP_API_KEY" \
  -H "Idempotency-Key: crm-visit-1042" \
  -H "Content-Type: application/json" \
  -d '{"lineId":"line-0193f2a1-7c4e-7a10-9b2e-000000000001","customer":{"name":"Asha Rao","phone":"+919000000001"},"note":"First visit","reference":"CRM-1042","consent":true}'

Node

const res = await fetch("https://business.linemeup.in/api/v1/visits", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.LINEMEUP_API_KEY}`,
    "Idempotency-Key": "crm-visit-1042",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "lineId": "line-0193f2a1-7c4e-7a10-9b2e-000000000001",
    "customer": {
      "name": "Asha Rao",
      "phone": "+919000000001"
    },
    "note": "First visit",
    "reference": "CRM-1042",
    "consent": true
  }),
});
if (!res.ok) throw new Error(`Line Me Up answered ${res.status}`);
const answer = await res.json();

Python

import os
import requests

res = requests.post(
    "https://business.linemeup.in/api/v1/visits",
    headers={
        "Authorization": f"Bearer {os.environ['LINEMEUP_API_KEY']}",
        "Idempotency-Key": "crm-visit-1042",
    },
    json={
        "lineId": "line-0193f2a1-7c4e-7a10-9b2e-000000000001",
        "customer": {
            "name": "Asha Rao",
            "phone": "+919000000001",
        },
        "note": "First visit",
        "reference": "CRM-1042",
        "consent": True,
    },
    timeout=10,
)
res.raise_for_status()
answer = res.json()

PHP

<?php
$ch = curl_init("https://business.linemeup.in/api/v1/visits");
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("LINEMEUP_API_KEY"),
        "Idempotency-Key: crm-visit-1042",
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "lineId" => 'line-0193f2a1-7c4e-7a10-9b2e-000000000001',
        "customer" => [
            "name" => 'Asha Rao',
            "phone" => '+919000000001',
        ],
        "note" => 'First visit',
        "reference" => 'CRM-1042',
        "consent" => true,
    ]),
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 10,
]);
$answer = json_decode(curl_exec($ch), true);

What happens when a key is sent again:

Sending the same Idempotency-Key
WhenThe answer
The first request succeeded; same body The first answer again, word for word, with Idempotent-Replayed: true. No new visit.
The first request is still running 409 CONFLICT. Wait a second and retry with the same key. (In the rare case the visit was added but its answer could not be kept, the key goes on answering 409 until it is forgotten, rather than add a second visit. Look for it with GET /v1/visits.)
The first request was refused or failed Nothing is remembered: the retry is a fresh attempt.
The same key with a different body 422 VALIDATION_FAILED, and nothing is added. Use a new key for a new visit.

"The same body" means the same fields with the same values — the order you write them in does not matter.

A replayed answer
HTTP/1.1 200 OK
Idempotent-Replayed: true
Content-Type: application/json; charset=utf-8
…and its body, the first request's
{
  "data": [
    {
      "id": "job-0193f2a1-7c4e-7a10-9b2e-000000000001",
      "journeyId": "jny-0193f2a1-7c4e-7a10-9b2e-000000000001",
      "token": "GEN-20261030-014",
      "lineId": "line-0193f2a1-7c4e-7a10-9b2e-000000000001",
      "status": "queued",
      "bookingType": "walk_in",
      "priority": false,
      "note": "First visit",
      "customer": {
        "name": "Asha Rao",
        "phone": "+919000000001"
      },
      "services": [
        {
          "id": "svc-0193f2a1-7c4e-7a10-9b2e-000000000002",
          "name": "General consultation"
        }
      ],
      "deskId": null,
      "position": 3,
      "slotAt": null,
      "createdAt": "2026-10-30T04:12:00.000Z",
      "calledAt": null,
      "startedAt": null,
      "endedAt": null,
      "updatedAt": "2026-10-30T04:12:00.000Z"
    }
  ]
}
The same key, another body (422)
{
  "error": {
    "code": "VALIDATION_FAILED",
    "message": "This Idempotency-Key was sent before with a different request. Use a new key for a new request",
    "details": {
      "idempotencyKey": "reused"
    }
  }
}
The first request still running (409)
{
  "error": {
    "code": "CONFLICT",
    "message": "A request with this Idempotency-Key is still being processed. Retry it shortly"
  }
}

Retry-safe examples#

Retry on a timeout, a dropped connection, a 409, a 429 or a 5xx — with the same key, and a growing wait. Anything else is an answer.

Adding a visit, safely

Node

import { randomUUID } from "node:crypto";

// One key per visit you mean to add — made once, reused on every retry.
async function addVisit(visit, key = randomUUID()) {
  for (let attempt = 1; attempt <= 5; attempt++) {
    try {
      const res = await fetch("https://business.linemeup.in/api/v1/visits", {
        method: "POST",
        headers: {
          Authorization: `Bearer ${process.env.LINEMEUP_API_KEY}`,
          "Content-Type": "application/json",
          "Idempotency-Key": key,
        },
        body: JSON.stringify(visit),
        signal: AbortSignal.timeout(10_000),
      });
      // 409: the first try is still running. 429 and 5xx: try again shortly.
      if (res.status !== 409 && res.status !== 429 && res.status < 500) {
        const answer = await res.json();
        if (!res.ok) throw new Error(answer.error.message);
        return answer.data;
      }
    } catch (error) {
      if (error.name !== "TimeoutError" && error.name !== "TypeError") throw error;
    }
    await new Promise((resolve) => setTimeout(resolve, 2 ** attempt * 500));
  }
  throw new Error("Line Me Up did not answer; the same key is safe to try later");
}

Python

import os
import time
import uuid

import requests

def add_visit(visit, key=None):
    key = key or str(uuid.uuid4())  # one key per visit, reused on every retry
    for attempt in range(1, 6):
        try:
            res = requests.post(
                "https://business.linemeup.in/api/v1/visits",
                headers={
                    "Authorization": f"Bearer {os.environ['LINEMEUP_API_KEY']}",
                    "Idempotency-Key": key,
                },
                json=visit,
                timeout=10,
            )
            if res.status_code not in (409, 429) and res.status_code < 500:
                res.raise_for_status()
                return res.json()["data"]
        except (requests.Timeout, requests.ConnectionError):
            pass
        time.sleep(2 ** attempt * 0.5)
    raise RuntimeError("Line Me Up did not answer; the same key is safe to try later")

PHP

<?php
function add_visit(array $visit, ?string $key = null): array
{
    $key = $key ?? bin2hex(random_bytes(16)); // one key per visit, reused on every retry
    for ($attempt = 1; $attempt <= 5; $attempt++) {
        $ch = curl_init('https://business.linemeup.in/api/v1/visits');
        curl_setopt_array($ch, [
            CURLOPT_CUSTOMREQUEST => 'POST',
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . getenv('LINEMEUP_API_KEY'),
                'Content-Type: application/json',
                'Idempotency-Key: ' . $key,
            ],
            CURLOPT_POSTFIELDS => json_encode($visit),
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT => 10,
        ]);
        $body = curl_exec($ch);
        $status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
        if ($body !== false && $status !== 409 && $status !== 429 && $status < 500) {
            $answer = json_decode($body, true);
            if ($status !== 200) {
                throw new RuntimeException($answer['error']['message']);
            }
            return $answer['data'];
        }
        usleep((2 ** $attempt) * 500000);
    }
    throw new RuntimeException('Line Me Up did not answer; the same key is safe to try later');
}

How long a key is remembered#

24 hours from the first request. After that the key is forgotten, and sending it again adds a new visit — so a retry belongs within the day, and a key should never be reused on purpose. If you take your keys from your own records, prefix them with the date or the system (web-2026-…) so two systems cannot collide.