openapi: 3.0.3 info: title: 'Licenseshipper API Documentation' description: 'The LicenseShipper API enables developers and partners to securely manage, deliver, and track digital product licenses across multiple sales channels.' version: 1.0.0 servers: - url: 'https://app.licenseshipper.com' tags: - name: 'Activation Guides' description: "Manage activation guides for your products.\n\nA product can have at most one guide.\nRecommended \"type\" values: text | html | pdf_url" - name: Licenses description: "API endpoints for managing license keys.\n\nStatus legend:\n- 0 = available\n- 1 = assigned\n- 2 = redeemed" - name: Products description: 'API endpoints for managing your products.' - name: Suppliers description: 'API endpoints for managing suppliers.' - name: Utility description: '' components: securitySchemes: default: type: apiKey name: X-API-KEY in: header description: 'You can retrieve your token by visiting your dashboard and clicking Generate API token.' security: - default: [] paths: /api/activation-guides: get: summary: 'List activation guides' operationId: listActivationGuides description: 'Returns guides for the authenticated user with filters.' parameters: - in: query name: q description: 'Search in content (LIKE).' example: '"Windows"' required: false schema: type: string description: 'Search in content (LIKE).' example: '"Windows"' nullable: false - in: query name: product_id description: 'Filter by product.' example: 12 required: false schema: type: integer description: 'Filter by product.' example: 12 nullable: false - in: query name: type description: 'Filter by type (text|html|pdf_url).' example: html required: false schema: type: string description: 'Filter by type (text|html|pdf_url).' example: html nullable: false - in: query name: per_page description: 'Items per page (1..100, default 15).' example: 25 required: false schema: type: integer description: 'Items per page (1..100, default 15).' example: 25 nullable: false - in: query name: sort description: 'Sort "field,dir" where field in (id,created_at,updated_at).' example: 'created_at,desc' required: false schema: type: string description: 'Sort "field,dir" where field in (id,created_at,updated_at).' example: 'created_at,desc' nullable: false - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Activation guide list retrieved successfully.' data: guides: - id: 1 product_id: 12 type: html content: '
Steps...
' meta: current_page: 1 per_page: 15 total: 1 last_page: 1 properties: success: type: boolean example: true message: type: string example: 'Activation guide list retrieved successfully.' data: type: object properties: guides: type: array example: - id: 1 product_id: 12 type: html content: 'Steps...
' items: type: object properties: id: type: integer example: 1 product_id: type: integer example: 12 type: type: string example: html content: type: string example: 'Steps...
' meta: type: object properties: current_page: type: integer example: 1 per_page: type: integer example: 15 total: type: integer example: 1 last_page: type: integer example: 1 tags: - 'Activation Guides' post: summary: 'Create activation guide' operationId: createActivationGuide description: "Creates a guide for a product owned by the user.\nEnforces one guide per product." parameters: - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 201: description: '' content: application/json: schema: type: object example: success: true message: 'Activation guide created successfully.' data: id: 1 product_id: 12 type: html meta: [] properties: success: type: boolean example: true message: type: string example: 'Activation guide created successfully.' data: type: object properties: id: type: integer example: 1 product_id: type: integer example: 12 type: type: string example: html meta: type: array example: [] tags: - 'Activation Guides' requestBody: required: true content: application/json: schema: type: object properties: product_id: type: integer description: 'Product ID you own.' example: 12 nullable: false type: type: string description: 'One of text|html|pdf_url.' example: html nullable: false content: type: string description: 'The guide body or URL (if pdf_url).' example: '"Do this...
"' nullable: false required: - product_id - type - content '/api/activation-guides/{guide_id}': get: summary: 'Show activation guide' operationId: showActivationGuide description: '' parameters: - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Activation guide details retrieved successfully.' data: id: 1 product_id: 12 type: html content: '...
' meta: [] properties: success: type: boolean example: true message: type: string example: 'Activation guide details retrieved successfully.' data: type: object properties: id: type: integer example: 1 product_id: type: integer example: 12 type: type: string example: html content: type: string example: '...
' meta: type: array example: [] tags: - 'Activation Guides' put: summary: 'Update activation guide' operationId: updateActivationGuide description: '' parameters: - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Activation guide updated successfully.' data: id: 1 type: html meta: [] properties: success: type: boolean example: true message: type: string example: 'Activation guide updated successfully.' data: type: object properties: id: type: integer example: 1 type: type: string example: html meta: type: array example: [] tags: - 'Activation Guides' requestBody: required: false content: application/json: schema: type: object properties: product_id: type: integer description: 'Optional, must be your product and unused by another guide.' example: 17 nullable: false type: type: string description: 'Optional. One of text|html|pdf_url.' example: consequatur nullable: false content: type: string description: Optional. example: consequatur nullable: false patch: summary: 'Update activation guide' operationId: updateActivationGuide description: '' parameters: - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Activation guide updated successfully.' data: id: 1 type: html meta: [] properties: success: type: boolean example: true message: type: string example: 'Activation guide updated successfully.' data: type: object properties: id: type: integer example: 1 type: type: string example: html meta: type: array example: [] tags: - 'Activation Guides' requestBody: required: false content: application/json: schema: type: object properties: product_id: type: integer description: 'Optional, must be your product and unused by another guide.' example: 17 nullable: false type: type: string description: 'Optional. One of text|html|pdf_url.' example: consequatur nullable: false content: type: string description: Optional. example: consequatur nullable: false delete: summary: 'Delete activation guide' operationId: deleteActivationGuide description: '' parameters: - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Activation guide deleted successfully.' data: [] meta: [] properties: success: type: boolean example: true message: type: string example: 'Activation guide deleted successfully.' data: type: array example: [] meta: type: array example: [] tags: - 'Activation Guides' parameters: - in: path name: guide_id description: 'The ID of the guide.' example: 17 required: true schema: type: integer - in: path name: guide description: 'Guide ID.' example: 17 required: true schema: type: integer '/api/products/{product_id}/activation-guide': get: summary: 'Get activation guide by product' operationId: getActivationGuideByProduct description: 'Convenience endpoint to fetch a guide via product ID.' parameters: - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Activation guide retrieved successfully.' data: id: 1 product_id: 12 type: html meta: [] properties: success: type: boolean example: true message: type: string example: 'Activation guide retrieved successfully.' data: type: object properties: id: type: integer example: 1 product_id: type: integer example: 12 type: type: string example: html meta: type: array example: [] 404: description: '' content: application/json: schema: type: object example: success: false message: 'Activation guide not found.' data: [] meta: [] properties: success: type: boolean example: false message: type: string example: 'Activation guide not found.' data: type: array example: [] meta: type: array example: [] tags: - 'Activation Guides' parameters: - in: path name: product_id description: 'The ID of the product.' example: 17 required: true schema: type: integer - in: path name: product description: 'Product ID.' example: 17 required: true schema: type: integer /api/licenses: get: summary: 'List licenses' operationId: listLicenses description: "Returns licenses for the authenticated user with filtering, sorting, and pagination.\nLicense keys are masked in list results." parameters: - in: query name: status description: 'Filter by status (0,1,2).' example: 0 required: false schema: type: integer description: 'Filter by status (0,1,2).' example: 0 nullable: false - in: query name: product_id description: 'Filter by product.' example: 12 required: false schema: type: integer description: 'Filter by product.' example: 12 nullable: false - in: query name: supplier_id description: 'Filter by supplier.' example: 3 required: false schema: type: integer description: 'Filter by supplier.' example: 3 nullable: false - in: query name: order_email description: 'Filter by customer email (contains).' example: user@example.com required: false schema: type: string description: 'Filter by customer email (contains).' example: user@example.com nullable: false - in: query name: order_id description: 'Filter by external order id (contains).' example: '100045' required: false schema: type: string description: 'Filter by external order id (contains).' example: '100045' nullable: false - in: query name: key_ends description: 'Optional. Match last N chars of key (masked search).' example: ABC123 required: false schema: type: string description: 'Optional. Match last N chars of key (masked search).' example: ABC123 nullable: false - in: query name: date_from description: 'date ISO date for created_at >=.' example: '2025-08-01' required: false schema: type: string description: 'date ISO date for created_at >=.' example: '2025-08-01' nullable: false - in: query name: date_to description: 'date ISO date for created_at <=.' example: '2025-08-13' required: false schema: type: string description: 'date ISO date for created_at <=.' example: '2025-08-13' nullable: false - in: query name: per_page description: 'Items per page (1..100). Defaults to 15.' example: 25 required: false schema: type: integer description: 'Items per page (1..100). Defaults to 15.' example: 25 nullable: false - in: query name: sort description: 'Sort "field,dir" where field in (id, price, created_at, redeemed_at).' example: 'created_at,desc' required: false schema: type: string description: 'Sort "field,dir" where field in (id, price, created_at, redeemed_at).' example: 'created_at,desc' nullable: false - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'License list retrieved successfully.' data: licenses: - id: 1 product_id: 12 supplier_id: 3 masked_key: ABCD••••••••••1234 price: '9.99' status: 0 order_id: null order_email: null source: Manual redeemed_at: null created_at: '2025-08-13T10:20:00Z' meta: current_page: 1 per_page: 15 total: 1 last_page: 1 properties: success: type: boolean example: true message: type: string example: 'License list retrieved successfully.' data: type: object properties: licenses: type: array example: - id: 1 product_id: 12 supplier_id: 3 masked_key: ABCD••••••••••1234 price: '9.99' status: 0 order_id: null order_email: null source: Manual redeemed_at: null created_at: '2025-08-13T10:20:00Z' items: type: object properties: id: type: integer example: 1 product_id: type: integer example: 12 supplier_id: type: integer example: 3 masked_key: type: string example: ABCD••••••••••1234 price: type: string example: '9.99' status: type: integer example: 0 order_id: type: string example: null order_email: type: string example: null source: type: string example: Manual redeemed_at: type: string example: null created_at: type: string example: '2025-08-13T10:20:00Z' meta: type: object properties: current_page: type: integer example: 1 per_page: type: integer example: 15 total: type: integer example: 1 last_page: type: integer example: 1 tags: - Licenses post: summary: 'Create license(s)' operationId: createLicenses description: "Create a single license or bulk create using \"items\".\nWhen bulk, each item must contain at least product_id and key." parameters: - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 201: description: '' content: application/json: schema: type: object example: success: true message: 'License(s) created successfully.' data: created: - id: 10 masked_key: ABCD••••••••••1234 status: 0 meta: [] properties: success: type: boolean example: true message: type: string example: 'License(s) created successfully.' data: type: object properties: created: type: array example: - id: 10 masked_key: ABCD••••••••••1234 status: 0 items: type: object properties: id: type: integer example: 10 masked_key: type: string example: ABCD••••••••••1234 status: type: integer example: 0 meta: type: array example: [] tags: - Licenses requestBody: required: true content: application/json: schema: type: object properties: product_id: type: integer description: 'When creating a single license.' example: 17 nullable: false supplier_id: type: integer description: 'optional Supplier reference.' example: 17 nullable: true key: type: string description: 'The license key value.' example: consequatur nullable: false price: type: number description: 'optional Price paid for the key.' example: 9.99 nullable: true source: type: string description: 'optional Origin label (WooCommerce, API, Manual).' example: consequatur nullable: true status: type: integer description: 'optional 0|1|2. Default: 0.' example: 17 nullable: true items: type: array description: 'optional For bulk creates.' example: - product_id: 1 key: ABC price: 0 items: type: string required: - product_id - key '/api/licenses/{license_id}': get: summary: 'Show license (full key)' operationId: showLicensefullKey description: 'Returns a single license. The **full key** is included here.' parameters: - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'License details retrieved successfully.' data: id: 1 product_id: 12 supplier_id: 3 key: FULL-KEY-VALUE-HERE price: '9.99' status: 0 order_id: null order_email: null source: Manual redeemed_at: null meta: [] properties: success: type: boolean example: true message: type: string example: 'License details retrieved successfully.' data: type: object properties: id: type: integer example: 1 product_id: type: integer example: 12 supplier_id: type: integer example: 3 key: type: string example: FULL-KEY-VALUE-HERE price: type: string example: '9.99' status: type: integer example: 0 order_id: type: string example: null order_email: type: string example: null source: type: string example: Manual redeemed_at: type: string example: null meta: type: array example: [] tags: - Licenses put: summary: 'Update license' operationId: updateLicense description: '' parameters: - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'License updated successfully.' data: id: 1 status: 1 meta: [] properties: success: type: boolean example: true message: type: string example: 'License updated successfully.' data: type: object properties: id: type: integer example: 1 status: type: integer example: 1 meta: type: array example: [] tags: - Licenses requestBody: required: false content: application/json: schema: type: object properties: product_id: type: integer description: 'optional Must belong to the user.' example: 17 nullable: false supplier_id: type: integer description: optional example: 17 nullable: true key: type: string description: optional example: consequatur nullable: false price: type: number description: optional example: 11613.31890586 nullable: false status: type: integer description: 'optional 0|1|2' example: 17 nullable: false order_id: type: string description: optional example: consequatur nullable: true order_email: type: string description: optional example: qkunze@example.com nullable: true source: type: string description: optional example: consequatur nullable: true redeemed_at: type: datetime description: 'optional ISO8601, for admins/backfills.' example: consequatur nullable: true patch: summary: 'Update license' operationId: updateLicense description: '' parameters: - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'License updated successfully.' data: id: 1 status: 1 meta: [] properties: success: type: boolean example: true message: type: string example: 'License updated successfully.' data: type: object properties: id: type: integer example: 1 status: type: integer example: 1 meta: type: array example: [] tags: - Licenses requestBody: required: false content: application/json: schema: type: object properties: product_id: type: integer description: 'optional Must belong to the user.' example: 17 nullable: false supplier_id: type: integer description: optional example: 17 nullable: true key: type: string description: optional example: consequatur nullable: false price: type: number description: optional example: 11613.31890586 nullable: false status: type: integer description: 'optional 0|1|2' example: 17 nullable: false order_id: type: string description: optional example: consequatur nullable: true order_email: type: string description: optional example: qkunze@example.com nullable: true source: type: string description: optional example: consequatur nullable: true redeemed_at: type: datetime description: 'optional ISO8601, for admins/backfills.' example: consequatur nullable: true delete: summary: 'Delete license' operationId: deleteLicense description: '' parameters: - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'License deleted successfully.' data: [] meta: [] properties: success: type: boolean example: true message: type: string example: 'License deleted successfully.' data: type: array example: [] meta: type: array example: [] tags: - Licenses parameters: - in: path name: license_id description: 'The ID of the license.' example: 17 required: true schema: type: integer - in: path name: license description: 'The license ID.' example: 17 required: true schema: type: integer '/api/licenses/{license_id}/assign': post: summary: 'Assign a license' operationId: assignALicense description: 'Transition to **assigned** (1). Typically used when linking a license to an order.' parameters: - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'License assigned successfully.' data: id: 1 status: 1 order_id: '100045' meta: [] properties: success: type: boolean example: true message: type: string example: 'License assigned successfully.' data: type: object properties: id: type: integer example: 1 status: type: integer example: 1 order_id: type: string example: '100045' meta: type: array example: [] tags: - Licenses requestBody: required: false content: application/json: schema: type: object properties: order_id: type: string description: 'optional External order id.' example: consequatur nullable: true order_email: type: string description: 'optional Customer email.' example: qkunze@example.com nullable: true source: type: string description: 'optional Origin label.' example: WooCommerce nullable: true parameters: - in: path name: license_id description: 'The ID of the license.' example: 17 required: true schema: type: integer - in: path name: license description: 'The license ID.' example: 17 required: true schema: type: integer '/api/licenses/{license_id}/redeem': post: summary: 'Redeem a license' operationId: redeemALicense description: 'Transition to **redeemed** (2) and set `redeemed_at`.' parameters: - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'License redeemed successfully.' data: id: 1 status: 2 redeemed_at: '2025-08-13T11:12:13Z' meta: [] properties: success: type: boolean example: true message: type: string example: 'License redeemed successfully.' data: type: object properties: id: type: integer example: 1 status: type: integer example: 2 redeemed_at: type: string example: '2025-08-13T11:12:13Z' meta: type: array example: [] tags: - Licenses requestBody: required: false content: application/json: schema: type: object properties: redeemed_at: type: datetime description: 'optional ISO8601 (defaults to now).' example: consequatur nullable: false parameters: - in: path name: license_id description: 'The ID of the license.' example: 17 required: true schema: type: integer - in: path name: license description: 'The license ID.' example: 17 required: true schema: type: integer '/api/licenses/{license_id}/unassign': post: summary: 'Unassign a license' operationId: unassignALicense description: 'Reset a license back to **available** (0). Clears order fields and `redeemed_at`.' parameters: - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'License unassigned successfully.' data: id: 1 status: 0 meta: [] properties: success: type: boolean example: true message: type: string example: 'License unassigned successfully.' data: type: object properties: id: type: integer example: 1 status: type: integer example: 0 meta: type: array example: [] tags: - Licenses parameters: - in: path name: license_id description: 'The ID of the license.' example: 17 required: true schema: type: integer - in: path name: license description: 'The license ID.' example: 17 required: true schema: type: integer /api/license/fetch: post: summary: 'Fetch licenses' operationId: fetchLicenses description: "Assigns license keys for a given product SKU if the subscription is valid,\nblacklist rules pass, and stock is available." parameters: - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: Success content: application/json: schema: type: object example: success: true message: 'All licenses assigned successfully.' data: product: name: 'Windows 11 Pro' sku: WIN11-PRO-KEY download_link: 'https://example.com/dl' activation_guide: 'https://app.example.com/storage/temp-guides/guide.pdf' licenses: - license_id: 1 key: AAAA-BBBB-CCCC-DDDD price: 14.99 meta: delivered_total: 1 properties: success: type: boolean example: true message: type: string example: 'All licenses assigned successfully.' data: type: object properties: product: type: object properties: name: type: string example: 'Windows 11 Pro' sku: type: string example: WIN11-PRO-KEY download_link: type: string example: 'https://example.com/dl' activation_guide: type: string example: 'https://app.example.com/storage/temp-guides/guide.pdf' licenses: type: array example: - license_id: 1 key: AAAA-BBBB-CCCC-DDDD price: 14.99 items: type: object properties: license_id: type: integer example: 1 key: type: string example: AAAA-BBBB-CCCC-DDDD price: type: number example: 14.99 meta: type: object properties: delivered_total: type: integer example: 1 400: description: 'Already delivered' content: application/json: schema: type: object example: success: false message: 'This order has already received licenses.' meta: already_delivered: 1 properties: success: type: boolean example: false message: type: string example: 'This order has already received licenses.' meta: type: object properties: already_delivered: type: integer example: 1 402: description: 'Subscription missing' content: application/json: schema: type: object example: success: false message: 'Subscription missing' properties: success: type: boolean example: false message: type: string example: 'Subscription missing' 403: description: Blacklisted content: application/json: schema: type: object example: success: false message: 'Request blocked by Blacklist Manager.' meta: block_id: 12 scope: global properties: success: type: boolean example: false message: type: string example: 'Request blocked by Blacklist Manager.' meta: type: object properties: block_id: type: integer example: 12 scope: type: string example: global 404: description: 'Product not found' content: application/json: schema: type: object example: success: false message: 'Product not found or unauthorized.' properties: success: type: boolean example: false message: type: string example: 'Product not found or unauthorized.' 422: description: 'Validation error' content: application/json: schema: type: object example: success: false message: 'Validation failed.' errors: sku: - 'The sku field is required.' properties: success: type: boolean example: false message: type: string example: 'Validation failed.' errors: type: object properties: sku: type: array example: - 'The sku field is required.' items: type: string 429: description: 'Monthly quota reached' content: application/json: schema: type: object example: success: false message: 'Monthly quota reached. Upgrade plan or wait until next month.' properties: success: type: boolean example: false message: type: string example: 'Monthly quota reached. Upgrade plan or wait until next month.' tags: - Licenses requestBody: required: true content: application/json: schema: type: object properties: sku: type: string description: 'The product SKU.' example: WIN11-PRO-KEY nullable: false quantity: type: integer description: 'Minimum: 1.' example: 2 nullable: false order_id: type: string description: 'Merchant order ID.' example: WC-102938 nullable: false order_email: type: string description: 'A valid email.' example: buyer@example.com nullable: false source: type: string description: 'Source system label.' example: woocommerce nullable: false required: - sku - quantity - order_id - order_email - source /api/products: get: summary: 'List products' operationId: listProducts description: "Returns the authenticated user's active products." parameters: - in: query name: q description: 'Optional. Search term for name or SKU.' example: consequatur required: false schema: type: string description: 'Optional. Search term for name or SKU.' example: consequatur nullable: false - in: query name: active description: 'Optional. Filter by active status (1 or 0).' example: false required: false schema: type: boolean description: 'Optional. Filter by active status (1 or 0).' example: false nullable: false - in: query name: sort description: 'Optional. Sort field and direction (e.g. name,asc).' example: consequatur required: false schema: type: string description: 'Optional. Sort field and direction (e.g. name,asc).' example: consequatur nullable: false - in: query name: per_page description: 'Optional. Results per page (default: 15).' example: 17 required: false schema: type: integer description: 'Optional. Results per page (default: 15).' example: 17 nullable: false - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Product list retrieved successfully.' data: products: - id: 1 name: 'Windows 11 Pro' sku: WIN11-PRO-KEY meta: count: 1 properties: success: type: boolean example: true message: type: string example: 'Product list retrieved successfully.' data: type: object properties: products: type: array example: - id: 1 name: 'Windows 11 Pro' sku: WIN11-PRO-KEY items: type: object properties: id: type: integer example: 1 name: type: string example: 'Windows 11 Pro' sku: type: string example: WIN11-PRO-KEY meta: type: object properties: count: type: integer example: 1 tags: - Products post: summary: 'Create product' operationId: createProduct description: 'Adds a new product for the authenticated user.' parameters: - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 201: description: '' content: application/json: schema: type: object example: success: true message: 'Product created successfully.' data: id: 1 name: 'Windows 11 Pro' sku: WIN11-PRO-KEY meta: [] properties: success: type: boolean example: true message: type: string example: 'Product created successfully.' data: type: object properties: id: type: integer example: 1 name: type: string example: 'Windows 11 Pro' sku: type: string example: WIN11-PRO-KEY meta: type: array example: [] tags: - Products requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: 'Product name.' example: consequatur nullable: false sku: type: string description: 'Unique SKU code.' example: consequatur nullable: false download_link: type: string description: 'Optional. Direct download URL.' example: consequatur nullable: true active: type: boolean description: 'Optional. Default: true.' example: false nullable: false required: - name - sku '/api/products/{product_id}': get: summary: 'Show product details' operationId: showProductDetails description: 'Displays full product information by ID.' parameters: - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Product details retrieved successfully.' data: id: 1 name: 'Windows 11 Pro' sku: WIN11-PRO-KEY download_link: 'https://example.com/file.zip' active: true meta: [] properties: success: type: boolean example: true message: type: string example: 'Product details retrieved successfully.' data: type: object properties: id: type: integer example: 1 name: type: string example: 'Windows 11 Pro' sku: type: string example: WIN11-PRO-KEY download_link: type: string example: 'https://example.com/file.zip' active: type: boolean example: true meta: type: array example: [] tags: - Products put: summary: 'Update product' operationId: updateProduct description: '' parameters: - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Product updated successfully.' data: id: 1 name: 'Windows 11 Pro' sku: WIN11-PRO-KEY meta: [] properties: success: type: boolean example: true message: type: string example: 'Product updated successfully.' data: type: object properties: id: type: integer example: 1 name: type: string example: 'Windows 11 Pro' sku: type: string example: WIN11-PRO-KEY meta: type: array example: [] tags: - Products requestBody: required: false content: application/json: schema: type: object properties: name: type: string description: 'Optional. Product name.' example: consequatur nullable: false sku: type: string description: 'Optional. Unique SKU.' example: consequatur nullable: false download_link: type: string description: 'Optional. Direct download URL.' example: consequatur nullable: true active: type: boolean description: Optional. example: false nullable: false patch: summary: 'Update product' operationId: updateProduct description: '' parameters: - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Product updated successfully.' data: id: 1 name: 'Windows 11 Pro' sku: WIN11-PRO-KEY meta: [] properties: success: type: boolean example: true message: type: string example: 'Product updated successfully.' data: type: object properties: id: type: integer example: 1 name: type: string example: 'Windows 11 Pro' sku: type: string example: WIN11-PRO-KEY meta: type: array example: [] tags: - Products requestBody: required: false content: application/json: schema: type: object properties: name: type: string description: 'Optional. Product name.' example: consequatur nullable: false sku: type: string description: 'Optional. Unique SKU.' example: consequatur nullable: false download_link: type: string description: 'Optional. Direct download URL.' example: consequatur nullable: true active: type: boolean description: Optional. example: false nullable: false delete: summary: 'Delete product' operationId: deleteProduct description: '' parameters: - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Product deleted successfully.' data: [] meta: [] properties: success: type: boolean example: true message: type: string example: 'Product deleted successfully.' data: type: array example: [] meta: type: array example: [] tags: - Products parameters: - in: path name: product_id description: 'The ID of the product.' example: 17 required: true schema: type: integer - in: path name: id description: 'The ID of the product.' example: 17 required: true schema: type: integer '/api/products/{product_id}/licenses': get: summary: 'List licenses for a product' operationId: listLicensesForAProduct description: "Returns licenses linked to a specific product you own.\nLicense keys are masked in the list for security.\nUse the `GET /licenses/{license}` endpoint to see the full key." parameters: - in: query name: status description: 'Optional. Filter by status (0=available, 1=assigned, 2=redeemed).' example: 0 required: false schema: type: integer description: 'Optional. Filter by status (0=available, 1=assigned, 2=redeemed).' example: 0 nullable: false - in: query name: per_page description: 'Optional. Items per page (1..100, default 15).' example: 25 required: false schema: type: integer description: 'Optional. Items per page (1..100, default 15).' example: 25 nullable: false - in: query name: sort description: 'Optional. Sort "field,dir" where field in (id,price,created_at,redeemed_at).' example: 'created_at,desc' required: false schema: type: string description: 'Optional. Sort "field,dir" where field in (id,price,created_at,redeemed_at).' example: 'created_at,desc' nullable: false - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Product licenses retrieved successfully.' data: licenses: - id: 101 masked_key: ABCD••••••••••1234 price: '9.99' status: 0 order_id: null order_email: null source: Manual redeemed_at: null created_at: '2025-08-13T10:20:00Z' meta: counts: total: 10 available: 6 assigned: 3 redeemed: 1 current_page: 1 per_page: 15 total: 10 last_page: 1 properties: success: type: boolean example: true message: type: string example: 'Product licenses retrieved successfully.' data: type: object properties: licenses: type: array example: - id: 101 masked_key: ABCD••••••••••1234 price: '9.99' status: 0 order_id: null order_email: null source: Manual redeemed_at: null created_at: '2025-08-13T10:20:00Z' items: type: object properties: id: type: integer example: 101 masked_key: type: string example: ABCD••••••••••1234 price: type: string example: '9.99' status: type: integer example: 0 order_id: type: string example: null order_email: type: string example: null source: type: string example: Manual redeemed_at: type: string example: null created_at: type: string example: '2025-08-13T10:20:00Z' meta: type: object properties: counts: type: object properties: total: type: integer example: 10 available: type: integer example: 6 assigned: type: integer example: 3 redeemed: type: integer example: 1 current_page: type: integer example: 1 per_page: type: integer example: 15 total: type: integer example: 10 last_page: type: integer example: 1 tags: - Products parameters: - in: path name: product_id description: 'The ID of the product.' example: 17 required: true schema: type: integer - in: path name: product description: 'The product ID.' example: 12 required: true schema: type: integer '/api/products/sku/{sku}/licenses': get: summary: 'List licenses by SKU' operationId: listLicensesBySKU description: "Returns licenses for a product you own, looked up by SKU.\nLicense keys are masked in the list for security." parameters: - in: query name: status description: 'Optional. Filter by status (0=available, 1=assigned, 2=redeemed).' example: 0 required: false schema: type: integer description: 'Optional. Filter by status (0=available, 1=assigned, 2=redeemed).' example: 0 nullable: false - in: query name: per_page description: 'Optional. Items per page (1..100, default 15).' example: 25 required: false schema: type: integer description: 'Optional. Items per page (1..100, default 15).' example: 25 nullable: false - in: query name: sort description: 'Optional. Sort "field,dir" where field in (id,price,created_at,redeemed_at).' example: 'created_at,desc' required: false schema: type: string description: 'Optional. Sort "field,dir" where field in (id,price,created_at,redeemed_at).' example: 'created_at,desc' nullable: false - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Product licenses (by SKU) retrieved successfully.' data: licenses: [] meta: counts: total: 0 available: 0 assigned: 0 redeemed: 0 current_page: 1 per_page: 15 total: 0 last_page: 1 properties: success: type: boolean example: true message: type: string example: 'Product licenses (by SKU) retrieved successfully.' data: type: object properties: licenses: type: array example: [] meta: type: object properties: counts: type: object properties: total: type: integer example: 0 available: type: integer example: 0 assigned: type: integer example: 0 redeemed: type: integer example: 0 current_page: type: integer example: 1 per_page: type: integer example: 15 total: type: integer example: 0 last_page: type: integer example: 1 tags: - Products parameters: - in: path name: sku description: 'The product SKU.' example: WIN11-PRO-KEY required: true schema: type: string /api/suppliers: get: summary: 'List suppliers' operationId: listSuppliers description: 'Returns suppliers belonging to the authenticated user.' parameters: - in: query name: q description: 'Optional. Search in name or contact.' example: '"Acme"' required: false schema: type: string description: 'Optional. Search in name or contact.' example: '"Acme"' nullable: false - in: query name: status description: 'Optional. 1 or 0.' example: true required: false schema: type: boolean description: 'Optional. 1 or 0.' example: true nullable: false - in: query name: sort description: 'Optional. "field,dir" where field in (id,name,created_at).' example: 'name,asc' required: false schema: type: string description: 'Optional. "field,dir" where field in (id,name,created_at).' example: 'name,asc' nullable: false - in: query name: per_page description: 'Optional. 1..100 (default 15).' example: 25 required: false schema: type: integer description: 'Optional. 1..100 (default 15).' example: 25 nullable: false - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Supplier list retrieved successfully.' data: suppliers: - id: 1 name: 'Acme Keys' contact: sales@acme.tld status: true meta: current_page: 1 per_page: 15 total: 1 last_page: 1 sort: - id - desc properties: success: type: boolean example: true message: type: string example: 'Supplier list retrieved successfully.' data: type: object properties: suppliers: type: array example: - id: 1 name: 'Acme Keys' contact: sales@acme.tld status: true items: type: object properties: id: type: integer example: 1 name: type: string example: 'Acme Keys' contact: type: string example: sales@acme.tld status: type: boolean example: true meta: type: object properties: current_page: type: integer example: 1 per_page: type: integer example: 15 total: type: integer example: 1 last_page: type: integer example: 1 sort: type: array example: - id - desc items: type: string tags: - Suppliers post: summary: 'Create supplier' operationId: createSupplier description: '' parameters: - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 201: description: '' content: application/json: schema: type: object example: success: true message: 'Supplier created successfully.' data: id: 1 name: 'Acme Keys' contact: sales@acme.tld status: true meta: [] properties: success: type: boolean example: true message: type: string example: 'Supplier created successfully.' data: type: object properties: id: type: integer example: 1 name: type: string example: 'Acme Keys' contact: type: string example: sales@acme.tld status: type: boolean example: true meta: type: array example: [] tags: - Suppliers requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: 'Supplier name.' example: 'Acme Keys' nullable: false contact: type: string description: 'Contact email/phone/handle.' example: sales@acme.tld nullable: false status: type: boolean description: 'Optional. Default true.' example: false nullable: false required: - name - contact '/api/suppliers/{supplier_id}': get: summary: 'Show supplier' operationId: showSupplier description: 'Returns a supplier and quick license counts.' parameters: - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Supplier details retrieved successfully.' data: id: 1 name: 'Acme Keys' contact: sales@acme.tld status: true license_counts: total: 20 available: 15 assigned: 3 redeemed: 2 meta: [] properties: success: type: boolean example: true message: type: string example: 'Supplier details retrieved successfully.' data: type: object properties: id: type: integer example: 1 name: type: string example: 'Acme Keys' contact: type: string example: sales@acme.tld status: type: boolean example: true license_counts: type: object properties: total: type: integer example: 20 available: type: integer example: 15 assigned: type: integer example: 3 redeemed: type: integer example: 2 meta: type: array example: [] tags: - Suppliers put: summary: 'Update supplier' operationId: updateSupplier description: '' parameters: - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Supplier updated successfully.' data: id: 1 name: 'Acme Keys' status: true meta: [] properties: success: type: boolean example: true message: type: string example: 'Supplier updated successfully.' data: type: object properties: id: type: integer example: 1 name: type: string example: 'Acme Keys' status: type: boolean example: true meta: type: array example: [] tags: - Suppliers requestBody: required: false content: application/json: schema: type: object properties: name: type: string description: 'Optional. Must be unique per user.' example: consequatur nullable: false contact: type: string description: Optional. example: consequatur nullable: false status: type: boolean description: Optional. example: false nullable: false patch: summary: 'Update supplier' operationId: updateSupplier description: '' parameters: - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Supplier updated successfully.' data: id: 1 name: 'Acme Keys' status: true meta: [] properties: success: type: boolean example: true message: type: string example: 'Supplier updated successfully.' data: type: object properties: id: type: integer example: 1 name: type: string example: 'Acme Keys' status: type: boolean example: true meta: type: array example: [] tags: - Suppliers requestBody: required: false content: application/json: schema: type: object properties: name: type: string description: 'Optional. Must be unique per user.' example: consequatur nullable: false contact: type: string description: Optional. example: consequatur nullable: false status: type: boolean description: Optional. example: false nullable: false delete: summary: 'Delete supplier' operationId: deleteSupplier description: "Note: Existing licenses referencing this supplier will be deleted\nonly if your foreign key is `onDelete('cascade')` on `licenses.supplier_id`." parameters: - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Supplier deleted successfully.' data: [] meta: [] properties: success: type: boolean example: true message: type: string example: 'Supplier deleted successfully.' data: type: array example: [] meta: type: array example: [] tags: - Suppliers parameters: - in: path name: supplier_id description: 'The ID of the supplier.' example: 17 required: true schema: type: integer - in: path name: supplier description: 'Supplier ID.' example: 17 required: true schema: type: integer '/api/suppliers/{supplier_id}/toggle': post: summary: 'Toggle supplier status' operationId: toggleSupplierStatus description: 'Flips `status` true/false.' parameters: - in: header name: X-API-KEY description: '' example: '{YOUR_AUTH_KEY}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Supplier status toggled successfully.' data: id: 1 status: false meta: [] properties: success: type: boolean example: true message: type: string example: 'Supplier status toggled successfully.' data: type: object properties: id: type: integer example: 1 status: type: boolean example: false meta: type: array example: [] tags: - Suppliers parameters: - in: path name: supplier_id description: 'The ID of the supplier.' example: 17 required: true schema: type: integer - in: path name: supplier description: 'Supplier ID.' example: 17 required: true schema: type: integer /api/ping: get: summary: 'Ping (health check)' operationId: pinghealthCheck description: 'Lightweight endpoint to verify API availability and clock sync.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Ping successful.' data: server_time: '2025-08-13 17:20:33' meta: author: 'LicenseShipper API' properties: success: type: boolean example: true message: type: string example: 'Ping successful.' data: type: object properties: server_time: type: string example: '2025-08-13 17:20:33' meta: type: object properties: author: type: string example: 'LicenseShipper API' tags: - Utility security: []