MENU navbar-image

Introduction

REST API v1 for the Bitaqa NFC business-card platform: provision cards, sync HR employees, read analytics and manage touchpoints and webhooks.

All endpoints live under `/api/v1` and are tenant-scoped to the organization that owns the API token
(super admin tokens select an organization with the `X-Organization: {org-slug}` header).

Each token carries a set of abilities; endpoints reject tokens missing the required ability with a
`403` response. Available abilities: `cards:read`, `cards:write`, `analytics:read`, `employees:write`,
`touchpoints:read`, `touchpoints:write`, `webhooks:manage`.

<aside>As you scroll, you'll see code examples for working with the API in different programming languages in the dark area to the right (or as part of the content on mobile).
You can switch the language used with the tabs at the top right (or from the nav menu at the top left on mobile).</aside>

Authenticating requests

To authenticate requests, include an Authorization header with the value "Bearer {YOUR_API_TOKEN}".

All authenticated endpoints are marked with a requires authentication badge in the documentation below.

Authenticate with a Sanctum personal access token sent as a bearer token: Authorization: Bearer {token}. An organization admin can issue tokens (with the abilities listed above) from the admin panel's API tokens screen. Requests without a valid token receive a 401; tokens missing the required ability receive a 403.

Analytics

Aggregated tap/click analytics. All endpoints accept an optional from/to date range (defaults to the last 30 days, maximum span 366 days) and require the analytics:read token ability.

Card analytics

requires authentication

Summary, per-day timeseries and top link channels for one card.

Example request:
curl --request GET \
    --get "http://bitaqa.test/api/v1/cards/k7m2p9qr/analytics?from=2026-06-01&to=2026-06-30" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://bitaqa.test/api/v1/cards/k7m2p9qr/analytics"
);

const params = {
    "from": "2026-06-01",
    "to": "2026-06-30",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "from": "2026-06-01",
    "to": "2026-06-30",
    "summary": {
        "views": 58,
        "unique_visitors": 41,
        "link_clicks": 23,
        "vcard_downloads": 6,
        "shares": 2,
        "qr_scans": 4,
        "journey_submits": 0
    },
    "timeseries": [
        {
            "date": "2026-06-01",
            "views": 3,
            "link_clicks": 1,
            "vcard_downloads": 0
        }
    ],
    "channels": [
        {
            "channel": "whatsapp",
            "count": 12
        }
    ]
}
 

Request      

GET api/v1/cards/{slug}/analytics

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

slug   string     

The card slug. Example: k7m2p9qr

Query Parameters

from   string  optional    

Start date (Y-m-d). Defaults to 30 days before to. Example: 2026-06-01

to   string  optional    

End date (Y-m-d). Defaults to today. Example: 2026-06-30

Organization summary

requires authentication

Org-wide totals, top link channels and a per-branch breakdown.

Example request:
curl --request GET \
    --get "http://bitaqa.test/api/v1/analytics/summary?from=2026-06-01&to=2026-06-30" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://bitaqa.test/api/v1/analytics/summary"
);

const params = {
    "from": "2026-06-01",
    "to": "2026-06-30",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "from": "2026-06-01",
    "to": "2026-06-30",
    "summary": {
        "views": 412,
        "unique_visitors": 267,
        "link_clicks": 158,
        "vcard_downloads": 41,
        "shares": 12,
        "qr_scans": 33,
        "journey_submits": 9
    },
    "channels": [
        {
            "channel": "whatsapp",
            "count": 74
        }
    ],
    "by_branch": [
        {
            "branch_id": 1,
            "name_en": "Ruwi",
            "name_ar": "روي",
            "views": 210,
            "link_clicks": 80,
            "vcard_downloads": 22
        }
    ]
}
 

Request      

GET api/v1/analytics/summary

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

from   string  optional    

Start date (Y-m-d). Defaults to 30 days before to. Example: 2026-06-01

to   string  optional    

End date (Y-m-d). Defaults to today. Example: 2026-06-30

Branches

List branches

requires authentication

Branch directory with coordinates, opening hours and services. Requires the cards:read token ability.

Example request:
curl --request GET \
    --get "http://bitaqa.test/api/v1/branches?search=ruwi&per_page=15" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"search\": \"b\"
}"
const url = new URL(
    "http://bitaqa.test/api/v1/branches"
);

const params = {
    "search": "ruwi",
    "per_page": "15",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "search": "b"
};

