openapi: 3.0.3
info:
  title: EasySignage Admin API Key Endpoints
  version: 0.1.0
  description: >
    Public Admin API surface for partner and reseller integrations. These
    endpoints are documented for API keys generated from the EasySignage Admin
    Settings > API Key page. Every request must include the API key in the
    X-API-Key header and the target brand identifier in the brand-ID header.
    The API key is scoped to one or more permission categories. Permission
    value 1 means read-only access and can call GET/read operations for that
    category. Permission value 2 means full access and can call both read and
    write operations for that category. Account Summary is read-only and does
    not support full access. Responses use the standard EasySignage Admin envelope:
    status is true on success, error_msg contains a machine-readable or
    operator-facing error string when status is false, and data contains the
    endpoint-specific payload. Authentication and permission failures return
    HTTP 403 with an empty body. Unknown endpoint paths or unsupported methods
    return HTTP 404 with an empty body. Paths in this specification use the
    public /v1/admin-api prefix.
servers:
  - url: https://admin-api.easysignage.io
security:
  - AdminApiKeyAuth: []
tags:
  - name: Users
    description: Manage brand users, their profile details, status, sub-users, trials, migrations, and coupon assignment.
  - name: Coupons
    description: Manage billing coupons and subscription-related coupon operations for the brand.
  - name: Players
    description: Read and update digital signage player records owned by the brand.
  - name: Billings
    description: Read billing account details and run billing actions for the brand.
  - name: Account Summary
    description: Read-only aggregate reporting for the brand account.
