openapi: 3.0.3
info:
  title: 'Bitaqa API'
  description: 'REST API v1 for the Bitaqa NFC business-card platform: provision cards, sync HR employees, read analytics and manage touchpoints and webhooks.'
  version: 1.0.0
servers:
  -
    url: 'http://bitaqa.test'
tags:
  -
    name: Analytics
    description: "\nAggregated tap/click analytics. All endpoints accept an optional\n`from`/`to` date range (defaults to the last 30 days, maximum span\n366 days) and require the `analytics:read` token ability."
  -
    name: Branches
    description: ''
  -
    name: Cards
    description: "\nProvision and manage the organization's digital business cards. Card\nendpoints are tenant-scoped: slugs belonging to another organization\nalways return 404."
  -
    name: Employees
    description: "\nPush HR directory changes into Bitaqa."
  -
    name: Touchpoints
    description: "\nPhysical NFC/QR touchpoints (branch counters, marketing material)\nthat open a journey when tapped."
  -
    name: Webhooks
    description: "\nWebhook endpoints receiving signed event deliveries\n(`X-Bitaqa-Signature: t=<ts>,v1=hmac_sha256(secret, ts.'.'.body)`).\nAll endpoints require the `webhooks:manage` token ability."
components:
  securitySchemes:
    default:
      type: http
      scheme: bearer
      description: "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`."
security:
  -
    default: []