fetch(url, {
    method: "GET",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request      

GET api/v1/branches

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

search   string  optional    

Match against name or code. Example: ruwi

per_page   integer  optional    

Results per page (max 100). Example: 15

Body Parameters

search   string  optional    

Must not be greater than 255 characters. Example: b

Cards

Provision and manage the organization's digital business cards. Card endpoints are tenant-scoped: slugs belonging to another organization always return 404.

List cards

requires authentication

Requires the cards:read token ability.

Example request:
curl --request GET \
    --get "http://bitaqa.test/api/v1/cards?status=active&branch_id=1&department_id=1&search=sara&per_page=15&page=1" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"status\": \"architecto\",
    \"branch_id\": 16,
    \"department_id\": 16,
    \"search\": \"n\"
}"
const url = new URL(
    "http://bitaqa.test/api/v1/cards"
);

const params = {
    "status": "active",
    "branch_id": "1",
    "department_id": "1",
    "search": "sara",
    "per_page": "15",
    "page": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "status": "architecto",
    "branch_id": 16,
    "department_id": 16,
    "search": "n"
};

fetch(url, {
    method: "GET",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request      

GET api/v1/cards

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

status   string  optional    

Filter by status: draft, pending, active, inactive or rejected. Example: active

branch_id   integer  optional    

Filter by branch. Example: 1

department_id   integer  optional    

Filter by department. Example: 1

search   string  optional    

Match against display name, email or slug. Example: sara

per_page   integer  optional    

Results per page (max 100). Example: 15

page   integer  optional    

Page number. Example: 1

Body Parameters

status   string  optional    

Example: architecto

branch_id   integer  optional    

Example: 16

department_id   integer  optional    

Example: 16

search   string  optional    

Must not be greater than 255 characters. Example: n

Provision a card

requires authentication

Creates a card for the given employee email — reusing the matching organization user, or provisioning a new user (random password, local source) when none exists. Requires the cards:write ability.

Example request:
curl --request POST \
    "http://bitaqa.test/api/v1/cards" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"email\": \"sara@alameen.test\",
    \"display_name_en\": \"Sara Al Busaidi\",
    \"display_name_ar\": \"سارة البوسعيدية\",
    \"title_en\": \"Relationship Manager\",
    \"title_ar\": \"مدير علاقات العملاء\",
    \"phone\": \"+96891234567\",
    \"whatsapp\": \"+96891234567\",
    \"website\": \"https:\\/\\/alameen.test\",
    \"branch_id\": 1,
    \"department_id\": 1,
    \"template_key\": \"classic\",
    \"status\": \"pending\",
    \"links\": [
        {
            \"type\": \"custom\",
            \"label_en\": \"b\",
            \"label_ar\": \"n\",
            \"value\": \"g\"
        }
    ]
}"
const url = new URL(
    "http://bitaqa.test/api/v1/cards"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "email": "sara@alameen.test",
    "display_name_en": "Sara Al Busaidi",
    "display_name_ar": "سارة البوسعيدية",
    "title_en": "Relationship Manager",
    "title_ar": "مدير علاقات العملاء",
    "phone": "+96891234567",
    "whatsapp": "+96891234567",
    "website": "https:\/\/alameen.test",
    "branch_id": 1,
    "department_id": 1,
    "template_key": "classic",
    "status": "pending",
    "links": [
        {
            "type": "custom",
            "label_en": "b",
            "label_ar": "n",
            "value": "g"
        }
    ]
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (201):


{
    "data": {
        "slug": "k7m2p9qr",
        "status": "pending",
        "display_name_en": "Sara Al Busaidi",
        "links": [],
        "public_url": "http://bitaqa.test/alameen/k7m2p9qr"
    }
}
 

Request      

POST api/v1/cards

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

email   string     

Employee email. Reuses the matching organization user or provisions a new one. Must be a valid email address. Must not be greater than 255 characters. Example: sara@alameen.test

display_name_en   string     

Display name (English). Must not be greater than 255 characters. Example: Sara Al Busaidi

display_name_ar   string  optional    

Display name (Arabic). Must not be greater than 255 characters. Example: سارة البوسعيدية

title_en   string  optional    

Job title (English). Must not be greater than 255 characters. Example: Relationship Manager

title_ar   string  optional    

Job title (Arabic). Must not be greater than 255 characters. Example: مدير علاقات العملاء

phone   string  optional    

Must not be greater than 50 characters. Example: +96891234567

whatsapp   string  optional    

Must not be greater than 50 characters. Example: +96891234567

website   string  optional    

Must be a valid URL. Must not be greater than 255 characters. Example: https://alameen.test

branch_id   integer  optional    

Branch id within the organization. Must match an existing stored value. Example: 1

department_id   integer  optional    

Department id within the organization. Must match an existing stored value. Example: 1

template_key   string  optional    

Card template key (classic, modern, minimal, corporate, banking). Must match an existing stored value. Example: classic

links   object[]  optional    

Card links, ordered as given. Must not have more than 30 items.

type   string     

Example: custom

Must be one of:
  • phone
  • whatsapp
  • email
  • website
  • location
  • linkedin
  • x
  • instagram
  • facebook
  • telegram
  • snapchat
  • tiktok
  • youtube
  • custom
label_en   string  optional    

Must not be greater than 255 characters. Example: b

label_ar   string  optional    

Must not be greater than 255 characters. Example: n

value   string     

Must not be greater than 2048 characters. Example: g

status   string  optional    

Initial status: pending (awaits approval, default) or active (published immediately). Example: pending

Must be one of:
  • pending
  • active

Get a card

requires authentication

Requires the cards:read token ability.

Example request:
curl --request GET \
    --get "http://bitaqa.test/api/v1/cards/k7m2p9qr" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://bitaqa.test/api/v1/cards/k7m2p9qr"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request      

GET api/v1/cards/{slug}

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

slug   string     

The card slug. Example: k7m2p9qr

Update a card

requires authentication

Partial update. When links is present the existing links are replaced with the given set. Requires the cards:write ability.

Example request:
curl --request PATCH \
    "http://bitaqa.test/api/v1/cards/k7m2p9qr" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"display_name_en\": \"Sara Al Busaidi\",
    \"display_name_ar\": \"b\",
    \"title_en\": \"n\",
    \"title_ar\": \"g\",
    \"bio_en\": \"z\",
    \"bio_ar\": \"m\",
    \"email\": \"gulgowski.asia@example.com\",
    \"phone\": \"j\",
    \"whatsapp\": \"n\",
    \"website\": \"i\",
    \"branch_id\": 16,
    \"department_id\": 16,
    \"template_key\": \"modern\",
    \"links\": [
        {
            \"type\": \"linkedin\",
            \"label_en\": \"n\",
            \"label_ar\": \"g\",
            \"value\": \"z\"
        }
    ]
}"
const url = new URL(
    "http://bitaqa.test/api/v1/cards/k7m2p9qr"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "display_name_en": "Sara Al Busaidi",
    "display_name_ar": "b",
    "title_en": "n",
    "title_ar": "g",
    "bio_en": "z",
    "bio_ar": "m",
    "email": "gulgowski.asia@example.com",
    "phone": "j",
    "whatsapp": "n",
    "website": "i",
    "branch_id": 16,
    "department_id": 16,
    "template_key": "modern",
    "links": [
        {
            "type": "linkedin",
            "label_en": "n",
            "label_ar": "g",
            "value": "z"
        }
    ]
};

