openapi: 3.0.0
info:
  title: Bappy API
  description: >-
    Complete collection of all API endpoints for the Bappy API.


    ## Quick Start

    1. Get your `client_id` and `client_secret` from
    [OmaxTelecom Console](https://console.omaxtelecom.com)

    2. Run **Auth → Get Access Token** to obtain a Bearer token

    3. All other endpoints use the `access_token` automatically


    ## Authentication (OAuth 2.0)


    This API uses the **OAuth 2.0 Client Credentials** grant type ([RFC 6749
    §4.4](https://datatracker.ietf.org/doc/html/rfc6749#section-4.4)).


    **Token endpoint:**

    ```

    POST
    POST https://api.omaxtelecom.com/auth/token

    ```


    **Parameters:**

    | Parameter | Value |

    |-----------|-------|

    | `grant_type` | `client_credentials` |

    | `client_id` | Your Client ID |

    | `client_secret` | Your Client Secret |


    The token endpoint returns a Bearer `access_token` with a limited lifetime
    (`expires_in` seconds). When the token expires, request a new one — there
    are no refresh tokens in this flow.


    ## API Design


    The API follows RESTful conventions:

    - **Path parameters** (`{identifier}`) are used for resource identification

    - **Query parameters** are used for filtering, pagination, and search

    - Links accept UUID or ICCID as the `{identifier}` path parameter


    ### Common Patterns:

    - **List**: `GET /resource` - Returns paginated list

    - **Single**: `GET /resource/{id}` - Returns single item

    - **Create**: `POST /resource` - Creates new resource

    - **Update**: `PUT /resource/{id}` - Updates existing resource


    ### Response Format:

    ```json

    {
      "success": true,
      "data": { ... },
      "meta": {
        "timestamp": "2025-01-01T12:00:00Z",
        "response_time_ms": 42
      }
    }

    ```


    ### Error Format:

    ```json

    {
      "success": false,
      "error": {
        "code": "NOT_FOUND",
        "message": "Resource not found.",
        "details": null
      },
      "meta": { "timestamp": "..." }
    }

    ```


    ### Error Codes:

    | Code | HTTP | Description |

    |------|------|-------------|

    | `INSUFFICIENT_BALANCE` | 402 | Wallet balance too low |

    | `ACTIVATION_FAILED` | 502 | OmaxTelecom Core network activation failed |

    | `ORG_SUSPENDED` | 403 | Organization is suspended |

    | `NOT_FOUND` | 404 | Resource not found |

    | `UNAUTHORIZED` | 401 | Missing or invalid token |

    | `VALIDATION_ERROR` | 422 | Request validation failed |

    | `PROVISIONING_ERROR` | 502 | OmaxTelecom Core network API error |

    | `PROVISIONING_FAILED` | 502 | OmaxTelecom Core network returned no result |

    | `PROVIDER_ERROR` | 502 | OmaxTelecom Core network operation failed |

    | `CONFIG_ERROR` | 500 | Server misconfiguration |

    | `INVALID_STATUS_CHANGE` | 422 | Status transition not allowed |

    | `INVALID_STATE` | 422 | Resource in invalid state |

    | `INVALID_PLAN` | 422 | Plan not available for operation |


    ### Pagination:

    List endpoints return paginated results with meta:

    ```json

    {
      "data": {
        "data": [...],
        "meta": {
          "current_page": 1,
          "last_page": 5,
          "per_page": 20,
          "total": 95,
          "from": 1,
          "to": 20
        }
      }
    }

    ```
  version: 1.0.0
components:
  securitySchemes:
    noauthAuth:
      type: http
      scheme: noauth
    bearerAuth:
      type: http
      scheme: bearer
security:
  - bearerAuth: []
tags:
  - name: Auth
    description: >-
      OAuth 2.0 authentication using the **Client Credentials** grant type ([RFC
      6749 §4.4](https://datatracker.ietf.org/doc/html/rfc6749#section-4.4)).


      Use your **Client ID** and **Client Secret** from
      [OmaxTelecom Console](https://console.omaxtelecom.com) to obtain an access token. The token has a limited lifetime — when it
      expires, simply request a new one.
  - name: Health (no auth)
    description: Health check endpoints that do not require authentication.
  - name: Links
    description: >-
      Link (SIM) management — list, create, view, update, manage plans, view
      history, and check network status.


      **Path Parameter – `{identifier}`:**

      All single-resource Link endpoints accept either a **Link UUID** or an
      **ICCID** as the `{identifier}` path parameter. Use whichever is more
      convenient for your integration.


      Examples:

      - `GET /v1/links/550e8400-e29b-41d4-a716-446655440000`

      - `GET /v1/links/8901010000000000001`
  - name: Plans
    description: >-
      Data plan management. List available plans, get plan details, view
      coverage, and explore regions.


      Plans can be **global** (available to all organizations) or
      **org-specific** (custom pricing). Global plans can exclude certain
      organizations via the `excluded_organizations` field.


      Each plan includes enriched OmaxTelecom Core network data: data amount, validity, sponsor
      profile, coverage type, regions, and coverage summary.
  - name: Transactions
    description: >-
      Transaction history, statistics, and analytics. View all financial
      transactions (activations, topups, SMS charges, monthly link fees,
      refunds), aggregated statistics, and dashboard analytics.
  - name: SMS
    description: >-
      SMS messaging — list sent messages and send new SMS to SIMs.


      The `link_id` in the send request body accepts either a Link UUID or
      ICCID.
  - name: Organization
    description: Organization profile and account balance.
  - name: Info
    description: >-
      Informational endpoints — eSIM installation instructions and mobile
      operator coverage.
paths:
  /auth/token:
    servers:
      - url: https://api.omaxtelecom.com
    post:
      tags:
        - Auth
      summary: Get Access Token
      description: >-
        ## Get Access Token


        Obtain a Bearer access token using the OAuth 2.0 **Client Credentials**
        grant ([RFC 6749
        §4.4](https://datatracker.ietf.org/doc/html/rfc6749#section-4.4)).


        ### Setup

        1. Get your `client_id` from
        [OmaxTelecom Console](https://console.omaxtelecom.com)

        2. Get your `client_secret` from
        [OmaxTelecom Console](https://console.omaxtelecom.com)


        ### Request

        ```

        POST https://api.omaxtelecom.com/auth/token

        Content-Type: application/x-www-form-urlencoded


        grant_type=client_credentials&client_id={client_id}&client_secret={client_secret}

        ```


        ### Response (200 OK)

        ```json

        {
          "access_token": "eyJhbGciOiJSUzI1NiIs...",
          "expires_in": 300,
          "token_type": "Bearer",
          "scope": "openid"
        }

        ```


        | Field | Type | Description |

        |-------|------|-------------|

        | `access_token` | string | Bearer token — include in `Authorization`
        header for all API calls |

        | `expires_in` | int | Token lifetime in seconds |

        | `token_type` | string | Always `Bearer` |

        | `scope` | string | Granted scopes |


        ### Token Usage

        Include the token in the `Authorization` header:

        ```

        Authorization: Bearer {access_token}

        ```


        ### Token Expiry

        The `client_credentials` grant does not issue refresh tokens ([RFC 6749
        §4.4.3](https://datatracker.ietf.org/doc/html/rfc6749#section-4.4.3)).
        When the token expires, request a new one by calling this endpoint
        again.


        ### Errors

        | HTTP | Error | Description |

        |------|-------|-------------|

        | 401 | `invalid_client` | Client ID or Secret is incorrect |

        | 400 | `unsupported_grant_type` | Wrong grant_type value |

        | 400 | `invalid_request` | Missing required parameters |


        ### Notes

        - Use the returned `access_token` in the `Authorization: Bearer` header
        for all API calls

        - Client ID and Secret are available at
        [OmaxTelecom Console](https://console.omaxtelecom.com)
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              properties:
                grant_type:
                  type: string
                  description: OAuth 2.0 grant type (RFC 6749 §4.4)
                  example: client_credentials
                client_id:
                  type: string
                  description: Your Client ID
                  example: '{{client_id}}'
                client_secret:
                  type: string
                  description: Your Client Secret
                  example: '{{client_secret}}'
      security:
        - noauthAuth: []
      parameters:
        - name: Content-Type
          in: header
          schema:
            type: string
          example: application/x-www-form-urlencoded
        - name: Accept
          in: header
          schema:
            type: string
          example: application/json
      responses:
        '200':
          description: Successful response
          content:
            application/json: {}
  /v1/health:
    servers:
      - url: https://api.omaxtelecom.com/bappy
    get:
      tags:
        - Health (no auth)
      summary: Health
      description: |-
        ## Health Check

        Simple health check endpoint.

        **Authentication:** None required

        **Response:**
        ```json
        {
          "success": true,
          "data": {
            "status": "ok"
          }
        }
        ```
      security:
        - noauthAuth: []
      parameters:
        - name: Accept
          in: header
          schema:
            type: string
          example: application/json
      responses:
        '200':
          description: Successful response
          content:
            application/json: {}
  /v1/status:
    servers:
      - url: https://api.omaxtelecom.com/bappy
    get:
      tags:
        - Health (no auth)
      summary: Status
      description: >-
        ## System Status


        Detailed system status including API, database and cache connectivity
        checks.


        **Authentication:** None required


        **Response:**

        ```json

        {
          "success": true,
          "data": {
            "api": "ok",
            "database": "ok",
            "cache": "ok"
          }
        }

        ```


        **Note:** Individual checks return `"error"` if the respective service
        is unreachable.
      security:
        - noauthAuth: []
      parameters:
        - name: Accept
          in: header
          schema:
            type: string
          example: application/json
      responses:
        '200':
          description: Successful response
          content:
            application/json: {}
  /v1/links:
    servers:
      - url: https://api.omaxtelecom.com/bappy
    get:
      tags:
        - Links
      summary: List links
      description: >-
        ## List Links


        Returns a paginated list of all links (SIM activations) for your
        organization.


        **Query Parameters:**

        | Parameter | Type | Default | Description |

        |-----------|------|---------|-------------|

        | `per_page` | int | 20 | Items per page (min: 1, max: 100) |

        | `status` | string | – | Filter by link status: `active`, `suspended`,
        `inactive` |

        | `search` | string | – | Free-text search (matches ICCID and other
        fields) |

        | `page` | int | 1 | Page number for pagination |


        **Response:**

        ```json

        {
          "success": true,
          "data": {
            "data": [
              {
                "id": "550e8400-e29b-41d4-a716-446655440000",
                "name": "My SIM",
                "iccid": "8901010000000000001",
                "status": "active",
                "created_at": "2025-01-10T08:30:00+00:00"
              }
            ],
            "meta": {
              "current_page": 1,
              "last_page": 5,
              "per_page": 20,
              "total": 95,
              "from": 1,
              "to": 20
            }
          }
        }

        ```
      parameters:
        - name: Accept
          in: header
          schema:
            type: string
          example: application/json
        - name: per_page
          in: query
          schema:
            type: integer
          description: 'Items per page (1-100, default: 20)'
          example: '20'
      responses:
        '200':
          description: Successful response
          content:
            application/json: {}
    post:
      tags:
        - Links
      summary: Create link
      description: >-
        ## Create Link


        Create a new link (eSIM activation). The system fetches an available SIM
        from the OmaxTelecom Core network, creates an endpoint, and activates it with the specified
        plan.


        This creates both a **link** and an initial **activation** record for
        the plan.


        **Body Parameters:**

        | Parameter | Type | Required | Description |

        |-----------|------|----------|-------------|

        | `plan_id` | uuid | **Yes** | Plan UUID to activate with (must exist in
        plans table) |

        | `name` | string | No | Optional display name (max 255 chars) |


        **Flow:**

        1. Checks wallet balance (must cover plan's retail price)

        2. Fetches available eSIM ICCID from OmaxTelecom Core network (filtered by sponsor profile
        and eSIM product)

        3. Deducts plan retail price from wallet

        4. Creates OmaxTelecom Core network endpoint with the plan as addon

        5. Creates link + activation + transaction records

        6. On OmaxTelecom Core network failure: wallet amount is automatically refunded


        **Response (201 Created):**

        ```json

        {
          "success": true,
          "data": {
            "id": "550e8400-e29b-41d4-a716-446655440000",
            "name": "My new SIM",
            "iccid": "8932042000000000000",
            "msisdn": "+31612345678",
            "lpa_profile": "LPA:1$example.com$ACTIVATION_CODE",
            "activation_url": "https://example.smdp.com",
            "amount_charged": "4.50",
            "currency": "EUR",
            "created_at": "2025-06-01T12:00:00+00:00"
          },
          "message": "Link created."
        }

        ```


        **Errors:**

        - `401 UNAUTHORIZED` – Missing or invalid Authorization header

        - `402 INSUFFICIENT_BALANCE` – Wallet balance too low (details:
        `required`, `available`, `currency`)

        - `422 VALIDATION_ERROR` – plan_id is required / plan not found

        - `500 CONFIG_ERROR` – OmaxTelecom Core network default base plan is not configured

        - `502 PROVISIONING_FAILED` – OmaxTelecom Core network returned no endpoint ID (amount
        refunded)

        - `502 PROVISIONING_ERROR` – OmaxTelecom Core network API error (amount refunded)
      requestBody:
        content:
          application/json:
            schema:
              type: object
              example:
                plan_id: '{{plan_id}}'
                name: My new SIM
      parameters:
        - name: Accept
          in: header
          schema:
            type: string
          example: application/json
        - name: Content-Type
          in: header
          schema:
            type: string
          example: application/json
      responses:
        '200':
          description: Successful response
          content:
            application/json: {}
  /v1/links/{link_identifier}:
    servers:
      - url: https://api.omaxtelecom.com/bappy
    get:
      tags:
        - Links
      summary: Get link by identifier
      description: >-
        ## Get Single Link


        Returns detailed link information including live OmaxTelecom Core network data, eSIM
        activation URLs, all activations with per-plan usage, and coverage data.


        Each activation has an `id` (activation UUID) which can be used in `PUT
        /v1/links/{identifier}/plans` to remove it.


        **Path Parameter:**

        | Parameter | Type | Description |

        |-----------|------|-------------|

        | `identifier` | string | Link **UUID** or **ICCID** |


        **Response:**

        ```json

        {
          "success": true,
          "data": {
            "id": "550e8400-e29b-41d4-a716-446655440000",
            "name": "My SIM",
            "iccid": "8932042000000000000",
            "status": "active",
            "created_at": "2025-01-10T08:30:00+00:00",
            "lpa_profile": "LPA:1$example.com$ACTIVATION_CODE",
            "apple_activation_url": "https://esimsetup.apple.com/esim_qrcode_provisioning?carddata=LPA:1$example.com$ACTIVATION_CODE",
            "android_activation_url": "https://esimsetup.android.com/esim_qrcode_provisioning?carddata=LPA:1$example.com$ACTIVATION_CODE",
            "msisdn": "+31612345678",
            "data_used_mb": 256.1234,
            "data_remaining_mb": 767.8766,
            "activations": [
              {
                "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
                "plan_id": "p1a2b3c4-d5e6-7890-abcd-ef1234567890",
                "plan_name": "Europe 1GB - 7 Days",
                "status": "active",
                "activation_date": "2025-01-15T10:00:00+00:00",
                "data_used_mb": 256.1234,
                "data_remaining_mb": 767.8766,
                "expiry_date": "2025-01-22T10:00:00+00:00",
                "coverage_countries": ["HR", "DE", "FR", "IT", "ES"]
              }
            ],
            "coverage_data": [
              {
                "iso2": "HR",
                "name": "Croatia",
                "operators": [
                  {
                    "operator_id": 123,
                    "operator_name": "A1 HR",
                    "network_types": "2G, 3G, 4G"
                  }
                ]
              }
            ]
          }
        }

        ```


        **Notes:**

        - `activations[].id` is the activation UUID — pass this in `remove[]` to
        detach a plan

        - `data_used_mb` / `data_remaining_mb` come from live OmaxTelecom Core network data (both
        total and per-activation)

        - `status` reflects the live OmaxTelecom Core network endpoint status

        - `lpa_profile` is the eSIM LPA activation string (fetched from OmaxTelecom Core network if
        not stored locally)

        - `apple_activation_url` / `android_activation_url` are universal deep
        links for eSIM installation

        - `coverage_countries` per activation shows ISO2 codes for that plan's
        coverage

        - `coverage_data` is an aggregated list of all countries and operators
        across all active plans


        **Errors:**

        - `404 NOT_FOUND` – Link not found
      parameters:
        - name: Accept
          in: header
          schema:
            type: string
          example: application/json
        - name: link_identifier
          in: path
          schema:
            type: string
          required: true
      responses:
        '200':
          description: Successful response
          content:
            application/json: {}
    put:
      tags:
        - Links
      summary: Reactivate link
      description: >-
        ## Reactivate Link


        Reactivate a suspended link. The status change is synchronized with
        the OmaxTelecom Core network.


        **Body:** `{ "status": "active" }`
      requestBody:
        content:
          application/json:
            schema:
              type: object
              example:
                status: active
      parameters:
        - name: Accept
          in: header
          schema:
            type: string
          example: application/json
        - name: Content-Type
          in: header
          schema:
            type: string
          example: application/json
        - name: link_identifier
          in: path
          schema:
            type: string
          required: true
      responses:
        '200':
          description: Successful response
          content:
            application/json: {}
  /v1/links/{link_identifier}/plans:
    servers:
      - url: https://api.omaxtelecom.com/bappy
    put:
      tags:
        - Links
      summary: Modify link plans (remove only)
      description: >-
        ## Remove Activation from Link


        Remove (cancel) an activation from a link. Get the activation UUID from
        `GET /v1/links/{id}` → `activations[].id`.


        **Body:** `{ "remove": ["activation-uuid"] }`
      requestBody:
        content:
          application/json:
            schema:
              type: object
              example:
                remove:
                  - '{{activation_id}}'
      parameters:
        - name: Accept
          in: header
          schema:
            type: string
          example: application/json
        - name: Content-Type
          in: header
          schema:
            type: string
          example: application/json
        - name: link_identifier
          in: path
          schema:
            type: string
          required: true
      responses:
        '200':
          description: Successful response
          content:
            application/json: {}
  /v1/links/{link_identifier}/topup-plans:
    servers:
      - url: https://api.omaxtelecom.com/bappy
    get:
      tags:
        - Links
      summary: Get topup plans for link
      description: >-
        ## Get Available Topup Plans for Link


        Returns plans available for topping up a specific link. Plans are
        filtered by matching sponsor profile only plans compatible with the
        link's OmaxTelecom Core network sponsor profile are returned.


        Each plan includes data amount, validity, pricing and coverage summary.


        **Path Parameter:**

        | Parameter | Type | Description |

        |-----------|------|-------------|

        | `identifier` | string | Link **UUID** or **ICCID** |


        **Response:**

        ```json

        {
          "success": true,
          "data": [
            {
              "id": 5,
              "name": "Europe Topup 1GB - 7 Days",
              "retail_price": "4.50",
              "currency": "EUR",
              "data_gb": 1.0,
              "validity_days": 7,
              "coverage": {
                "countries": ["HR", "DE", "FR", "IT", "ES"],
                "total_countries": 32,
                "total_operators": 85
              }
            }
          ]
        }

        ```


        **Notes:**

        - Only plans with a matching OmaxTelecom Core network sponsor profile are returned

        - Plans without a `provider_plan_id` are excluded when a sponsor profile
        is detected

        - Use the plan `id` in `PUT /v1/links/{identifier}/plans` → `add[]` to
        apply the topup


        **Errors:**

        - `404 NOT_FOUND` – Link not found
      parameters:
        - name: Accept
          in: header
          schema:
            type: string
          example: application/json
        - name: link_identifier
          in: path
          schema:
            type: string
          required: true
      responses:
        '200':
          description: Successful response
          content:
            application/json: {}
  /v1/links/{link_identifier}/history:
    servers:
      - url: https://api.omaxtelecom.com/bappy
    get:
      tags:
        - Links
      summary: Get link history
      description: >-
        ## Get Link History


        Returns a paginated list of all transactions related to a specific link.
        This includes:

        - **activation** — initial link creation charge

        - **topup** — plan topup charges

        - **refund** — refunds for failed operations

        - **monthly_link_fee** — monthly fees that include this link in
        `charged_link_ids`


        **Path Parameter:**

        | Parameter | Type | Description |

        |-----------|------|-------------|

        | `identifier` | string | Link **UUID** or **ICCID** |


        **Query Parameters:**

        | Parameter | Type | Default | Description |

        |-----------|------|---------|-------------|

        | `per_page` | int | 15 | Items per page (min: 1, max: 100) |

        | `page` | int | 1 | Page number for pagination |


        **Response:**

        ```json

        {
          "success": true,
          "data": {
            "data": [
              {
                "id": "tx-uuid",
                "type": "activation",
                "amount": "4.50",
                "currency": "EUR",
                "plan_name": "Europe 1GB - 7 Days",
                "price_per_link": null,
                "billing_period": null,
                "activation_id": "act-uuid",
                "charged_at": "2025-01-15T10:00:00+00:00",
                "created_at": "2025-01-15T10:00:00+00:00"
              },
              {
                "id": "tx-uuid-2",
                "type": "topup",
                "amount": "10.00",
                "currency": "EUR",
                "plan_name": "Europe 3GB - 30 Days",
                "price_per_link": null,
                "billing_period": null,
                "activation_id": "act-uuid-2",
                "charged_at": "2025-02-01T14:30:00+00:00",
                "created_at": "2025-02-01T14:30:00+00:00"
              },
              {
                "id": "tx-uuid-3",
                "type": "monthly_link_fee",
                "amount": "15.00",
                "currency": "EUR",
                "plan_name": null,
                "price_per_link": "0.5000",
                "billing_period": "2025-01",
                "activation_id": null,
                "charged_at": "2025-02-01T00:00:00+00:00",
                "created_at": "2025-02-01T00:05:00+00:00"
              }
            ],
            "meta": {
              "current_page": 1,
              "last_page": 2,
              "per_page": 15,
              "total": 18,
              "from": 1,
              "to": 15
            }
          }
        }

        ```


        **Notes:**

        - Transactions are ordered by `charged_at` descending (newest first)

        - Monthly link fee transactions appear if this link is in their
        `charged_link_ids` metadata

        - `plan_name` is resolved from the activation's plan, or from
        transaction metadata


        **Errors:**

        - `404 NOT_FOUND` – Link not found
      parameters:
        - name: Accept
          in: header
          schema:
            type: string
          example: application/json
        - name: per_page
          in: query
          schema:
            type: integer
          description: 'Items per page (1-100, default: 15)'
          example: '15'
        - name: link_identifier
          in: path
          schema:
            type: string
          required: true
      responses:
        '200':
          description: Successful response
          content:
            application/json: {}
  /v1/links/{link_identifier}/network-status:
    servers:
      - url: https://api.omaxtelecom.com/bappy
    get:
      tags:
        - Links
      summary: Get link network status (live)
      description: >-
        ## Get Link Network Status (Live)


        Force a live network status check from the OmaxTelecom Core network, bypassing the cache.


        Same response format as the cached version but always returns `cached:
        false`.
      parameters:
        - name: Accept
          in: header
          schema:
            type: string
          example: application/json
        - name: live
          in: query
          schema:
            type: boolean
          description: Force live fetch from OmaxTelecom Core network (bypass cache)
          example: 'true'
        - name: link_identifier
          in: path
          schema:
            type: string
          required: true
      responses:
        '200':
          description: Successful response
          content:
            application/json: {}
  /v1/plans:
    servers:
      - url: https://api.omaxtelecom.com/bappy
    get:
      tags:
        - Plans
      summary: List plans (combined filters)
      description: >-
        ## List Plans (Combined Filters)


        All plan filters can be combined. This example returns multi-country
        European plans with IR1 sponsor profile.
      parameters:
        - name: Accept
          in: header
          schema:
            type: string
          example: application/json
        - name: region
          in: query
          schema:
            type: string
          description: Region code
          example: EU
        - name: coverage_type
          in: query
          schema:
            type: string
          description: Coverage type filter
          example: regional
        - name: sponsor_profile
          in: query
          schema:
            type: string
          description: Sponsor profile filter
          example: IR1
      responses:
        '200':
          description: Successful response
          content:
            application/json: {}
  /v1/plans/{plan_id}:
    servers:
      - url: https://api.omaxtelecom.com/bappy
    get:
      tags:
        - Plans
      summary: Get plan by ID
      description: >-
        ## Get Single Plan


        Returns detailed information about a specific plan. Only returns enabled
        plans that are accessible to your organization.


        Same fields as the list response. Global plans that have an org-specific
        copy (same `provider_plan_id`) are hidden.


        **Path Parameter:**

        | Parameter | Type | Description |

        |-----------|------|-------------|

        | `id` | uuid | Plan UUID |


        **Response:**

        ```json

        {
          "success": true,
          "data": {
            "id": 1,
            "name": "Europe 1GB - 7 Days",
            "retail_price": "4.50",
            "currency": "EUR",
            "data_gb": 1.0,
            "validity_days": 7,
            "sponsor_profile": "IR1",
            "coverage_type": "regional",
            "regions": [
              {"code": "EU", "name": "Europe & UK"}
            ],
            "coverage": {
              "countries": ["HR", "DE", "FR", "IT", "ES"],
              "total_countries": 32,
              "total_operators": 85
            }
          }
        }

        ```


        **Errors:**

        - `404 NOT_FOUND` – Plan not found (or disabled/excluded for your org)
      parameters:
        - name: Accept
          in: header
          schema:
            type: string
          example: application/json
        - name: plan_id
          in: path
          schema:
            type: string
          required: true
      responses:
        '200':
          description: Successful response
          content:
            application/json: {}
  /v1/plans/{plan_id}/coverage:
    servers:
      - url: https://api.omaxtelecom.com/bappy
    get:
      tags:
        - Plans
      summary: Get plan coverage
      description: >-
        ## Get Plan Coverage


        Returns the full detailed coverage for a specific plan — all countries
        and their operators with network types.


        Use this for displaying a detailed coverage map. For a quick summary,
        use the `coverage` field in `GET /v1/plans` or `GET /v1/plans/{id}`.


        **Path Parameter:**

        | Parameter | Type | Description |

        |-----------|------|-------------|

        | `id` | uuid | Plan UUID |


        **Response:**

        ```json

        {
          "success": true,
          "data": {
            "plan_id": 1,
            "plan_name": "Europe 1GB - 7 Days",
            "countries": [
              {
                "country_id": 48,
                "iso2": "HR",
                "iso3": "HRV",
                "name": "Croatia",
                "operators": [
                  {
                    "operator_name": "A1 HR",
                    "sponsor_name": "A1 Telekom Austria",
                    "tadig": "HRVVIP",
                    "network_types": "2G, 3G, 4G"
                  },
                  {
                    "operator_name": "T-Mobile HR",
                    "sponsor_name": "Deutsche Telekom",
                    "tadig": "HRVTMO",
                    "network_types": "2G, 3G, 4G, 5G"
                  }
                ]
              },
              {
                "country_id": 53,
                "iso2": "DE",
                "iso3": "DEU",
                "name": "Germany",
                "operators": ["..."]
              }
            ],
            "total_countries": 32,
            "total_operators": 85
          }
        }

        ```


        **Errors:**

        - `404 NOT_FOUND` – Plan not found (or disabled/excluded for your org)
      parameters:
        - name: Accept
          in: header
          schema:
            type: string
          example: application/json
        - name: plan_id
          in: path
          schema:
            type: string
          required: true
      responses:
        '200':
          description: Successful response
          content:
            application/json: {}
  /v1/plans/regions:
    servers:
      - url: https://api.omaxtelecom.com/bappy
    get:
      tags:
        - Plans
      summary: Get coverage regions
      description: >-
        ## Get Coverage Regions


        Returns all available coverage regions with their codes and display
        labels. Use region codes to filter plans via `GET /v1/plans?region=EU`.


        **Response:**

        ```json

        {
          "success": true,
          "data": [
            {"code": "EU", "name": "Europe & UK"},
            {"code": "AF", "name": "Africa"},
            {"code": "AS", "name": "Asia"},
            {"code": "LA", "name": "Latin America"},
            {"code": "NA", "name": "North America"},
            {"code": "OC", "name": "Oceania"}
          ]
        }

        ```


        **Notes:**

        - Region codes are: `EU`, `AF`, `AS`, `LA`, `NA`, `OC`

        - Each region contains a predefined set of ISO 3166-1 alpha-2 country
        codes

        - A plan matches a region if at least one of its coverage countries
        belongs to that region
      parameters:
        - name: Accept
          in: header
          schema:
            type: string
          example: application/json
      responses:
        '200':
          description: Successful response
          content:
            application/json: {}
  /v1/transactions:
    servers:
      - url: https://api.omaxtelecom.com/bappy
    get:
      tags:
        - Transactions
      summary: List transactions (filter by link)
      description: >-
        ## List Transactions for Link


        Filter transactions for a specific link UUID.


        **Note:** For a more comprehensive link-specific transaction history
        (including monthly link fees), use `GET /v1/links/{identifier}/history`
        instead.
      parameters:
        - name: Accept
          in: header
          schema:
            type: string
          example: application/json
        - name: link_id
          in: query
          schema:
            type: string
          description: Link UUID to filter by
          example: '{{link_identifier}}'
        - name: per_page
          in: query
          schema:
            type: integer
          example: '20'
      responses:
        '200':
          description: Successful response
          content:
            application/json: {}
  /v1/transactions/stats:
    servers:
      - url: https://api.omaxtelecom.com/bappy
    get:
      tags:
        - Transactions
      summary: Transaction stats (date range)
      description: |-
        ## Transaction Statistics (Date Range)

        Get transaction statistics for a specific date range.
      parameters:
        - name: Accept
          in: header
          schema:
            type: string
          example: application/json
        - name: from
          in: query
          schema:
            type: string
          description: Start date (Y-m-d)
          example: '2025-01-01'
        - name: to
          in: query
          schema:
            type: string
          description: End date (Y-m-d)
          example: '2025-12-31'
      responses:
        '200':
          description: Successful response
          content:
            application/json: {}
  /v1/transactions/analytics:
    servers:
      - url: https://api.omaxtelecom.com/bappy
    get:
      tags:
        - Transactions
      summary: Transaction analytics (30 days)
      description: |-
        ## Transaction Analytics (30 Days)

        Get analytics for the last 30 days.
      parameters:
        - name: Accept
          in: header
          schema:
            type: string
          example: application/json
        - name: period_days
          in: query
          schema:
            type: integer
          description: 30-day analytics period
          example: '30'
      responses:
        '200':
          description: Successful response
          content:
            application/json: {}
  /v1/sms:
    servers:
      - url: https://api.omaxtelecom.com/bappy
    get:
      tags:
        - SMS
      summary: List SMS messages (by link)
      description: |-
        ## List SMS Messages for Link

        Filter SMS messages for a specific link.
      parameters:
        - name: Accept
          in: header
          schema:
            type: string
          example: application/json
        - name: link_id
          in: query
          schema:
            type: string
          description: Link UUID to filter by
          example: '{{link_identifier}}'
        - name: per_page
          in: query
          schema:
            type: integer
          example: '20'
      responses:
        '200':
          description: Successful response
          content:
            application/json: {}
    post:
      tags:
        - SMS
      summary: Send SMS
      description: >-
        ## Send SMS


        Send an SMS message to a specific SIM. The message is queued for async
        delivery via a background job.


        **Body Parameters:**

        | Parameter | Type | Required | Description |

        |-----------|------|----------|-------------|

        | `link_id` | string | **Yes** | Link UUID or ICCID identifying the
        target SIM |

        | `message` | string | **Yes** | Message content (**max 80 characters**)
        |


        **Response (202 Accepted):**

        ```json

        {
          "success": true,
          "data": {
            "id": "sms-uuid",
            "link_id": "link-uuid",
            "status": "pending"
          },
          "message": "SMS queued for delivery."
        }

        ```


        **Notes:**

        - SMS is delivered asynchronously — check the status via `GET /v1/sms`

        - Cost per SMS is determined by the organization's `price_per_sms`
        setting

        - The `link_id` field accepts either a UUID or ICCID


        **Errors:**

        - `404 NOT_FOUND` – Link not found

        - `422 VALIDATION_ERROR` – link_id and message are required, message max
        80 chars
      requestBody:
        content:
          application/json:
            schema:
              type: object
              example:
                link_id: '{{link_identifier}}'
                message: Hello from API
      parameters:
        - name: Accept
          in: header
          schema:
            type: string
          example: application/json
        - name: Content-Type
          in: header
          schema:
            type: string
          example: application/json
      responses:
        '200':
          description: Successful response
          content:
            application/json: {}
  /v1/organization:
    servers:
      - url: https://api.omaxtelecom.com/bappy
    get:
      tags:
        - Organization
      summary: Profile
      description: >-
        ## Organization Profile


        Returns the authenticated user's organization profile including pricing
        settings.


        **Response:**

        ```json

        {
          "success": true,
          "data": {
            "id": 1,
            "name": "My Company",
            "slug": "my-company",
            "omaxtelecom_id": "org-omaxtelecom-id-uuid",
            "status": "active",
            "price_per_sms": "0.0500",
            "price_per_link": "0.5000",
            "settings": {
              "...custom org settings..."
            }
          }
        }

        ```


        **Fields:**

        | Field | Type | Description |

        |-------|------|-------------|

        | `id` | int | Organization ID |

        | `name` | string | Organization display name |

        | `slug` | string | URL-friendly slug |

        | `omaxtelecom_id` | string | OmaxTelecom ID organization UUID |

        | `status` | string | Organization status: `active`, `suspended` |

        | `price_per_sms` | string | Cost per SMS message (EUR, 4 decimals) |

        | `price_per_link` | string | Monthly cost per active link (EUR, 4
        decimals) |

        | `settings` | object | Custom organization settings |
      parameters:
        - name: Accept
          in: header
          schema:
            type: string
          example: application/json
      responses:
        '200':
          description: Successful response
          content:
            application/json: {}
  /v1/organization/balance:
    servers:
      - url: https://api.omaxtelecom.com/bappy
    get:
      tags:
        - Organization
      summary: Balance
      description: |-
        ## Organization Balance

        Returns the current account balance from the Console wallet.

        **Response:**
        ```json
        {
          "success": true,
          "data": {
            "balance": "1250.50",
            "currency": "EUR"
          }
        }
        ```

        **Errors:**
        - `401 UNAUTHORIZED` – Missing or invalid Authorization header
      parameters:
        - name: Accept
          in: header
          schema:
            type: string
          example: application/json
      responses:
        '200':
          description: Successful response
          content:
            application/json: {}
  /v1/info/instructions:
    servers:
      - url: https://api.omaxtelecom.com/bappy
    get:
      tags:
        - Info
      summary: eSIM installation instructions
      description: >-
        ## eSIM Installation Instructions


        Returns step-by-step eSIM installation instructions for iOS and Android
        devices.


        **Response:**

        ```json

        {
          "success": true,
          "data": {
            "ios": {
              "title": "iOS Installation",
              "steps": [
                "Go to Settings > Cellular > Add Cellular Plan.",
                "Scan the QR code or enter the activation details manually.",
                "Label the plan (e.g., 'Travel Data').",
                "Set the eSIM as your data line if needed.",
                "Turn on Data Roaming under Cellular Data Options."
              ]
            },
            "android": {
              "title": "Android Installation",
              "steps": [
                "Go to Settings > Network & Internet > SIMs > Add SIM.",
                "Choose 'Download a SIM instead' or scan QR code.",
                "Follow the on-screen prompts to activate.",
                "Enable Mobile Data and Data Roaming."
              ]
            }
          }
        }

        ```
      parameters:
        - name: Accept
          in: header
          schema:
            type: string
          example: application/json
      responses:
        '200':
          description: Successful response
          content:
            application/json: {}
  /v1/info/operators:
    servers:
      - url: https://api.omaxtelecom.com/bappy
    get:
      tags:
        - Info
      summary: Mobile operators (search by name)
      description: |-
        ## Search Operators by Country Name

        Search for operators by partial country name.

        **Example:** `?search=croa` returns Croatia and its operators.
      parameters:
        - name: Accept
          in: header
          schema:
            type: string
          example: application/json
        - name: search
          in: query
          schema:
            type: string
          description: Partial country name (case-insensitive)
          example: croa
      responses:
        '200':
          description: Successful response
          content:
            application/json: {}