paths:
  '/api/v1/cards/{slug}/analytics':
    get:
      summary: 'Card analytics'
      operationId: cardAnalytics
      description: 'Summary, per-day timeseries and top link channels for one card.'
      parameters:
        -
          in: query
          name: from
          description: 'Start date (Y-m-d). Defaults to 30 days before `to`.'
          example: '2026-06-01'
          required: false
          schema:
            type: string
            description: 'Start date (Y-m-d). Defaults to 30 days before `to`.'
            example: '2026-06-01'
        -
          in: query
          name: to
          description: 'End date (Y-m-d). Defaults to today.'
          example: '2026-06-30'
          required: false
          schema:
            type: string
            description: 'End date (Y-m-d). Defaults to today.'
            example: '2026-06-30'
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  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
                properties:
                  from:
                    type: string
                    example: '2026-06-01'
                  to:
                    type: string
                    example: '2026-06-30'
                  summary:
                    type: object
                    properties:
                      views:
                        type: integer
                        example: 58
                      unique_visitors:
                        type: integer
                        example: 41
                      link_clicks:
                        type: integer
                        example: 23
                      vcard_downloads:
                        type: integer
                        example: 6
                      shares:
                        type: integer
                        example: 2
                      qr_scans:
                        type: integer
                        example: 4
                      journey_submits:
                        type: integer
                        example: 0
                  timeseries:
                    type: array
                    example:
                      -
                        date: '2026-06-01'
                        views: 3
                        link_clicks: 1
                        vcard_downloads: 0
                    items:
                      type: object
                      properties:
                        date:
                          type: string
                          example: '2026-06-01'
                        views:
                          type: integer
                          example: 3
                        link_clicks:
                          type: integer
                          example: 1
                        vcard_downloads:
                          type: integer
                          example: 0
                  channels:
                    type: array
                    example:
                      -
                        channel: whatsapp
                        count: 12
                    items:
                      type: object
                      properties:
                        channel:
                          type: string
                          example: whatsapp
                        count:
                          type: integer
                          example: 12
      tags:
        - Analytics
    parameters:
      -
        in: path
        name: slug
        description: 'The card slug.'
        example: k7m2p9qr
        required: true
        schema:
          type: string
  /api/v1/analytics/summary:
    get:
      summary: 'Organization summary'
      operationId: organizationSummary
      description: 'Org-wide totals, top link channels and a per-branch breakdown.'
      parameters:
        -
          in: query
          name: from
          description: 'Start date (Y-m-d). Defaults to 30 days before `to`.'
          example: '2026-06-01'
          required: false
          schema:
            type: string
            description: 'Start date (Y-m-d). Defaults to 30 days before `to`.'
            example: '2026-06-01'
        -
          in: query
          name: to
          description: 'End date (Y-m-d). Defaults to today.'
          example: '2026-06-30'
          required: false
          schema:
            type: string
            description: 'End date (Y-m-d). Defaults to today.'
            example: '2026-06-30'
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  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
                properties:
                  from:
                    type: string
                    example: '2026-06-01'
                  to:
                    type: string
                    example: '2026-06-30'
                  summary:
                    type: object
                    properties:
                      views:
                        type: integer
                        example: 412
                      unique_visitors:
                        type: integer
                        example: 267
                      link_clicks:
                        type: integer
                        example: 158
                      vcard_downloads:
                        type: integer
                        example: 41
                      shares:
                        type: integer
                        example: 12
                      qr_scans:
                        type: integer
                        example: 33
                      journey_submits:
                        type: integer
                        example: 9
                  channels:
                    type: array
                    example:
                      -
                        channel: whatsapp
                        count: 74
                    items:
                      type: object
                      properties:
                        channel:
                          type: string
                          example: whatsapp
                        count:
                          type: integer
                          example: 74
                  by_branch:
                    type: array
                    example:
                      -
                        branch_id: 1
                        name_en: Ruwi
                        name_ar: روي
                        views: 210
                        link_clicks: 80
                        vcard_downloads: 22
                    items:
                      type: object
                      properties:
                        branch_id:
                          type: integer
                          example: 1
                        name_en:
                          type: string
                          example: Ruwi
                        name_ar:
                          type: string
                          example: روي
                        views:
                          type: integer
                          example: 210
                        link_clicks:
                          type: integer
                          example: 80
                        vcard_downloads:
                          type: integer
                          example: 22
      tags:
        - Analytics
  /api/v1/branches:
    get:
      summary: 'List branches'
      operationId: listBranches
      description: "Branch directory with coordinates, opening hours and services.\nRequires the `cards:read` token ability."
      parameters:
        -
          in: query
          name: search
          description: 'Match against name or code.'
          example: ruwi
          required: false
          schema:
            type: string
            description: 'Match against name or code.'
            example: ruwi
        -
          in: query
          name: per_page
          description: 'Results per page (max 100).'
          example: 15
          required: false
          schema:
            type: integer
            description: 'Results per page (max 100).'
            example: 15
      responses: {  }
      tags:
        - Branches
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                search:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: b
                  nullable: true
  /api/v1/cards:
    get:
      summary: 'List cards'
      operationId: listCards
      description: 'Requires the `cards:read` token ability.'
      parameters:
        -
          in: query
          name: status
          description: 'Filter by status: draft, pending, active, inactive or rejected.'
          example: active
          required: false
          schema:
            type: string
            description: 'Filter by status: draft, pending, active, inactive or rejected.'
            example: active
        -
          in: query
          name: branch_id
          description: 'Filter by branch.'
          example: 1
          required: false
          schema:
            type: integer
            description: 'Filter by branch.'
            example: 1
        -
          in: query
          name: department_id
          description: 'Filter by department.'
          example: 1
          required: false
          schema:
            type: integer
            description: 'Filter by department.'
            example: 1
        -
          in: query
          name: search
          description: 'Match against display name, email or slug.'
          example: sara
          required: false
          schema:
            type: string
            description: 'Match against display name, email or slug.'
            example: sara
        -
          in: query
          name: per_page
          description: 'Results per page (max 100).'
          example: 15
          required: false
          schema:
            type: integer
            description: 'Results per page (max 100).'
            example: 15
        -
          in: query
          name: page
          description: 'Page number.'
          example: 1
          required: false
          schema:
            type: integer
            description: 'Page number.'
            example: 1
      responses: {  }
      tags:
        - Cards
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                status:
                  type: string
                  description: ''
                  example: architecto
                  nullable: true
                branch_id:
                  type: integer
                  description: ''
                  example: 16
                  nullable: true
                department_id:
                  type: integer
                  description: ''
                  example: 16
                  nullable: true
                search:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: 'n'
                  nullable: true
    post:
      summary: 'Provision a card'
      operationId: provisionACard
      description: "Creates a card for the given employee email — reusing the matching\norganization user, or provisioning a new user (random password,\nlocal source) when none exists. Requires the `cards:write` ability."
      parameters: []
      responses:
        201:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    slug: k7m2p9qr
                    status: pending
                    display_name_en: 'Sara Al Busaidi'
                    links: []
                    public_url: 'http://bitaqa.test/alameen/k7m2p9qr'
                properties:
                  data:
                    type: object
                    properties:
                      slug:
                        type: string
                        example: k7m2p9qr
                      status:
                        type: string
                        example: pending
                      display_name_en:
                        type: string
                        example: 'Sara Al Busaidi'
                      links:
                        type: array
                        example: []
                      public_url:
                        type: string
                        example: 'http://bitaqa.test/alameen/k7m2p9qr'
      tags:
        - Cards
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  description: '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:
                  type: string
                  description: 'Display name (English). Must not be greater than 255 characters.'
                  example: 'Sara Al Busaidi'
                display_name_ar:
                  type: string
                  description: 'Display name (Arabic). Must not be greater than 255 characters.'
                  example: 'سارة البوسعيدية'
                  nullable: true
                title_en:
                  type: string
                  description: 'Job title (English). Must not be greater than 255 characters.'
                  example: 'Relationship Manager'
                  nullable: true
                title_ar:
                  type: string
                  description: 'Job title (Arabic). Must not be greater than 255 characters.'
                  example: 'مدير علاقات العملاء'
                  nullable: true
                phone:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: '+96891234567'
                  nullable: true
                whatsapp:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: '+96891234567'
                  nullable: true
                website:
                  type: string
                  description: 'Must be a valid URL. Must not be greater than 255 characters.'
                  example: 'https://alameen.test'
                  nullable: true
                branch_id:
                  type: integer
                  description: 'Branch id within the organization. Must match an existing stored value.'
                  example: 1
                  nullable: true
                department_id:
                  type: integer
                  description: 'Department id within the organization. Must match an existing stored value.'
                  example: 1
                  nullable: true
                template_key:
                  type: string
                  description: 'Card template key (classic, modern, minimal, corporate, banking). Must match an existing stored value.'
                  example: classic
                  nullable: true
                links:
                  type: array
                  description: 'Card links, ordered as given. Must not have more than 30 items.'
                  example: null
                  items:
                    type: object
                    nullable: true
                    properties:
                      type:
                        type: string
                        description: ''
                        example: custom
                        enum:
                          - phone
                          - whatsapp
                          - email
                          - website
                          - location
                          - linkedin
                          - x
                          - instagram
                          - facebook
                          - telegram
                          - snapchat
                          - tiktok
                          - youtube
                          - custom
                      label_en:
                        type: string
                        description: 'Must not be greater than 255 characters.'
                        example: b
                        nullable: true
                      label_ar:
                        type: string
                        description: 'Must not be greater than 255 characters.'
                        example: 'n'
                        nullable: true
                      value:
                        type: string
                        description: 'Must not be greater than 2048 characters.'
                        example: g
                    required:
                      - type
                      - value
                status:
                  type: string
                  description: 'Initial status: `pending` (awaits approval, default) or `active` (published immediately).'
                  example: pending
                  enum:
                    - pending
                    - active
                  nullable: true
              required:
                - email
                - display_name_en
  '/api/v1/cards/{slug}':
    get:
      summary: 'Get a card'
      operationId: getACard
      description: 'Requires the `cards:read` token ability.'
      parameters: []
      responses: {  }
      tags:
        - Cards
    patch:
      summary: 'Update a card'
      operationId: updateACard
      description: "Partial update. When `links` is present the existing links are\nreplaced with the given set. Requires the `cards:write` ability."
      parameters: []
      responses: {  }
      tags:
        - Cards
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                display_name_en:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: 'Sara Al Busaidi'
                display_name_ar:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: b
                  nullable: true
                title_en:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: 'n'
                  nullable: true
                title_ar:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: g
                  nullable: true
                bio_en:
                  type: string
                  description: 'Must not be greater than 2000 characters.'
                  example: z
                  nullable: true
                bio_ar:
                  type: string
                  description: 'Must not be greater than 2000 characters.'
                  example: m
                  nullable: true
                email:
                  type: string
                  description: 'Must be a valid email address. Must not be greater than 255 characters.'
                  example: gulgowski.asia@example.com
                  nullable: true
                phone:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: j
                  nullable: true
                whatsapp:
                  type: string
                  description: 'Must not be greater than 50 characters.'
                  example: 'n'
                  nullable: true
                website:
                  type: string
                  description: 'Must be a valid URL. Must not be greater than 255 characters.'
                  example: i
                  nullable: true
                branch_id:
                  type: integer
                  description: 'Must match an existing stored value.'
                  example: 16
                  nullable: true
                department_id:
                  type: integer
                  description: 'Must match an existing stored value.'
                  example: 16
                  nullable: true
                template_key:
                  type: string
                  description: 'Must match an existing stored value.'
                  example: modern
                  nullable: true
                links:
                  type: array
                  description: 'When present, replaces ALL existing links with the given set. Must not have more than 30 items.'
                  example: null
                  items:
                    type: object
                    properties:
                      type:
                        type: string
                        description: ''
                        example: linkedin
                        enum:
                          - phone
                          - whatsapp
                          - email
                          - website
                          - location
                          - linkedin
                          - x
                          - instagram
                          - facebook
                          - telegram
                          - snapchat
                          - tiktok
                          - youtube
                          - custom
                      label_en:
                        type: string
                        description: 'Must not be greater than 255 characters.'
                        example: 'n'
                        nullable: true
                      label_ar:
                        type: string
                        description: 'Must not be greater than 255 characters.'
                        example: g
                        nullable: true
                      value:
                        type: string
                        description: 'Must not be greater than 2048 characters.'
                        example: z
                    required:
                      - type
                      - value
    parameters:
      -
        in: path
        name: slug
        description: 'The card slug.'
        example: k7m2p9qr
        required: true
        schema:
          type: string
  '/api/v1/cards/{slug}/deactivate':
    post:
      summary: 'Deactivate a card'
      operationId: deactivateACard
      description: "Instant status flip (no approval step) — the public page stops\nserving on the very next tap. Requires the `cards:write` ability."
      parameters: []
      responses: {  }
      tags:
        - Cards
    parameters:
      -
        in: path
        name: slug
        description: 'The card slug.'
        example: k7m2p9qr
        required: true
        schema:
          type: string
  '/api/v1/cards/{slug}/activate':
    post:
      summary: 'Activate a card'
      operationId: activateACard
      description: 'Instant status flip to active. Requires the `cards:write` ability.'
      parameters: []
      responses: {  }
      tags:
        - Cards
    parameters:
      -
        in: path
        name: slug
        description: 'The card slug.'
        example: k7m2p9qr
        required: true
        schema:
          type: string
  /api/v1/employees/sync:
    post:
      summary: 'Sync employees'
      operationId: syncEmployees
      description: "Batch upsert (max 500 rows) matched by `employee_ref`, falling back\nto `email`. New employees are created with an auto-provisioned\nPENDING card. Rows with `active: false` deactivate the user and flip\ntheir cards to inactive immediately; re-activated users keep their\ncards inactive until re-approved. Requires the `employees:write`\ntoken ability."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  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.'
                properties:
                  created:
                    type: integer
                    example: 2
                  updated:
                    type: integer
                    example: 1
                  deactivated:
                    type: integer
                    example: 1
                  reactivated:
                    type: integer
                    example: 0
                  failures:
                    type: array
                    example:
                      -
                        index: 4
                        errors:
                          email:
                            - 'The email field is required.'
                    items:
                      type: object
                      properties:
                        index:
                          type: integer
                          example: 4
                        errors:
                          type: object
                          properties:
                            email:
                              type: array
                              example:
                                - 'The email field is required.'
                              items:
                                type: string
                  note:
                    type: string
                    example: 'Re-activated employees keep their cards inactive until re-approved.'
      tags:
        - Employees
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                employees:
                  type: array
                  description: ''
                  example: null
                  items:
                    type: object
  /api/v1/touchpoints:
    get:
      summary: 'List touchpoints'
      operationId: listTouchpoints
      description: 'Requires the `touchpoints:read` token ability.'
      parameters:
        -
          in: query
          name: type
          description: 'Filter by type: staff_card, branch_counter or marketing_material.'
          example: branch_counter
          required: false
          schema:
            type: string
            description: 'Filter by type: staff_card, branch_counter or marketing_material.'
            example: branch_counter
        -
          in: query
          name: journey
          description: 'Filter by journey: card, inquiry, service_request, feedback, booking or locator.'
          example: feedback
          required: false
          schema:
            type: string
            description: 'Filter by journey: card, inquiry, service_request, feedback, booking or locator.'
            example: feedback
        -
          in: query
          name: branch_id
          description: 'Filter by branch.'
          example: 1
          required: false
          schema:
            type: integer
            description: 'Filter by branch.'
            example: 1
        -
          in: query
          name: search
          description: 'Match against the internal name.'
          example: lobby
          required: false
          schema:
            type: string
            description: 'Match against the internal name.'
            example: lobby
        -
          in: query
          name: per_page
          description: 'Results per page (max 100).'
          example: 15
          required: false
          schema:
            type: integer
            description: 'Results per page (max 100).'
            example: 15
      responses: {  }
      tags:
        - Touchpoints
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                type:
                  type: string
                  description: ''
                  example: architecto
                  nullable: true
                journey:
                  type: string
                  description: ''
                  example: architecto
                  nullable: true
                branch_id:
                  type: integer
                  description: ''
                  example: 16
                  nullable: true
                search:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: 'n'
                  nullable: true
    post:
      summary: 'Create a touchpoint'
      operationId: createATouchpoint
      description: "The public slug is generated server-side. Requires the\n`touchpoints:write` token ability."
      parameters: []
      responses:
        201:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  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'
                properties:
                  data:
                    type: object
                    properties:
                      slug:
                        type: string
                        example: w3n8k2mq
                      type:
                        type: string
                        example: branch_counter
                      journey:
                        type: string
                        example: feedback
                      name:
                        type: string
                        example: 'Qurum branch counter'
                      branch_id:
                        type: integer
                        example: 1
                      is_active:
                        type: boolean
                        example: true
                      public_url:
                        type: string
                        example: 'http://bitaqa.test/alameen/w3n8k2mq'
      tags:
        - Touchpoints
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                type:
                  type: string
                  description: 'Touchpoint type: staff_card, branch_counter or marketing_material.'
                  example: branch_counter
                  enum:
                    - staff_card
                    - branch_counter
                    - marketing_material
                journey:
                  type: string
                  description: 'Journey the touchpoint opens: card, inquiry, service_request, feedback, booking or locator.'
                  example: feedback
                  enum:
                    - card
                    - inquiry
                    - service_request
                    - feedback
                    - booking
                    - locator
                name:
                  type: string
                  description: 'Internal label. Must not be greater than 255 characters.'
                  example: 'Qurum branch counter'
                branch_id:
                  type: integer
                  description: 'Must match an existing stored value.'
                  example: 1
                  nullable: true
                is_active:
                  type: boolean
                  description: ''
                  example: true
                  nullable: true
              required:
                - type
                - journey
                - name
  '/api/v1/touchpoints/{slug}':
    patch:
      summary: 'Update a touchpoint'
      operationId: updateATouchpoint
      description: 'Requires the `touchpoints:write` token ability.'
      parameters: []
      responses: {  }
      tags:
        - Touchpoints
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                type:
                  type: string
                  description: ''
                  example: branch_counter
                  enum:
                    - staff_card
                    - branch_counter
                    - marketing_material
                journey:
                  type: string
                  description: ''
                  example: feedback
                  enum:
                    - card
                    - inquiry
                    - service_request
                    - feedback
                    - booking
                    - locator
                name:
                  type: string
                  description: 'Must not be greater than 255 characters.'
                  example: 'Lobby stand — renamed'
                branch_id:
                  type: integer
                  description: 'Must match an existing stored value.'
                  example: 16
                  nullable: true
                is_active:
                  type: boolean
                  description: ''
                  example: false
    delete:
      summary: 'Delete a touchpoint'
      operationId: deleteATouchpoint
      description: 'Requires the `touchpoints:write` token ability.'
      parameters: []
      responses:
        204:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example: {  }
                properties: {  }
      tags:
        - Touchpoints
    parameters:
      -
        in: path
        name: slug
        description: 'The touchpoint slug.'
        example: w3n8k2mq
        required: true
        schema:
          type: string
  /api/v1/webhooks:
    get:
      summary: 'List webhook endpoints'
      operationId: listWebhookEndpoints
      description: 'Secrets are masked — they are only revealed once, on creation.'
      parameters: []
      responses: {  }
      tags:
        - Webhooks
    post:
      summary: 'Create a webhook endpoint'
      operationId: createAWebhookEndpoint
      description: "The signing secret (provided or generated) is returned ONCE in this\nresponse as `secret` — store it now; it is stored encrypted and\nnever shown again."
      parameters: []
      responses:
        201:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  data:
                    id: 7
                    url: 'https://example.com/hooks/bitaqa'
                    events:
                      - card.created
                    secret: '********a1b2'
                    is_active: true
                  secret: whsec_9fK2...
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 7
                      url:
                        type: string
                        example: 'https://example.com/hooks/bitaqa'
                      events:
                        type: array
                        example:
                          - card.created
                        items:
                          type: string
                      secret:
                        type: string
                        example: '********a1b2'
                      is_active:
                        type: boolean
                        example: true
                  secret:
                    type: string
                    example: whsec_9fK2...
      tags:
        - Webhooks
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                url:
                  type: string
                  description: '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:
                  type: array
                  description: ''
                  example:
                    - appointment.created
                  items:
                    type: string
                    enum:
                      - card.tapped
                      - card.saved
                      - card.created
                      - card.deactivated
                      - inquiry.created
                      - request.created
                      - feedback.created
                      - appointment.created
                secret:
                  type: string
                  description: '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
                  nullable: true
              required:
                - url
  '/api/v1/webhooks/{id}':
    delete:
      summary: 'Delete a webhook endpoint'
      operationId: deleteAWebhookEndpoint
      description: ''
      parameters: []
      responses:
        204:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example: {  }
                properties: {  }
      tags:
        - Webhooks
    parameters:
      -
        in: path
        name: id
        description: 'The webhook endpoint id.'
        example: 7
        required: true
        schema:
          type: integer