fetch(url, {
    method: "PATCH",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request      

PATCH api/v1/cards/{slug}

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

slug   string     

The card slug. Example: k7m2p9qr

Body Parameters

display_name_en   string  optional    

Must not be greater than 255 characters. Example: Sara Al Busaidi

display_name_ar   string  optional    

Must not be greater than 255 characters. Example: b

title_en   string  optional    

Must not be greater than 255 characters. Example: n

title_ar   string  optional    

Must not be greater than 255 characters. Example: g

bio_en   string  optional    

Must not be greater than 2000 characters. Example: z

bio_ar   string  optional    

Must not be greater than 2000 characters. Example: m

email   string  optional    

Must be a valid email address. Must not be greater than 255 characters. Example: gulgowski.asia@example.com

phone   string  optional    

Must not be greater than 50 characters. Example: j

whatsapp   string  optional    

Must not be greater than 50 characters. Example: n

website   string  optional    

Must be a valid URL. Must not be greater than 255 characters. Example: i

branch_id   integer  optional    

Must match an existing stored value. Example: 16

department_id   integer  optional    

Must match an existing stored value. Example: 16

template_key   string  optional    

Must match an existing stored value. Example: modern

links   object[]  optional    

When present, replaces ALL existing links with the given set. Must not have more than 30 items.

type   string     

Example: linkedin

Must be one of:
  • phone
  • whatsapp
  • email
  • website
  • location
  • linkedin
  • x
  • instagram
  • facebook
  • telegram
  • snapchat
  • tiktok
  • youtube
  • custom
label_en   string  optional    

Must not be greater than 255 characters. Example: n

label_ar   string  optional    

Must not be greater than 255 characters. Example: g

value   string     

Must not be greater than 2048 characters. Example: z

Deactivate a card

requires authentication

Instant status flip (no approval step) — the public page stops serving on the very next tap. Requires the cards:write ability.

Example request:
curl --request POST \
    "http://bitaqa.test/api/v1/cards/k7m2p9qr/deactivate" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://bitaqa.test/api/v1/cards/k7m2p9qr/deactivate"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Request      

POST api/v1/cards/{slug}/deactivate

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

slug   string     

The card slug. Example: k7m2p9qr

Activate a card

requires authentication

Instant status flip to active. Requires the cards:write ability.

Example request:
curl --request POST \
    "http://bitaqa.test/api/v1/cards/k7m2p9qr/activate" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://bitaqa.test/api/v1/cards/k7m2p9qr/activate"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Request      

POST api/v1/cards/{slug}/activate

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

slug   string     

The card slug. Example: k7m2p9qr

Employees

Push HR directory changes into Bitaqa.

Sync employees

requires authentication

Batch upsert (max 500 rows) matched by employee_ref, falling back to email. New employees are created with an auto-provisioned PENDING card. Rows with active: false deactivate the user and flip their cards to inactive immediately; re-activated users keep their cards inactive until re-approved. Requires the employees:write token ability.

Example request:
curl --request POST \
    "http://bitaqa.test/api/v1/employees/sync" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
const url = new URL(
    "http://bitaqa.test/api/v1/employees/sync"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Example response (200):


{
    "created": 2,
    "updated": 1,
    "deactivated": 1,
    "reactivated": 0,
    "failures": [
        {
            "index": 4,
            "errors": {
                "email": [
                    "The email field is required."
                ]
            }
        }
    ],
    "note": "Re-activated employees keep their cards inactive until re-approved."
}
 

Request      

POST api/v1/employees/sync

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

employees   object[]  optional    

Touchpoints

Physical NFC/QR touchpoints (branch counters, marketing material) that open a journey when tapped.

List touchpoints

requires authentication

Requires the touchpoints:read token ability.

Example request:
curl --request GET \
    --get "http://bitaqa.test/api/v1/touchpoints?type=branch_counter&journey=feedback&branch_id=1&search=lobby&per_page=15" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"type\": \"architecto\",
    \"journey\": \"architecto\",
    \"branch_id\": 16,
    \"search\": \"n\"
}"
const url = new URL(
    "http://bitaqa.test/api/v1/touchpoints"
);

const params = {
    "type": "branch_counter",
    "journey": "feedback",
    "branch_id": "1",
    "search": "lobby",
    "per_page": "15",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "type": "architecto",
    "journey": "architecto",
    "branch_id": 16,
    "search": "n"
};

fetch(url, {
    method: "GET",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request      

GET api/v1/touchpoints

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

type   string  optional    

Filter by type: staff_card, branch_counter or marketing_material. Example: branch_counter

journey   string  optional    

Filter by journey: card, inquiry, service_request, feedback, booking or locator. Example: feedback

branch_id   integer  optional    

Filter by branch. Example: 1

search   string  optional    

Match against the internal name. Example: lobby

per_page   integer  optional    

Results per page (max 100). Example: 15

Body Parameters

type   string  optional    

Example: architecto

journey   string  optional    

Example: architecto

branch_id   integer  optional    

Example: 16

search   string  optional    

Must not be greater than 255 characters. Example: n

Create a touchpoint

requires authentication

The public slug is generated server-side. Requires the touchpoints:write token ability.

Example request:
curl --request POST \
    "http://bitaqa.test/api/v1/touchpoints" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"type\": \"branch_counter\",
    \"journey\": \"feedback\",
    \"name\": \"Qurum branch counter\",
    \"branch_id\": 1,
    \"is_active\": true
}"
const url = new URL(
    "http://bitaqa.test/api/v1/touchpoints"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "type": "branch_counter",
    "journey": "feedback",
    "name": "Qurum branch counter",
    "branch_id": 1,
    "is_active": true
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (201):


{
    "data": {
        "slug": "w3n8k2mq",
        "type": "branch_counter",
        "journey": "feedback",
        "name": "Qurum branch counter",
        "branch_id": 1,
        "is_active": true,
        "public_url": "http://bitaqa.test/alameen/w3n8k2mq"
    }
}
 

Request      

POST api/v1/touchpoints

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

type   string     

Touchpoint type: staff_card, branch_counter or marketing_material. Example: branch_counter

Must be one of:
  • staff_card
  • branch_counter
  • marketing_material
journey   string     

Journey the touchpoint opens: card, inquiry, service_request, feedback, booking or locator. Example: feedback

Must be one of:
  • card
  • inquiry
  • service_request
  • feedback
  • booking
  • locator
name   string     

Internal label. Must not be greater than 255 characters. Example: Qurum branch counter

branch_id   integer  optional    

Must match an existing stored value. Example: 1

is_active   boolean  optional    

Example: true

Update a touchpoint

requires authentication

Requires the touchpoints:write token ability.

Example request:
curl --request PATCH \
    "http://bitaqa.test/api/v1/touchpoints/w3n8k2mq" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"type\": \"branch_counter\",
    \"journey\": \"feedback\",
    \"name\": \"Lobby stand — renamed\",
    \"branch_id\": 16,
    \"is_active\": false
}"
const url = new URL(
    "http://bitaqa.test/api/v1/touchpoints/w3n8k2mq"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "type": "branch_counter",
    "journey": "feedback",
    "name": "Lobby stand — renamed",
    "branch_id": 16,
    "is_active": false
};

fetch(url, {
    method: "PATCH",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request      

PATCH api/v1/touchpoints/{slug}

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

slug   string     

The touchpoint slug. Example: w3n8k2mq

Body Parameters

type   string  optional    

Example: branch_counter

Must be one of:
  • staff_card
  • branch_counter
  • marketing_material
journey   string  optional    

Example: feedback

Must be one of:
  • card
  • inquiry
  • service_request
  • feedback
  • booking
  • locator
name   string  optional    

Must not be greater than 255 characters. Example: Lobby stand — renamed

branch_id   integer  optional    

Must match an existing stored value. Example: 16

is_active   boolean  optional    

Example: false

Delete a touchpoint

requires authentication

Requires the touchpoints:write token ability.

Example request:
curl --request DELETE \
    "http://bitaqa.test/api/v1/touchpoints/w3n8k2mq" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://bitaqa.test/api/v1/touchpoints/w3n8k2mq"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (204):

Empty response
 

Request      

DELETE api/v1/touchpoints/{slug}

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

slug   string     

The touchpoint slug. Example: w3n8k2mq

Webhooks

Webhook endpoints receiving signed event deliveries (X-Bitaqa-Signature: t=<ts>,v1=hmac_sha256(secret, ts.'.'.body)). All endpoints require the webhooks:manage token ability.

List webhook endpoints

requires authentication

Secrets are masked — they are only revealed once, on creation.

Example request:
curl --request GET \
    --get "http://bitaqa.test/api/v1/webhooks" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://bitaqa.test/api/v1/webhooks"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request      

GET api/v1/webhooks

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Create a webhook endpoint

requires authentication

The signing secret (provided or generated) is returned ONCE in this response as secret — store it now; it is stored encrypted and never shown again.

Example request:
curl --request POST \
    "http://bitaqa.test/api/v1/webhooks" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"url\": \"https:\\/\\/example.com\\/hooks\\/bitaqa\",
    \"events\": [
        \"appointment.created\"
    ],
    \"secret\": \"b\"
}"
const url = new URL(
    "http://bitaqa.test/api/v1/webhooks"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "url": "https:\/\/example.com\/hooks\/bitaqa",
    "events": [
        "appointment.created"
    ],
    "secret": "b"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (201):


{
    "data": {
        "id": 7,
        "url": "https://example.com/hooks/bitaqa",
        "events": [
            "card.created"
        ],
        "secret": "********a1b2",
        "is_active": true
    },
    "secret": "whsec_9fK2..."
}
 

Request      

POST api/v1/webhooks

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

url   string     

HTTPS endpoint that receives signed deliveries. Must be a valid URL. Must not be greater than 2048 characters. Example: https://example.com/hooks/bitaqa

events   string[]  optional    
Must be one of:
  • card.tapped
  • card.saved
  • card.created
  • card.deactivated
  • inquiry.created
  • request.created
  • feedback.created
  • appointment.created
secret   string  optional    

Optional signing secret (16–128 chars). Generated when omitted and returned ONCE in the creation response. Must be at least 16 characters. Must not be greater than 128 characters. Example: b

Delete a webhook endpoint

requires authentication

Example request:
curl --request DELETE \
    "http://bitaqa.test/api/v1/webhooks/7" \
    --header "Authorization: Bearer {YOUR_API_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://bitaqa.test/api/v1/webhooks/7"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (204):

Empty response
 

Request      

DELETE api/v1/webhooks/{id}

Headers

Authorization        

Example: Bearer {YOUR_API_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   integer     

The webhook endpoint id. Example: 7