paths:
  /v1/admin-api/users:
    get:
      tags:
        - Users
      summary: List users
      description: >
        Returns all users for the requested brand. The response data is an
        array of user records. This is a read-only operation and requires the
        users permission with value 1 or 2.
      operationId: listUsers
      x-admin-api-resource: users
      x-admin-api-permission: 1
      parameters:
        - $ref: "#/components/parameters/BrandID"
      responses:
        "200":
          $ref: "#/components/responses/UserListEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
    put:
      tags:
        - Users
      summary: Create user
      description: >
        Creates a user for the brand. The JSON body must include email,
        password, and name. The optional organization field is stored on the
        user profile when supplied. The API also creates the default licence
        account settings for the user and ensures a billing account exists.
        Requires full users permission with value 2.
      operationId: createUser
      x-admin-api-resource: users
      x-admin-api-permission: 2
      parameters:
        - $ref: "#/components/parameters/BrandID"
      requestBody:
        $ref: "#/components/requestBodies/GenericObjectBody"
      responses:
        "200":
          $ref: "#/components/responses/ApiEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/users/password:
    patch:
      tags:
        - Users
      summary: Reset user password
      description: >
        Updates the password for a user. The JSON body must include email and
        password. The email is lower-cased before it is used. This endpoint
        does not return the new password. Requires full users permission with
        value 2.
      operationId: resetUserPassword
      x-admin-api-resource: users
      x-admin-api-permission: 2
      parameters:
        - $ref: "#/components/parameters/BrandID"
      requestBody:
        $ref: "#/components/requestBodies/GenericObjectBody"
      responses:
        "200":
          $ref: "#/components/responses/ApiEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/users/{email}:
    get:
      tags:
        - Users
      summary: Get user
      description: >
        Returns the full admin view of one brand user by email. The response
        combines the user profile, billing/account settings, account creation
        time, managed-account access, and trial availability for the brand.
        Requires users permission with value 1 or 2.
      operationId: getUser
      x-admin-api-resource: users
      x-admin-api-permission: 1
      parameters:
        - $ref: "#/components/parameters/BrandID"
        - $ref: "#/components/parameters/Email"
      responses:
        "200":
          $ref: "#/components/responses/ApiEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
    patch:
      tags:
        - Users
      summary: Update user
      description: >
        Updates editable profile fields for one brand user. The JSON body must
        include name and may include organization. Admin API key requests
        should use only the fields documented for this endpoint. On success
        the response data contains the refreshed user details. Requires full
        users permission with value 2.
      operationId: updateUser
      x-admin-api-resource: users
      x-admin-api-permission: 2
      parameters:
        - $ref: "#/components/parameters/BrandID"
        - $ref: "#/components/parameters/Email"
      requestBody:
        $ref: "#/components/requestBodies/GenericObjectBody"
      responses:
        "200":
          $ref: "#/components/responses/ApiEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
    delete:
      tags:
        - Users
      summary: Delete user
      description: >
        Deletes the user profile from the current brand. This operation does
        not remove related player or billing data. Requires full users
        permission with value 2.
      operationId: deleteUser
      x-admin-api-resource: users
      x-admin-api-permission: 2
      parameters:
        - $ref: "#/components/parameters/BrandID"
        - $ref: "#/components/parameters/Email"
      responses:
        "200":
          $ref: "#/components/responses/ApiEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/users/{email}/sub_user:
    put:
      tags:
        - Users
      summary: Add or update a sub-user
      description: >
        Adds a sub-user relationship under the parent account identified by the
        email path parameter. The JSON body must include sub_user as an email
        address. Optional auto_switch updates the sub-user account linkage so
        the sub-user can switch into the parent account. On success the
        response data contains the updated sub-user list. Requires full users
        permission with value 2.
      operationId: setSubUser
      x-admin-api-resource: users
      x-admin-api-permission: 2
      parameters:
        - $ref: "#/components/parameters/BrandID"
        - $ref: "#/components/parameters/Email"
      requestBody:
        $ref: "#/components/requestBodies/GenericObjectBody"
      responses:
        "200":
          $ref: "#/components/responses/ApiEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/users/{email}/trial:
    put:
      tags:
        - Users
      summary: Add trial for user
      description: >
        Creates a trial subscription for the user when trials are enabled for
        the brand and the user has not already used a trial. The trial length
        and plan come from the brand settings. Requires full users permission
        with value 2.
      operationId: addUserTrial
      x-admin-api-resource: users
      x-admin-api-permission: 2
      parameters:
        - $ref: "#/components/parameters/BrandID"
        - $ref: "#/components/parameters/Email"
      responses:
        "200":
          $ref: "#/components/responses/ApiEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/users/{email}/sub_users:
    get:
      tags:
        - Users
      summary: List sub-users
      description: >
        Returns the sub-user records for the parent account. The email path
        parameter identifies the parent account.
        Requires users permission with value 1 or 2.
      operationId: listSubUsers
      x-admin-api-resource: users
      x-admin-api-permission: 1
      parameters:
        - $ref: "#/components/parameters/BrandID"
        - $ref: "#/components/parameters/Email"
      responses:
        "200":
          $ref: "#/components/responses/ApiEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/users/{email}/sub_users/{subuser}:
    delete:
      tags:
        - Users
      summary: Delete sub-user
      description: >
        Removes a sub-user relationship from the parent user's users
        account. The email path parameter identifies the parent account
        and subuser identifies the sub-user email to remove. On success the
        response data contains the updated sub-user list. Requires full users
        permission with value 2.
      operationId: deleteSubUser
      x-admin-api-resource: users
      x-admin-api-permission: 2
      parameters:
        - $ref: "#/components/parameters/BrandID"
        - $ref: "#/components/parameters/Email"
        - $ref: "#/components/parameters/Subuser"
      responses:
        "200":
          $ref: "#/components/responses/ApiEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/users/{email}/coupon/{coupon_id}:
    put:
      tags:
        - Users
      summary: Assign coupon to user
      description: >
        Applies the coupon identified by coupon_id to the user identified by
        email. The API validates the coupon, creates or loads the user's
        billing account, and creates a subscription using the coupon's plan and
        quantity. Requires full users permission with value 2.
      operationId: assignCouponToUser
      x-admin-api-resource: users
      x-admin-api-permission: 2
      parameters:
        - $ref: "#/components/parameters/BrandID"
        - $ref: "#/components/parameters/Email"
        - $ref: "#/components/parameters/CouponID"
      responses:
        "200":
          $ref: "#/components/responses/ApiEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/users/{email}/autoRenewCoupon/{coupon_id}:
    put:
      tags:
        - Users
      summary: Update user coupon auto-renew setting
      description: >
        Applies a coupon to the user through the auto-renew assignment flow.
        The email path parameter identifies the account and coupon_id
        identifies the coupon to apply. Requires full users permission with
        value 2.
      operationId: updateUserCouponAutoRenew
      x-admin-api-resource: users
      x-admin-api-permission: 2
      parameters:
        - $ref: "#/components/parameters/BrandID"
        - $ref: "#/components/parameters/Email"
        - $ref: "#/components/parameters/CouponID"
      requestBody:
        $ref: "#/components/requestBodies/GenericObjectBody"
      responses:
        "200":
          $ref: "#/components/responses/ApiEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/coupons:
    get:
      tags:
        - Coupons
      summary: List coupons
      description: >
        Returns coupons for the requested brand ordered by created date
        descending. This is the list used by the admin billing and licence
        flows for the selected brand. Requires coupons permission with value 1
        or 2.
      operationId: listCoupons
      x-admin-api-resource: coupons
      x-admin-api-permission: 1
      parameters:
        - $ref: "#/components/parameters/BrandID"
      responses:
        "200":
          $ref: "#/components/responses/CouponListEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
    put:
      tags:
        - Coupons
      summary: Create coupon
      description: >
        Creates a coupon for the brand. The JSON body must include planID,
        qty, and name. Optional fields include note, renew, and screenQty. The
        API calculates the coupon value from the selected plan and quantity,
        stores the coupon settings, and returns the created coupon. Requires
        full coupons permission with value 2.
      operationId: createCoupon
      x-admin-api-resource: coupons
      x-admin-api-permission: 2
      parameters:
        - $ref: "#/components/parameters/BrandID"
      requestBody:
        $ref: "#/components/requestBodies/GenericObjectBody"
      responses:
        "200":
          $ref: "#/components/responses/ApiEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/coupons/auto_renew:
    put:
      tags:
        - Coupons
      summary: Update coupon auto-renew
      description: >
        Creates or renews a coupon through the auto-renew route. The JSON body
        follows the same fields as Create coupon: planID, qty, name, optional
        note, optional renew, and optional screenQty. Requires full coupons
        permission with value 2.
      operationId: updateCouponsAutoRenew
      x-admin-api-resource: coupons
      x-admin-api-permission: 2
      parameters:
        - $ref: "#/components/parameters/BrandID"
      requestBody:
        $ref: "#/components/requestBodies/GenericObjectBody"
      responses:
        "200":
          $ref: "#/components/responses/ApiEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/coupons/sendInvoice/{coupon}:
    put:
      tags:
        - Coupons
      summary: Send invoice for coupon
      description: >
        Creates and sends an invoice for one or more coupon IDs supplied in
        the coupon path parameter. Multiple coupon IDs may be comma separated.
        Each coupon must have been redeemed before an invoice can be generated.
        If an invoice is already recorded for the coupon, the existing invoice
        is reused. Requires full coupons permission with value 2.
      operationId: sendCouponInvoice
      x-admin-api-resource: coupons
      x-admin-api-permission: 2
      parameters:
        - $ref: "#/components/parameters/BrandID"
        - $ref: "#/components/parameters/Coupon"
      responses:
        "200":
          $ref: "#/components/responses/ApiEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/coupons/{id}:
    delete:
      tags:
        - Coupons
      summary: Delete coupon
      description: >
        Deletes a coupon or cancels the linked subscription before deleting the
        coupon. Coupons that have already been redeemed cannot be deleted
        through this API. Requires full coupons permission with value 2.
      operationId: deleteCoupon
      x-admin-api-resource: coupons
      x-admin-api-permission: 2
      parameters:
        - $ref: "#/components/parameters/BrandID"
        - $ref: "#/components/parameters/ID"
      responses:
        "200":
          $ref: "#/components/responses/ApiEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/coupons/{id}/pause:
    post:
      tags:
        - Coupons
      summary: Pause coupon
      description: >
        Pauses the subscription linked to the coupon and marks the coupon as
        paused. The API stores who paused the coupon and when it was paused.
        The coupon must have a linked subscription. Requires full coupons
        permission with value 2.
      operationId: pauseCoupon
      x-admin-api-resource: coupons
      x-admin-api-permission: 2
      parameters:
        - $ref: "#/components/parameters/BrandID"
        - $ref: "#/components/parameters/ID"
      responses:
        "200":
          $ref: "#/components/responses/ApiEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/coupons/{id}/refresh:
    post:
      tags:
        - Coupons
      summary: Refresh coupon
      description: >
        Updates the coupon refresh timestamp and refreshes the linked
        subscription when one is present. A coupon can be refreshed at most
        once per hour through this API. Requires full coupons permission with
        value 2.
      operationId: refreshCoupon
      x-admin-api-resource: coupons
      x-admin-api-permission: 2
      parameters:
        - $ref: "#/components/parameters/BrandID"
        - $ref: "#/components/parameters/ID"
      responses:
        "200":
          $ref: "#/components/responses/ApiEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/coupons/{id}/autorenew:
    post:
      tags:
        - Coupons
      summary: Update coupon autorenew
      description: >
        Updates the auto-renew setting for a single coupon. The JSON body is an
        object containing the auto-renew settings to apply. Requires full
        coupons permission with value 2.
      operationId: updateCouponAutorenew
      x-admin-api-resource: coupons
      x-admin-api-permission: 2
      parameters:
        - $ref: "#/components/parameters/BrandID"
        - $ref: "#/components/parameters/ID"
      requestBody:
        $ref: "#/components/requestBodies/GenericObjectBody"
      responses:
        "200":
          $ref: "#/components/responses/ApiEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/coupons/{id}/unpause:
    post:
      tags:
        - Coupons
      summary: Unpause coupon
      description: >
        Restores a paused coupon's linked subscription and marks coupon
        as active. The coupon must currently have status paused, must have a
        linked subscription, and must be unpaused by the same user email that
        paused it. Requires full coupons permission with value 2.
      operationId: unpauseCoupon
      x-admin-api-resource: coupons
      x-admin-api-permission: 2
      parameters:
        - $ref: "#/components/parameters/BrandID"
        - $ref: "#/components/parameters/ID"
      responses:
        "200":
          $ref: "#/components/responses/ApiEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/players:
    get:
      tags:
        - Players
      summary: List players
      description: >
        Returns all players for the requested brand. Each returned player
        includes its id. Requires players permission with value 1 or 2.
      operationId: listPlayers
      x-admin-api-resource: players
      x-admin-api-permission: 1
      parameters:
        - $ref: "#/components/parameters/BrandID"
      responses:
        "200":
          $ref: "#/components/responses/PlayerListEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/players/data:
    put:
      tags:
        - Players
      summary: Remove player data
      description: >
        Removes stored player data for one or more players. The JSON body must
        include IDs as a comma-separated string of player IDs. Before removing
        data for each player, the API verifies that the player belongs to the
        requested brand. Requires full players permission with value 2.
      operationId: removePlayerData
      x-admin-api-resource: players
      x-admin-api-permission: 2
      parameters:
        - $ref: "#/components/parameters/BrandID"
      requestBody:
        $ref: "#/components/requestBodies/GenericObjectBody"
      responses:
        "200":
          $ref: "#/components/responses/ApiEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/players/summary:
    get:
      tags:
        - Account Summary
      summary: Get account player summary
      description: >
        Returns aggregate player counts for the brand. The summary includes
        total player count, licence count, expired count, paid count, online
        count, offline count, and per-account user summary numbers. This
        operation is read-only and belongs to the accountSummary permission
        category, which only supports permission value 1.
      operationId: getAccountPlayerSummary
      x-admin-api-resource: accountSummary
      x-admin-api-permission: 1
      parameters:
        - $ref: "#/components/parameters/BrandID"
      responses:
        "200":
          $ref: "#/components/responses/AccountPlayerSummaryEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/players/{id}:
    get:
      tags:
        - Players
      summary: Get players route by id
      description: >
        This endpoint currently returns the brand player list rather than a
        single player by ID. Treat it as current API behavior, not as a true
        player detail endpoint. Requires players permission with value 1 or 2.
      operationId: getPlayerRouteByID
      x-admin-api-resource: players
      x-admin-api-permission: 1
      parameters:
        - $ref: "#/components/parameters/BrandID"
        - $ref: "#/components/parameters/ID"
      responses:
        "200":
          $ref: "#/components/responses/ApiEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/players/{id}/autoUpdate:
    put:
      tags:
        - Players
      summary: Update player auto-update setting
      description: >
        Updates the auto-update setting for one player. The JSON body should
        include autoUpdate as a boolean. The API verifies the player belongs to
        the requested brand before updating and returns the refreshed player
        data with id included. Requires full players permission with value 2.
      operationId: updatePlayerAutoUpdate
      x-admin-api-resource: players
      x-admin-api-permission: 2
      parameters:
        - $ref: "#/components/parameters/BrandID"
        - $ref: "#/components/parameters/ID"
      requestBody:
        $ref: "#/components/requestBodies/GenericObjectBody"
      responses:
        "200":
          $ref: "#/components/responses/ApiEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/players/account/autoUpdate/{email}:
    put:
      tags:
        - Players
      summary: Update auto-update setting for account players
      description: >
        Updates the auto-update setting for every player belonging to the user
        identified by the email path parameter and the requested brand. The
        JSON body should include autoUpdate as a boolean. Requires full players
        permission with value 2.
      operationId: updateAccountPlayersAutoUpdate
      x-admin-api-resource: players
      x-admin-api-permission: 2
      parameters:
        - $ref: "#/components/parameters/BrandID"
        - $ref: "#/components/parameters/Email"
      requestBody:
        $ref: "#/components/requestBodies/GenericObjectBody"
      responses:
        "200":
          $ref: "#/components/responses/ApiEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/players/all/autoUpdate:
    put:
      tags:
        - Players
      summary: Update auto-update setting for all players
      description: >
        Updates the auto-update setting for all players in the requested brand.
        The JSON body should include autoUpdate as a boolean. Requires full
        players permission with value 2.
      operationId: updateAllPlayersAutoUpdate
      x-admin-api-resource: players
      x-admin-api-permission: 2
      parameters:
        - $ref: "#/components/parameters/BrandID"
      requestBody:
        $ref: "#/components/requestBodies/GenericObjectBody"
      responses:
        "200":
          $ref: "#/components/responses/ApiEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/players/user/{email}:
    get:
      tags:
        - Players
      summary: List players for user
      description: >
        Returns all players owned by the user identified by email within the
        requested brand. Each returned player includes its id. Requires players
        permission with value 1 or 2.
      operationId: listUserPlayers
      x-admin-api-resource: players
      x-admin-api-permission: 1
      parameters:
        - $ref: "#/components/parameters/BrandID"
        - $ref: "#/components/parameters/Email"
      responses:
        "200":
          $ref: "#/components/responses/ApiEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/billing/customer:
    get:
      tags:
        - Billings
      summary: Get billing customer
      description: >
        Returns the billing account details for the brand. The brand must have
        a billing account configured. Requires billings permission with value 1
        or 2.
      operationId: getBillingCustomer
      x-admin-api-resource: billings
      x-admin-api-permission: 1
      parameters:
        - $ref: "#/components/parameters/BrandID"
      responses:
        "200":
          $ref: "#/components/responses/BillingCustomerEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/billing/brand:
    get:
      tags:
        - Billings
      summary: Get billing brand
      description: >
        Returns the current brand ID from the billing route after initializing
        billing access. This is a read-only billing utility endpoint. Requires
        billings permission with value 1 or 2.
      operationId: getBillingBrand
      x-admin-api-resource: billings
      x-admin-api-permission: 1
      parameters:
        - $ref: "#/components/parameters/BrandID"
      responses:
        "200":
          $ref: "#/components/responses/BillingBrandEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/billing/due_email:
    post:
      tags:
        - Billings
      summary: Send due invoice reminder email
      description: >
        Sends an outstanding invoice reminder email to the first billing
        contact configured on the brand. The email includes open invoices and
        total due amount. On success the API stores lastDueEmailDate in the
        brand settings. Requires full billings permission with value
        2.
      operationId: sendBillingDueEmail
      x-admin-api-resource: billings
      x-admin-api-permission: 2
      parameters:
        - $ref: "#/components/parameters/BrandID"
      responses:
        "200":
          $ref: "#/components/responses/ApiEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/admin-api/billing/invoices:
    get:
      tags:
        - Billings
      summary: List billing invoices
      description: >
        Lists invoices for the brand billing account. Response data includes
        lastDueEmailDate and an invoices array. Each invoice entry includes
        coupon reference, status, amount due, amount remaining, currency, due
        date, created timestamp, invoice ID, invoice PDF, invoice number, and
        hosted invoice URL. Requires billings permission with value 1 or 2.
      operationId: listBillingInvoices
      x-admin-api-resource: billings
      x-admin-api-permission: 1
      parameters:
        - $ref: "#/components/parameters/BrandID"
      responses:
        "200":
          $ref: "#/components/responses/BillingInvoicesEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
components:
  securitySchemes:
    AdminApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: >
        Admin API key generated from Settings > API Key. The key is only shown
        once at creation time. Store it securely and send it on every request
        in the X-API-Key header.
  parameters:
    BrandID:
      name: brand-ID
      in: header
      description: >
        Target brand identifier. The API key must be valid for this brand. The
        value identifies the brand used by the EasySignage Admin API.
      required: true
      schema:
        type: string
    Email:
      name: email
      in: path
      description: User account email address. Email values are validated by the API and are usually lower-cased before writes.
      required: true
      schema:
        type: string
        format: email
    Subuser:
      name: subuser
      in: path
      description: Sub-user email address to remove from a parent user's sub-user list.
      required: true
      schema:
        type: string
        format: email
    Coupon:
      name: coupon
      in: path
      description: Coupon ID, or a comma-separated list of coupon IDs for invoice operations.
      required: true
      schema:
        type: string
    CouponID:
      name: coupon_id
      in: path
      description: Coupon ID to assign to a user.
      required: true
      schema:
        type: string
    ID:
      name: id
      in: path
      description: Resource identifier from the relevant route, such as a coupon ID, subscription-backed coupon ID, or player ID.
      required: true
      schema:
        type: string
    Tag:
      name: tag
      in: path
      description: Coupon tag value.
      required: true
      schema:
        type: string
    UserStatus:
      name: status
      in: path
      description: >
        User status action. The API accepts activate to enable a
        user and disable to disable a user.
      required: true
      schema:
        type: string
        enum:
          - activate
          - disable
    AutoChargeValue:
      name: value
      in: path
      description: Invoice auto-charge flag. 1 enables auto-charge and 0 disables it.
      required: true
      schema:
        type: integer
        enum:
          - 0
          - 1
  requestBodies:
    GenericObjectBody:
      description: >
        JSON object passed to the API. See each endpoint description for the
        required and optional field names.
      required: true
      content:
        application/json:
          schema:
            type: object
            additionalProperties: true
          examples:
            create_user:
              summary: Create user
              value:
                email: user@example.com
                password: temporary-password
                name: Example User
                organization: Example Pty Ltd
            update_player_auto_update:
              summary: Update player auto-update setting
              value:
                autoUpdate: true
            create_coupon:
              summary: Create coupon
              value:
                planID: plan_123
                qty: 1
                name: Example coupon
                screenQty: 1
                note: Customer purchase order reference
  responses:
    ApiEnvelope:
      description: >
        Standard EasySignage Admin response envelope. A successful request returns
        status true and endpoint-specific data. Some validation or business
        rule failures are also returned with HTTP 200, status false, and an
        error_msg value that explains what the client should correct.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ApiEnvelope"
          examples:
            success:
              summary: Successful operation
              value:
                status: true
                error_msg: ""
                data: null
            business_error:
              summary: Request processed but rejected by a business rule
              value:
                status: false
                error_msg: invalid_email
                data: null
    UserListEnvelope:
      description: User list response.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/UserListEnvelope"
          examples:
            success:
              value:
                status: true
                error_msg: ""
                data:
                  - Email: user@example.com
                    brand: next
                    country: AU
                    createdAt: "2026-05-23T09:00:00Z"
                    displayCount: 3
                    freeLicences: 0
                    lastSeen: "2026-05-23T10:15:00Z"
                    licences: 3
                    organization: Example Pty Ltd
                    paidLicences: 3
                    totalStorage: 1.2 GB
                    updatedAt: "2026-05-23T10:15:00Z"
    CouponListEnvelope:
      description: Coupon list response.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/CouponListEnvelope"
          examples:
            success:
              value:
                status: true
                error_msg: ""
                data:
                  - id: coupon_123
                    name: Example coupon
                    amount_off: 800
                    currency: usd
                    duration: once
                    livemode: true
                    max_redemptions: 1
                    metadata:
                      brand: next
                      plan: pro
                      qty: "1"
                    times_redeemed: 0
                    valid: true
    PlayerListEnvelope:
      description: Player list response.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/PlayerListEnvelope"
          examples:
            success:
              value:
                status: true
                error_msg: ""
                data:
                  - id: player_123
                    account: user@example.com
                    brand_id: next
                    name: Lobby display
                    addedAt: "2026-05-23T09:00:00Z"
                    auto_update_disabled: false
                    online: true
    AccountPlayerSummaryEnvelope:
      description: Account summary response.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/AccountPlayerSummaryEnvelope"
          examples:
            success:
              value:
                status: true
                error_msg: ""
                data:
                  count: 10
                  online: 7
                  offline: 3
                  licence: 10
                  expired: 0
                  paid: 10
                  Users:
                    user@example.com:
                      count: 2
                      online: 1
                      offline: 1
                      licence: 2
                      expired: 0
                      paid: 2
    BillingCustomerEnvelope:
      description: Billing customer response.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/BillingCustomerEnvelope"
          examples:
            success:
              value:
                status: true
                error_msg: ""
                data:
                  id: cus_example123
                  email: billing@example.com
                  name: Example Pty Ltd
                  currency: usd
                  balance: 0
                  delinquent: false
                  created: 1779365417
    BillingBrandEnvelope:
      description: Billing brand response.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/BillingBrandEnvelope"
          examples:
            success:
              value:
                status: true
                error_msg: ""
                data: next
    BillingInvoicesEnvelope:
      description: Billing invoices response.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/BillingInvoicesEnvelope"
          examples:
            success:
              value:
                status: true
                error_msg: ""
                data:
                  lastDueEmailDate: 21-May-2026
                  invoices:
                    - AmountDue: 800
                      AmountRemaining: 800
                      Coupons: coupon_123
                      Created: 1779365417
                      Currency: usd
                      DueDate: 1779970216
                      HostedInvoiceURL: https://invoice.example.com/i/example
                      ID: in_example123
                      InvoicePDF: https://invoice.example.com/i/example/pdf
                      Number: A8341029-0056
                      Status: open
    BadRequest:
      description: >
        Bad request. The request could not be accepted because required data
        was missing, malformed, or not valid for the operation. Validation
        failures that are handled by the operation may instead return HTTP 200
        with status false and an error_msg value. The response body may be
        empty.
    Forbidden:
      description: >
        Forbidden. Returned when the API key is missing, invalid, not valid
        for the requested brand, or does not include the permission required by
        the endpoint. The response body is empty.
    NotFound:
      description: >
        Not found. Returned when the endpoint path or HTTP method is not
        available. The response body is empty.
  schemas:
    ApiEnvelope:
      type: object
      description: Standard response wrapper returned by the EasySignage Admin API.
      required:
        - status
        - error_msg
        - data
      properties:
        status:
          type: boolean
          description: True when the operation completed successfully.
        error_msg:
          type: string
          description: Empty on success; contains an error string when status is false.
        data:
          description: Endpoint-specific payload, or null when the endpoint has no payload.
          nullable: true
          oneOf:
            - type: object
              additionalProperties: true
            - type: array
              items: {}
            - type: string
            - type: number
            - type: boolean
    UserListEnvelope:
      allOf:
        - $ref: "#/components/schemas/ApiEnvelope"
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: "#/components/schemas/UserRecord"
    CouponListEnvelope:
      allOf:
        - $ref: "#/components/schemas/ApiEnvelope"
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: "#/components/schemas/Coupon"
    PlayerListEnvelope:
      allOf:
        - $ref: "#/components/schemas/ApiEnvelope"
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: "#/components/schemas/Player"
    AccountPlayerSummaryEnvelope:
      allOf:
        - $ref: "#/components/schemas/ApiEnvelope"
        - type: object
          properties:
            data:
              $ref: "#/components/schemas/AccountPlayerSummary"
    BillingCustomerEnvelope:
      allOf:
        - $ref: "#/components/schemas/ApiEnvelope"
        - type: object
          properties:
            data:
              $ref: "#/components/schemas/BillingCustomer"
    BillingBrandEnvelope:
      allOf:
        - $ref: "#/components/schemas/ApiEnvelope"
        - type: object
          properties:
            data:
              type: string
              description: Brand identifier used by the billing account.
    BillingInvoicesEnvelope:
      allOf:
        - $ref: "#/components/schemas/ApiEnvelope"
        - type: object
          properties:
            data:
              $ref: "#/components/schemas/BillingInvoices"
    UserRecord:
      type: object
      description: User account summary returned by the users endpoint.
      additionalProperties: true
      properties:
        Email:
          type: string
          format: email
        brand:
          type: string
        country:
          type: string
        createdAt:
          type: string
          format: date-time
          nullable: true
        displayCount:
          type: integer
        freeLicences:
          type: integer
        lastSeen:
          type: string
          format: date-time
          nullable: true
        licences:
          type: integer
        organization:
          type: string
          nullable: true
        paidLicences:
          type: integer
        totalStorage:
          type: string
        updatedAt:
          type: string
          format: date-time
          nullable: true
    Coupon:
      type: object
      description: Coupon record returned by the coupons endpoint.
      additionalProperties: true
      properties:
        id:
          type: string
        name:
          type: string
        amount_off:
          type: integer
          nullable: true
        currency:
          type: string
        duration:
          type: string
        duration_in_months:
          type: integer
          nullable: true
        livemode:
          type: boolean
        max_redemptions:
          type: integer
          nullable: true
        metadata:
          type: object
          additionalProperties: true
        percent_off:
          type: number
          nullable: true
        redeem_by:
          type: integer
          nullable: true
        times_redeemed:
          type: integer
        valid:
          type: boolean
    Player:
      type: object
      description: Player record returned by the players endpoint.
      additionalProperties: true
      properties:
        id:
          type: string
        account:
          type: string
          format: email
        brand_id:
          type: string
        name:
          type: string
        addedAt:
          type: string
          format: date-time
          nullable: true
        auto_update_disabled:
          type: boolean
        online:
          type: boolean
    AccountPlayerSummary:
      type: object
      required:
        - count
        - online
        - offline
        - licence
        - expired
        - paid
        - Users
      properties:
        count:
          type: integer
        online:
          type: integer
        offline:
          type: integer
        licence:
          type: integer
        expired:
          type: integer
        paid:
          type: integer
        Users:
          type: object
          description: Per-user player summary keyed by user email address.
          additionalProperties:
            $ref: "#/components/schemas/PlayerSummaryCounts"
    PlayerSummaryCounts:
      type: object
      properties:
        count:
          type: integer
        online:
          type: integer
        offline:
          type: integer
        licence:
          type: integer
        expired:
          type: integer
        paid:
          type: integer
    BillingCustomer:
      type: object
      description: Billing customer details for the requested brand.
      additionalProperties: true
      properties:
        id:
          type: string
        email:
          type: string
          format: email
          nullable: true
        name:
          type: string
          nullable: true
        currency:
          type: string
          nullable: true
        balance:
          type: integer
        delinquent:
          type: boolean
        created:
          type: integer
          description: Unix timestamp.
    BillingInvoices:
      type: object
      properties:
        lastDueEmailDate:
          type: string
          nullable: true
        invoices:
          type: array
          items:
            $ref: "#/components/schemas/BillingInvoice"
    BillingInvoice:
      type: object
      properties:
        AmountDue:
          type: integer
        AmountRemaining:
          type: integer
        Coupons:
          type: string
        Created:
          type: integer
          description: Unix timestamp.
        Currency:
          type: string
        DueDate:
          type: integer
          description: Unix timestamp.
        HostedInvoiceURL:
          type: string
          format: uri
        ID:
          type: string
        InvoicePDF:
          type: string
          format: uri
        Number:
          type: string
        Status:
          type: string
