├── jest.config.ts ├── jest.setup.ts ├── babel.config.js ├── tsconfig.json ├── tests ├── Webstore.test.ts ├── Pages.test.ts ├── Categories.test.ts ├── Package.test.ts └── Basket.test.ts ├── LICENSE ├── .github └── workflows │ └── release.yml ├── package.json ├── .gitignore ├── README.md └── index.ts /jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'jest'; 2 | 3 | const config: Config = { 4 | testTimeout: 60000, 5 | setupFilesAfterEnv: [ 6 | "./jest.setup.ts" 7 | ] 8 | } 9 | 10 | export default config; -------------------------------------------------------------------------------- /jest.setup.ts: -------------------------------------------------------------------------------- 1 | import { TebexHeadless } from "./dist"; 2 | 3 | declare global { 4 | var tebexHeadless: TebexHeadless; 5 | } 6 | 7 | require("dotenv").config(); 8 | 9 | global.tebexHeadless = new TebexHeadless( 10 | process.env.WEBSTORE_IDENTIFIER!, 11 | process.env.PRIVATE_KEY! 12 | ); -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | targets: { 7 | node: 'current', 8 | } 9 | } 10 | ], 11 | "@babel/preset-typescript" 12 | ] 13 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "module": "CommonJS", 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "skipLibCheck": true, 9 | "noUncheckedIndexedAccess": true, 10 | "noEmit": true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/Webstore.test.ts: -------------------------------------------------------------------------------- 1 | import { Webstore } from ".."; 2 | 3 | const keys: Array = [ 4 | "id", 5 | "name", 6 | "description", 7 | "webstore_url", 8 | "currency", 9 | "lang", 10 | "logo", 11 | "platform_type", 12 | "platform_type_id", 13 | "created_at" 14 | ] 15 | 16 | test("testWebstoreStructure", async () => { 17 | const webstore = await global.tebexHeadless.getWebstore(); 18 | expect(Object.keys(webstore).sort()).toEqual(keys.sort()) 19 | }) -------------------------------------------------------------------------------- /tests/Pages.test.ts: -------------------------------------------------------------------------------- 1 | import { Page } from ".."; 2 | 3 | const keys: Array = [ 4 | "id", 5 | "created_at", 6 | "updated_at", 7 | "account_id", 8 | "title", 9 | "slug", 10 | "private", 11 | "hidden", 12 | "disabled", 13 | "sequence", 14 | "content" 15 | ] 16 | 17 | test("testWebstorePagesStructure", async () => { 18 | const pages = await global.tebexHeadless.getPages() as [Page]; 19 | const [ page ] = pages; 20 | 21 | expect(pages.length).toBe(1) 22 | expect(Object.keys(page).sort()).toEqual(keys.sort()) 23 | }) -------------------------------------------------------------------------------- /tests/Categories.test.ts: -------------------------------------------------------------------------------- 1 | import { Category } from ".."; 2 | 3 | const keys: Array = [ 4 | "id", 5 | "name", 6 | "description", 7 | "parent", 8 | "order", 9 | "packages", 10 | "display_type", 11 | "slug" 12 | ] 13 | 14 | test("testCategoriesStructure", async () => { 15 | const categories = await global.tebexHeadless.getCategories(); 16 | const category = categories[0]; 17 | 18 | expect(category).toBeDefined() 19 | 20 | if (category) { 21 | expect(Object.keys(category).sort()).toEqual(keys.sort()) 22 | } 23 | }) -------------------------------------------------------------------------------- /tests/Package.test.ts: -------------------------------------------------------------------------------- 1 | import { Package } from ".."; 2 | 3 | const keys: Array = [ 4 | "id", 5 | "name", 6 | "description", 7 | "type", 8 | "disable_gifting", 9 | "disable_quantity", 10 | "expiration_date", 11 | "currency", 12 | "category", 13 | "base_price", 14 | "sales_tax", 15 | "total_price", 16 | "discount", 17 | "image", 18 | "created_at", 19 | "updated_at", 20 | "variables", 21 | "order" 22 | ] 23 | 24 | const ip = process.env.IP_ADDRESS; 25 | const package_id = parseInt(process.env.PACKAGE_ID!); 26 | 27 | test("testPackageStructure", async () => { 28 | const _package = await global.tebexHeadless.getPackage(package_id, undefined, ip); 29 | expect(Object.keys(_package).sort()).toEqual(keys.sort()) 30 | }) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 GRP 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | schedule: 4 | - cron: 0 0 * * * 5 | push: 6 | branches: 7 | - main 8 | jobs: 9 | release: 10 | permissions: 11 | contents: write 12 | issues: write 13 | pull-requests: write 14 | environment: production 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v4 18 | - name: Use Node.js 19 | uses: actions/setup-node@v4 20 | with: 21 | node-version: 20 22 | - run: npm ci 23 | - run: npm run build 24 | - run: npm run test 25 | env: 26 | PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} 27 | CARD_NUMBER: ${{ vars.CARD_NUMBER }} 28 | IP_ADDRESS: ${{ vars.IP_ADDRESS }} 29 | PACKAGE_ID: ${{ vars.PACKAGE_ID }} 30 | WEBSTORE_IDENTIFIER: ${{ vars.WEBSTORE_IDENTIFIER }} 31 | - run: npx semantic-release 32 | env: 33 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 34 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tebex_headless", 3 | "version": "0.0.0", 4 | "description": "Tebex Headless API", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "module": "dist/index.mjs", 8 | "scripts": { 9 | "test": "jest", 10 | "build": "tsup index.ts --format cjs,esm --dts", 11 | "lint": "tsc" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/Tynopia/tebex_headless.git" 16 | }, 17 | "keywords": [ 18 | "tynopia", 19 | "tebex", 20 | "headless", 21 | "api", 22 | "typescript" 23 | ], 24 | "author": "Tynopia / Lukas Leisten", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/Tynopia/tebex_headless/issues" 28 | }, 29 | "homepage": "https://github.com/Tynopia/tebex_headless#readme", 30 | "devDependencies": { 31 | "@babel/preset-typescript": "^7.23.3", 32 | "@babel/preset-env": "^7.23.6", 33 | "@swc/core": "^1.3.99", 34 | "@types/jest": "^29.5.11", 35 | "dotenv": "^16.3.1", 36 | "jest": "^29.7.0", 37 | "ts-jest": "^29.1.1", 38 | "ts-node": "^10.9.2", 39 | "tsup": "^8.0.1", 40 | "typescript": "^5.3.2" 41 | }, 42 | "dependencies": { 43 | "axios": "^1.6.2" 44 | }, 45 | "publishConfig": { 46 | "registry": "https://registry.npmjs.org/", 47 | "tag": "latest" 48 | }, 49 | "release": { 50 | "branches": [ 51 | "main" 52 | ], 53 | "plugins": [ 54 | "@semantic-release/commit-analyzer", 55 | "@semantic-release/release-notes-generator", 56 | "@semantic-release/github", 57 | "@semantic-release/npm" 58 | ] 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env 77 | .env.development.local 78 | .env.test.local 79 | .env.production.local 80 | .env.local 81 | 82 | # parcel-bundler cache (https://parceljs.org/) 83 | .cache 84 | .parcel-cache 85 | 86 | # Next.js build output 87 | .next 88 | out 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | dist 93 | 94 | # Gatsby files 95 | .cache/ 96 | # Comment in the public line in if your project uses Gatsby and not Next.js 97 | # https://nextjs.org/blog/next-9-1#public-directory-support 98 | # public 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # vuepress v2.x temp and cache directory 104 | .temp 105 | .cache 106 | 107 | # Docusaurus cache and generated files 108 | .docusaurus 109 | 110 | # Serverless directories 111 | .serverless/ 112 | 113 | # FuseBox cache 114 | .fusebox/ 115 | 116 | # DynamoDB Local files 117 | .dynamodb/ 118 | 119 | # TernJS port file 120 | .tern-port 121 | 122 | # Stores VSCode versions used for testing VSCode extensions 123 | .vscode-test 124 | 125 | # yarn v2 126 | .yarn/cache 127 | .yarn/unplugged 128 | .yarn/build-state.yml 129 | .yarn/install-state.gz 130 | .pnp.* 131 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tebex Headless API Wrapper 2 | 3 | ![Tebex Headless](https://github.com/Tynopia/tebex_headless/assets/65678882/f9de08d5-aa6a-4cdf-a819-7d89d615c63b) 4 | 5 | Welcome to the Tebex Headless API Wrapper! This Node.js TypeScript library allows you to seamlessly integrate Tebex into your projects and build a custom storefront without revealing your use of Tebex. 6 | 7 | ## Installation 8 | 9 | ```bash 10 | npm install tebex_headless 11 | ``` 12 | 13 | ## Getting Started 14 | 15 | 1. Obtain your Tebex Headless API public token from your Tebex account. 16 | 2. Install the `tebex_headless` library in your project. 17 | 3. Start using the Tebex Headless API in your Node.js TypeScript application! 18 | 19 | ```typescript 20 | import { TebexHeadless } from "tebex_headless"; 21 | 22 | const tebexHeadless = new TebexHeadless(webstoreIdentifier); 23 | ``` 24 | 25 | ## Functions 26 | 27 | ```typescript 28 | // A function to get the categories from the Tebex Headless API 29 | async TebexHeadless::getCategories(includePackages?: boolean, basketIdent?: string, ipAddress?: string) 30 | 31 | // A function to get a category from the Tebex Headless API 32 | async TebexHeadless::getCategory(id: number, includePackages?: boolean, basketIdent?: string, ipAddress?: string) 33 | 34 | // A function to apply a coupon, giftcard or creator code to a basket 35 | async TebexHeadless::apply>(basketIdent: string, type: T, body: A) 36 | 37 | // A function to remove a coupon, giftcard or creator code from a basket 38 | async TebexHeadless::remove>(basketIdent: string, type: T, body: A) 39 | 40 | // A function to get a package from the Tebex Headless API 41 | async TebexHeadless::getPackage(id: number, basketIdent?: string, ipAddress?: string) 42 | 43 | // A function to get all packages from the Tebex Headless API 44 | async TebexHeadless::getPackages(basketIdent?: string, ipAddress?: string) 45 | 46 | // A function to get a basket from the Tebex Headless API 47 | async TebexHeadless::getBasket(basketIdent: string) 48 | 49 | // A function to create a basket from the Tebex Headless API 50 | async TebexHeadless::createBasket(complete_url: string, cancel_url: string, custom?: KeyValuePair, complete_auto_redirect?: boolean, ipAddress?: string) 51 | 52 | // A function to create a minecraft basket from the Tebex Headless API 53 | async TebexHeadless::createMinecraftBasket(username: string, complete_url: string, cancel_url: string, custom?: KeyValuePair, complete_auto_redirect?: boolean, ipAddress?: string) 54 | 55 | // A function to get the auth url of a basket from the Tebex Headless API 56 | async TebexHeadless::getBasketAuthUrl(basketIdent: string, returnUrl: string) 57 | 58 | // A function to add a package to a basket from the Tebex Headless API 59 | TebexHeadless::addPackageToBasket(basketIdent: string, package_id: number, quantity: number, type?: PackageType, variable_data?: KeyValuePair) 60 | 61 | // A function to gift a package to a user from the Tebex Headless API 62 | async TebexHeadless::giftPackage(basketIdent: string, package_id: number, target_username_id: string) 63 | 64 | // A function to remove a package from a basket from the Tebex Headless API 65 | async TebexHeadless::removePackage(basketIdent: string, package_id: number) 66 | 67 | // A function to update the quantity of a package in a basket from the Tebex Headless API 68 | async TebexHeadless::updateQuantity(basketIdent: string, package_id: number, quantity: number) 69 | 70 | // A function to get the webstore from the Tebex Headless API 71 | async TebexHeadless::getWebstore() 72 | ``` 73 | 74 | ## Features 75 | 76 | - **Seamless Integration:** Use Tebex functionalities in your project without exposing the fact that you are using Tebex. 77 | - **Custom Storefront:** Build your custom storefront by leveraging Tebex Headless API. 78 | 79 | 80 | ## IP forwarding 81 | 82 | If a store uses its own backend but wants to use the IP addresses of the users instead of the server, Tebex requires a basic [authentication](https://documenter.getpostman.com/view/10912536/2s9XxvTEmh#intro). 83 | 84 | [Check our following Link to generate a private key](https://creator.tebex.io/developers/api-keys) 85 | 86 | ```typescript 87 | import { TebexHeadless } from "tebex_headless"; 88 | 89 | const tebexHeadless = new TebexHeadless(webstoreIdentifier, privateKey); 90 | ``` 91 | 92 | ## Contributing 93 | 94 | We welcome contributions from the community! If you'd like to contribute to this project, please follow these steps: 95 | 96 | 1. Fork the repository. 97 | 2. Create a new branch for your feature or bug fix. 98 | 3. Make your changes and ensure tests pass. 99 | 4. Submit a pull request with a clear description of your changes. 100 | 101 | ## Documentation 102 | 103 | Check out the [official Tebex documentation](https://docs.tebex.io/) for detailed information about the Tebex Headless API and its features. 104 | 105 | ## Support 106 | 107 | If you have questions or need assistance, feel free to [open an issue](https://github.com/Tynopia/tebex_headless/issues) on the GitHub repository. 108 | 109 | ## License 110 | 111 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. 112 | 113 | --- 114 | 115 | Happy coding! 🚀 116 | -------------------------------------------------------------------------------- /tests/Basket.test.ts: -------------------------------------------------------------------------------- 1 | import { Basket, BasketPackage } from ".."; 2 | 3 | const keys: Array = [ 4 | "ident", 5 | "complete", 6 | "id", 7 | "country", 8 | "ip", 9 | "username_id", 10 | "username", 11 | "cancel_url", 12 | "complete_url", 13 | "complete_auto_redirect", 14 | "base_price", 15 | "sales_tax", 16 | "total_price", 17 | "email", 18 | "currency", 19 | "packages", 20 | "coupons", 21 | "giftcards", 22 | "creator_code", 23 | "links", 24 | "custom" 25 | ] 26 | 27 | const basketPackageKeys: Array = [ 28 | "description", 29 | "id", 30 | "in_basket", 31 | "name", 32 | "image" 33 | ] 34 | 35 | const ip = process.env.IP_ADDRESS; 36 | const url = "https://grp.plus/"; 37 | const custom = { 38 | check: true 39 | } 40 | 41 | const username = "test"; 42 | const username_id = "c53db9316d2d489996d183975a99eb6d"; 43 | 44 | const card_number = process.env.CARD_NUMBER; 45 | const package_id = parseInt(process.env.PACKAGE_ID!); 46 | const quantity = 7; 47 | 48 | let testBasket: Basket; 49 | 50 | beforeAll(async () => { 51 | testBasket = await global.tebexHeadless.createBasket(url, url, custom, true, ip); 52 | }); 53 | 54 | describe("Basket Tests", () => { 55 | test("testBasketStructure", async () => { 56 | expect(testBasket).toBeDefined() 57 | expect(Object.keys(testBasket).sort()).toEqual(keys.sort()) 58 | //expect(testBasket.currency).toEqual("GBP") // Maybe a tebex bug? The currency is actually EUR (Based on my webstore settings) 59 | //expect(testBasket.country).toEqual("GB") Why is this broken? This was working for months 60 | expect(testBasket.ip).toEqual(ip) 61 | expect(testBasket.custom).toEqual(custom) 62 | }) 63 | 64 | test("testMinecraftBasket", async () => { 65 | testBasket = await global.tebexHeadless.createMinecraftBasket(username, url, url, custom, true, ip); 66 | 67 | expect(testBasket).toBeDefined() 68 | expect(testBasket.username).toEqual(username.charAt(0).toUpperCase() + username.slice(1)) 69 | }) 70 | 71 | test("testBasketAddPackageToBasket", async () => { 72 | testBasket = await global.tebexHeadless.addPackageToBasket(testBasket.ident, package_id, quantity, "single") 73 | 74 | expect(testBasket.packages[0]).toBeDefined() 75 | expect(testBasket.packages[0]!.id).toEqual(package_id) 76 | expect(testBasket.packages[0]!.in_basket.quantity).toEqual(quantity) 77 | }) 78 | 79 | test("testBasketPackageStructure", async () => { 80 | expect(Object.keys(testBasket.packages[0]!).sort()).toEqual(basketPackageKeys.sort()) 81 | }) 82 | 83 | test("testBasketUpdateQuantity", async () => { 84 | testBasket = await global.tebexHeadless.updateQuantity(testBasket.ident, package_id, quantity * 2) 85 | 86 | expect(testBasket.packages[0]).toBeDefined() 87 | expect(testBasket.packages[0]!.in_basket.quantity).toEqual(quantity * 2) 88 | }) 89 | 90 | test("testBasketRemovePackage", async () => { 91 | testBasket = await global.tebexHeadless.removePackage(testBasket.ident, package_id) 92 | 93 | expect(testBasket.packages[0]).toBeUndefined() 94 | }) 95 | 96 | test("testBasketGiftPackage", async () => { 97 | testBasket = await global.tebexHeadless.giftPackage(testBasket.ident, package_id, username_id) 98 | 99 | expect(testBasket.packages[0]).toBeDefined() 100 | expect(testBasket.packages[0]!.in_basket.gift_username_id).toEqual(username_id) 101 | }) 102 | 103 | test("testBasketApplyCoupon", async () => { 104 | const response = await global.tebexHeadless.apply(testBasket.ident, "coupons", { 105 | coupon_code: "test" 106 | }) 107 | 108 | expect(response.success).toEqual(true) 109 | expect(response.message).toEqual("Coupon applied successfully") 110 | }) 111 | 112 | // Maybe a tebex bug? The coupon was successfully applied but the remove says it wasn't 113 | /*test("testBasketRemoveCoupon", async () => { 114 | const response = await Remove(testBasket.ident, "coupons", { 115 | coupon_code: "test" 116 | }) 117 | 118 | expect(response.success).toEqual(true) 119 | expect(response.message).toEqual("Coupon removed successfully") 120 | })*/ 121 | 122 | test("testBasketAppyCreatorCode", async () => { 123 | const response = await global.tebexHeadless.apply(testBasket.ident, "creator-codes", { 124 | creator_code: "test" 125 | }) 126 | 127 | expect(response.success).toEqual(true) 128 | expect(response.message).toEqual("Creator code applied successfully") 129 | }) 130 | 131 | test("testBasketRemoveCreatorCode", async () => { 132 | const response = await global.tebexHeadless.remove(testBasket.ident, "creator-codes", { 133 | creator_code: "test" 134 | }) 135 | 136 | expect(response.success).toEqual(true) 137 | expect(response.message).toEqual("Creator code removed successfully") 138 | }) 139 | 140 | test("testBasketApplyGiftCard", async () => { 141 | const response = await global.tebexHeadless.apply(testBasket.ident, "giftcards", { 142 | card_number: card_number! 143 | }) 144 | 145 | expect(response.success).toEqual(true) 146 | expect(response.message).toEqual("Gift card applied successfully") 147 | }) 148 | 149 | test("testBasketRemoveGiftCard", async () => { 150 | const response = await global.tebexHeadless.remove(testBasket.ident, "giftcards", { 151 | card_number: card_number! 152 | }) 153 | 154 | expect(response.success).toEqual(true) 155 | expect(response.message).toEqual("Gift card removed successfully") 156 | }) 157 | }) -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | import axios, { AxiosRequestConfig, Method } from "axios"; 2 | 3 | /** 4 | * @constant baseUrl 5 | * @description The base URL of the Tebex Headless API 6 | * 7 | * @type {string} 8 | */ 9 | const baseUrl: string = "https://headless.tebex.io"; 10 | 11 | /** 12 | * @type {Data} 13 | * @description The data returned from the Tebex Headless API 14 | * 15 | * @type {T} The type of data to be returned 16 | */ 17 | export type Data = { 18 | data: T; 19 | } 20 | 21 | /** 22 | * @type {Message} 23 | * @description The message returned from the Tebex Headless API 24 | * 25 | * @param {boolean} success Whether the request was successful 26 | * @param {string} message The message returned from the Tebex Headless API 27 | */ 28 | export type Message = { 29 | success: boolean; 30 | message: string; 31 | } 32 | 33 | /** 34 | * @type {GenericObject} 35 | * @description A generic object 36 | */ 37 | export type GenericObject = string | number | boolean | null | undefined; 38 | 39 | /** 40 | * @type {Route} 41 | * @description The route of the Tebex Headless API 42 | * 43 | * @param {string} accounts The accounts route 44 | * @param {string} baskets The baskets route 45 | */ 46 | export type Route = "accounts" | "baskets"; 47 | 48 | /** 49 | * @type {ApplyType} 50 | * @description The type of the apply request 51 | * 52 | * @param {string} coupons The coupons type 53 | * @param {string} giftcards The giftcards type 54 | * @param {string} creator-codes The creator codes type 55 | */ 56 | export type ApplyType = "coupons" | "giftcards" | "creator-codes"; 57 | 58 | /** 59 | * @type {BaseItem} 60 | * @description The base item object for the package and category objects 61 | * 62 | * @param {number} id The ID of the base item 63 | * @param {string} name The name of the base item 64 | */ 65 | export type BaseItem = { 66 | id: number; 67 | name: string; 68 | } 69 | 70 | /** 71 | * @type {CouponCodeBody} 72 | * @description The coupon code object for the body of the request 73 | * 74 | * @param {string} coupon_code The coupon code to apply or remove 75 | */ 76 | export type CouponCode = { 77 | coupon_code: string; 78 | } 79 | 80 | /** 81 | * @type {GiftCardCodeBody} 82 | * @description The gift card code object for the body of the request 83 | * 84 | * @param {string} card_number The gift card code to apply or remove 85 | */ 86 | export type GiftCardCode = { 87 | card_number: string; 88 | } 89 | 90 | /** 91 | * @type {CreatorCodeBody} 92 | * @description The creator code object for the body of the request 93 | * 94 | * @param {string} creator_code The creator code to apply or remove 95 | */ 96 | export type CreatorCode = { 97 | creator_code: string; 98 | } 99 | 100 | /** 101 | * @function Request 102 | * @description A function to make a request to the Tebex Headless API 103 | * 104 | * @param {Method | string} method The method of the request 105 | * @param {Route} route The route of the request 106 | * @param {string} path The path of the request 107 | * @param {Record} params The parameters of the request 108 | * 109 | * @returns {Promise} 110 | */ 111 | export async function Request( 112 | webstoreIdentifier: string, 113 | privateKey: string | undefined, 114 | method: Method, 115 | identifier: string | null, 116 | route: Route, 117 | path?: string, 118 | params?: Record, 119 | body?: Body 120 | ): Promise { 121 | if (params) { 122 | for (const [key, value] of Object.entries(params)) { 123 | if (typeof value === "boolean") { 124 | params[key] = value ? 1 : 0; 125 | } 126 | } 127 | } 128 | 129 | const config: AxiosRequestConfig = { 130 | url: `${baseUrl}/api/${route}/${identifier}${path ?? ""}`, 131 | params: params, 132 | method: method, 133 | data: body, 134 | headers: { 135 | "Content-Type": "application/json", 136 | }, 137 | }; 138 | 139 | if (webstoreIdentifier && privateKey) { 140 | config.auth = { 141 | username: webstoreIdentifier, 142 | password: privateKey, 143 | }; 144 | } 145 | 146 | const response = await axios.request(config); 147 | 148 | return response.data; 149 | } 150 | 151 | /** 152 | * @type {Category} 153 | * @description The category object returned from the Tebex Headless API 154 | * 155 | * @param {number} id The ID of the category 156 | * @param {string} name The name of the category 157 | * @param {string} description The description of the category 158 | * @param {Category | null} parent The parent category of the category 159 | * @param {number} order The order of the category 160 | * @param {Package[]} packages The packages in the category 161 | * @param {"grid" | "list" | string} display_type The display type of the category 162 | * @param {string | null} slug The slug of the category 163 | */ 164 | export type Category = BaseItem & { 165 | description: string; 166 | parent: Category | null; 167 | order: number; 168 | packages: Package[]; 169 | display_type: "grid" | "list"; 170 | slug: string | null; 171 | }; 172 | 173 | /** 174 | * @type {ApplyTypeToInterface} 175 | * @description The type of the apply request 176 | * 177 | * @param {string} coupons The coupons type 178 | * @param {string} giftcards The giftcards type 179 | * @param {string} creator-codes The creator codes type 180 | * 181 | * @returns {CouponCode | GiftCardCode | CreatorCode} 182 | */ 183 | export type ApplyTypeToInterface = T extends "coupons" 184 | ? CouponCode 185 | : T extends "giftcards" 186 | ? GiftCardCode 187 | : T extends "creator-codes" 188 | ? CreatorCode 189 | : never; 190 | 191 | /** 192 | * @type {PackageType} 193 | * @description The type of the package 194 | * 195 | * @param {string} subscription The subscription type 196 | * @param {string} single The single type 197 | */ 198 | export type PackageType = "subscription" | "single" | "both"; 199 | 200 | /** 201 | * @type {Package} 202 | * @description The package object returned from the Tebex Headless API 203 | * 204 | * @param {number} id The ID of the package 205 | * @param {string} name The name of the package 206 | * @param {string} description The description of the package 207 | * @param {PackageType} type The type of the package 208 | * @param {boolean} disable_gifting Whether gifting is disabled for the package 209 | * @param {boolean} disable_quantity Whether quantity is disabled for the package 210 | * @param {string | null} expiration_date The expiration date of the package 211 | * @param {ShortCategory} category The category of the package 212 | * @param {number} base_price The base price of the package 213 | * @param {number} sales_tax The sales tax of the package 214 | * @param {number} total_price The total price of the package 215 | * @param {number} discount The discount of the package 216 | * @param {string | null} image The image of the package 217 | * @param {string} created_at The date the package was created 218 | * @param {string} updated_at The date the package was updated 219 | * @param {Array} variables The variables referred to in this package 220 | * @param {number} order The order this package should be sorted in 221 | */ 222 | export type Package = BaseItem & { 223 | description: string; 224 | type: PackageType; 225 | disable_gifting: boolean; 226 | disable_quantity: boolean; 227 | expiration_date: string | null; 228 | currency: string; 229 | category: BaseItem; 230 | base_price: number; 231 | sales_tax: number; 232 | total_price: number; 233 | discount: number; 234 | image: string | null; 235 | created_at: string; 236 | updated_at: string; 237 | variables?: Array 238 | order: number; 239 | }; 240 | 241 | /** 242 | * @type {InBasket} 243 | * @description The in_basket object inside a basket package object 244 | * 245 | * @param {number} quantity The quantity of the package in the basket 246 | * @param {number} price The price of the package in the basket 247 | * @param {string | null} gift_username_id The ID of the user the package is gifted to 248 | * @param {string | null} gift_username The username of the user the package is gifted to 249 | */ 250 | export type InBasket = { 251 | quantity: number; 252 | price: number; 253 | gift_username_id: string | null; 254 | gift_username: string | null; 255 | } 256 | 257 | /** 258 | * @type {BasketPackage} 259 | * @description The basket package object returned from the Tebex Headless API 260 | * 261 | * @param {number} id The ID of the package 262 | * @param {string} name The name of the package 263 | * @param {string} description The description of the package 264 | * @param {InBasket} in_basket The in_basket object inside the basket package object 265 | * @param {string | null} image The image of the package 266 | */ 267 | export type BasketPackage = BaseItem & { 268 | description: string; 269 | in_basket: InBasket; 270 | image: string | null; 271 | }; 272 | 273 | /** 274 | * @type {Code} 275 | * @description The code object inside the basket coupons object 276 | * 277 | * @param {string} code The code of the object 278 | */ 279 | export type Code = { 280 | code: string; 281 | } 282 | 283 | /** 284 | * @type {Links} 285 | * @description The links object inside the basket object 286 | * 287 | * @param {string} checkout The checkout link of the basket 288 | */ 289 | export type Links = { 290 | checkout: string; 291 | [key: string]: string; 292 | } 293 | 294 | /** 295 | * @type {Basket} 296 | * @description The basket object returned from the Tebex Headless API 297 | * 298 | * @param {string} ident The identifier of the basket 299 | * @param {boolean} complete Whether the basket is complete 300 | * @param {number} id The ID of the basket 301 | * @param {string} country The country of the basket 302 | * @param {string} ip The IP address of the user 303 | * @param {string | null} username_id The ID of the user 304 | * @param {string | null} username The username of the user 305 | * @param {string} cancel_url The cancel url of the basket 306 | * @param {string} complete_url The complete url of the basket 307 | * @param {boolean} complete_auto_redirect Whether the basket should automatically redirect to the complete url 308 | * @param {number} base_price The base price of the basket 309 | * @param {number} sales_tax The sales tax of the basket 310 | * @param {number} total_price The total price of the basket 311 | * @param {string} email The email of the basket 312 | * @param {string} currency The currency of the basket 313 | * @param {BasketPackage[]} packages The packages in the basket 314 | * @param {Code[]} coupons The coupons in the basket 315 | * @param {GiftCardCode[]} giftcards The giftcards in the basket 316 | * @param {string} creator_code The creator code of the basket 317 | * @param {Links} links The links of the basket 318 | * @param {Record} custom The custom object of the basket 319 | */ 320 | export type Basket = { 321 | ident: string; 322 | complete: boolean; 323 | id: number; 324 | country: string; 325 | ip: string; 326 | username_id: string | null; 327 | username: string | null; 328 | cancel_url: string; 329 | complete_url: string; 330 | complete_auto_redirect: boolean; 331 | base_price: number; 332 | sales_tax: number; 333 | total_price: number; 334 | email: string; 335 | currency: string; 336 | packages: BasketPackage[]; 337 | coupons: Code[]; 338 | giftcards: GiftCardCode[]; 339 | creator_code: string; 340 | links: Links; 341 | custom: Record; 342 | } 343 | 344 | /** 345 | * @type {Urls} 346 | * @description The url object for the complete and cancel urls 347 | * 348 | * @param {string} complete_url The complete url 349 | * @param {string} cancel_url The cancel url 350 | */ 351 | export type Urls = { 352 | complete_url: string; 353 | cancel_url: string; 354 | custom?: Record; 355 | complete_auto_redirect?: boolean; 356 | }; 357 | 358 | /** 359 | * @type {AuthUrl} 360 | * @description The auth url object returned from the Tebex Headless API 361 | * 362 | * @param {string} name The name of the auth url 363 | * @param {string} url The url of the auth url 364 | */ 365 | export type AuthUrl = { 366 | name: string; 367 | url: string; 368 | } 369 | 370 | /** 371 | * @type {PackageBody} 372 | * @description The package object for the body of the request 373 | * 374 | * @param {number} package_id The ID of the package 375 | * @param {number} quantity The quantity of the package 376 | * @param {PackageType} type The type of the package 377 | */ 378 | export type PackageBody = { 379 | package_id: number; 380 | quantity: number; 381 | type: PackageType; 382 | } 383 | 384 | /** 385 | * @type {Webstore} 386 | * @description The webstore object returned from the Tebex Headless API 387 | * 388 | * @param {number} id The ID of the webstore 389 | * @param {string} description The description of the webstore 390 | * @param {string} name The name of the webstore 391 | * @param {string} webstore_url The webstore url of the webstore 392 | * @param {string} currency The currency of the webstore 393 | * @param {string} lang The language of the webstore 394 | * @param {string} logo The logo of the webstore 395 | * @param {string} platform_type The platform type of the webstore 396 | * @param {number} platform_type_id The platform type ID of the webstore 397 | * @param {string} created_at The date the webstore was created 398 | */ 399 | export type Webstore = { 400 | id: number; 401 | description: string; 402 | name: string; 403 | webstore_url: string; 404 | currency: string; 405 | lang: string; 406 | logo: string; 407 | platform_type: string; 408 | platform_type_id: number; 409 | created_at: string; 410 | } 411 | 412 | /** 413 | * @type {Page} 414 | * @description The page object returned from the Tebex Headless API 415 | * 416 | * @param {number} id The ID of the page 417 | * @param {string} created_at The date the page was created 418 | * @param {string} updated_at The date the page was updated 419 | * @param {number} account_id The ID of the account 420 | * @param {string} title The title of the page 421 | * @param {string} slug The slug of the page 422 | * @param {boolean} private Whether the page is private 423 | * @param {boolean} hidden Whether the page is hidden 424 | * @param {boolean} disabled Whether the page is disabled 425 | * @param {boolean} sequence Whether the page is in a sequence 426 | * @param {string} content The content of the page 427 | */ 428 | export type Page = { 429 | id: number; 430 | created_at: string; 431 | updated_at: string; 432 | account_id: number; 433 | title: string; 434 | slug: string; 435 | private: boolean; 436 | hidden: boolean; 437 | disabled: boolean; 438 | sequence: boolean; 439 | content: string; 440 | } 441 | 442 | export class TebexHeadless { 443 | constructor( 444 | /** 445 | * @constant webstoreIdentifier 446 | * @description A function to set the webstore identifier 447 | * 448 | * @param {string} identifier The identifier of the webstore 449 | * 450 | * @returns {void} 451 | */ 452 | readonly webstoreIdentifier: string, 453 | /** 454 | * @private {privateKey} 455 | * @description A function to set the private key 456 | * 457 | * @param {string} key The private key of the webstore 458 | * 459 | * @returns {void} 460 | */ 461 | private privateKey?: string 462 | ) {} 463 | 464 | /** 465 | * @function getCategories 466 | * @description A function to get the categories from the Tebex Headless API 467 | * 468 | * @param {boolean} includePackages Whether to include the packages in the categories 469 | * @param {string} basketIdent The identifier of the basket 470 | * @param {string} ipAddress The IP address of the user 471 | * 472 | * @returns {Promise} 473 | */ 474 | async getCategories( 475 | includePackages?: boolean, 476 | basketIdent?: string, 477 | ipAddress?: string 478 | ): Promise { 479 | const { data }: Data = await Request( 480 | this.webstoreIdentifier, 481 | this.privateKey, 482 | "get", 483 | this.webstoreIdentifier, 484 | "accounts", 485 | "/categories", 486 | { 487 | includePackages, 488 | basketIdent, 489 | ipAddress, 490 | } 491 | ); 492 | 493 | return data; 494 | } 495 | 496 | /** 497 | * @function getCategory 498 | * @description A function to get a category from the Tebex Headless API 499 | * 500 | * @param {number} id The ID of the category 501 | * @param {boolean} includePackages Whether to include the packages in the category 502 | * @param {string} basketIdent The identifier of the basket 503 | * @param {string} ipAddress The IP address of the user 504 | * 505 | * @returns {Promise} 506 | */ 507 | async getCategory( 508 | id: number, 509 | includePackages?: boolean, 510 | basketIdent?: string, 511 | ipAddress?: string 512 | ): Promise { 513 | const { data }: Data = await Request( 514 | this.webstoreIdentifier, 515 | this.privateKey, 516 | "get", 517 | this.webstoreIdentifier, 518 | "accounts", 519 | `/categories/${id}`, 520 | { 521 | includePackages, 522 | basketIdent, 523 | ipAddress, 524 | } 525 | ); 526 | 527 | return data; 528 | } 529 | 530 | /** 531 | * @function apply 532 | * @description A function to apply a coupon, giftcard or creator code to a basket 533 | * 534 | * @param {A} body The body of the request 535 | * @param {string} basketIdent The identifier of the basket 536 | * @param {ApplyType} type The type of the apply request 537 | * 538 | * @returns {Promise} 539 | */ 540 | async apply>( 541 | basketIdent: string, 542 | type: T, 543 | body: A 544 | ): Promise { 545 | return await Request( 546 | this.webstoreIdentifier, 547 | this.privateKey, 548 | "post", 549 | this.webstoreIdentifier, 550 | "accounts", 551 | `/baskets/${basketIdent}/${type}`, 552 | {}, 553 | body 554 | ); 555 | } 556 | 557 | /** 558 | * @function remove 559 | * @description A function to remove a coupon, giftcard or creator code from a basket 560 | * 561 | * @param {A} body The body of the request 562 | * @param {string} basketIdent The identifier of the basket 563 | * @param {ApplyType} type The type of the apply request 564 | * 565 | * @returns {Promise} 566 | */ 567 | async remove>( 568 | basketIdent: string, 569 | type: T, 570 | body: A 571 | ): Promise { 572 | return await Request( 573 | this.webstoreIdentifier, 574 | this.privateKey, 575 | "post", 576 | this.webstoreIdentifier, 577 | "accounts", 578 | `/baskets/${basketIdent}/${type}/remove`, 579 | {}, 580 | body 581 | ); 582 | } 583 | 584 | /** 585 | * @function getPackage 586 | * @description A function to get a package from the Tebex Headless API 587 | * 588 | * @param {number} id The ID of the package 589 | * @param {string} basketIdent The identifier of the basket 590 | * @param {string} ipAddress The IP address of the user 591 | * 592 | * @returns {Promise} 593 | */ 594 | async getPackage( 595 | id: number, 596 | basketIdent?: string, 597 | ipAddress?: string 598 | ): Promise { 599 | const { data }: Data = await Request( 600 | this.webstoreIdentifier, 601 | this.privateKey, 602 | "get", 603 | this.webstoreIdentifier, 604 | "accounts", 605 | `/packages/${id}`, 606 | { 607 | basketIdent, 608 | ipAddress, 609 | } 610 | ); 611 | 612 | return data; 613 | } 614 | 615 | /** 616 | * @function getPackages 617 | * @description A function to get all packages from the Tebex Headless API 618 | * 619 | * @param {string} basketIdent The identifier of the basket 620 | * @param {string} ipAddress The IP address of the user 621 | * 622 | * @returns {Promise} 623 | */ 624 | async getPackages( 625 | basketIdent?: string, 626 | ipAddress?: string 627 | ): Promise { 628 | const { data }: Data = await Request( 629 | this.webstoreIdentifier, 630 | this.privateKey, 631 | "get", 632 | this.webstoreIdentifier, 633 | "accounts", 634 | `/packages`, 635 | { 636 | basketIdent, 637 | ipAddress, 638 | } 639 | ); 640 | 641 | return data; 642 | } 643 | 644 | /** 645 | * @function getBasket 646 | * @description A function to get a basket from the Tebex Headless API 647 | * 648 | * @param {string} basketIdent The identifier of the basket 649 | * 650 | * @returns {Promise} 651 | */ 652 | async getBasket(basketIdent: string): Promise { 653 | const { data }: Data = await Request( 654 | this.webstoreIdentifier, 655 | this.privateKey, 656 | "get", 657 | this.webstoreIdentifier, 658 | "accounts", 659 | `/baskets/${basketIdent}` 660 | ); 661 | return data; 662 | } 663 | 664 | /** 665 | * @function createBasket 666 | * @description A function to create a basket from the Tebex Headless API 667 | * 668 | * @param {string} complete_url The complete url 669 | * @param {string} cancel_url The cancel url 670 | * @param {Record} custom The custom object of the basket 671 | * @param {boolean} complete_auto_redirect Whether the basket should automatically redirect to the complete url 672 | * @param {string} ip_address The IP address of the user 673 | * 674 | * @returns {Promise} 675 | */ 676 | async createBasket( 677 | complete_url: string, 678 | cancel_url: string, 679 | custom?: Record, 680 | complete_auto_redirect?: boolean, 681 | ip_address?: string 682 | ): Promise { 683 | const { data }: Data = await Request( 684 | this.webstoreIdentifier, 685 | this.privateKey, 686 | "post", 687 | this.webstoreIdentifier, 688 | "accounts", 689 | "/baskets", 690 | { 691 | ip_address, 692 | }, 693 | { 694 | complete_url, 695 | cancel_url, 696 | custom, 697 | complete_auto_redirect, 698 | } 699 | ); 700 | 701 | return data; 702 | } 703 | 704 | /** 705 | * @function createMinecraftBasket 706 | * @description A function to create a minecraft basket from the Tebex Headless API 707 | * 708 | * @param {string} username The username of the user 709 | * @param {string} complete_url The complete url 710 | * @param {string} cancel_url The cancel url 711 | * @param {Record} custom The custom object of the basket 712 | * @param {boolean} complete_auto_redirect Whether the basket should automatically redirect to the complete url 713 | * @param {string} ip_address The IP address of the user 714 | * 715 | * @returns {Promise} 716 | */ 717 | async createMinecraftBasket( 718 | username: string, 719 | complete_url: string, 720 | cancel_url: string, 721 | custom?: Record, 722 | complete_auto_redirect?: boolean, 723 | ip_address?: string 724 | ): Promise { 725 | const { data }: Data = await Request( 726 | this.webstoreIdentifier, 727 | this.privateKey, 728 | "post", 729 | this.webstoreIdentifier, 730 | "accounts", 731 | "/baskets", 732 | { 733 | ip_address, 734 | }, 735 | { 736 | username, 737 | complete_url, 738 | cancel_url, 739 | custom, 740 | complete_auto_redirect, 741 | } 742 | ); 743 | 744 | return data; 745 | } 746 | 747 | /** 748 | * @function getBasketAuthUrl 749 | * @description A function to get the auth url of a basket from the Tebex Headless API 750 | * 751 | * @param {string} basketIdent The identifier of the basket 752 | * @param {string} returnUrl The return url of the basket 753 | * 754 | * @returns {Promise} The data returned or an axios error 755 | */ 756 | async getBasketAuthUrl( 757 | basketIdent: string, 758 | returnUrl: string 759 | ): Promise { 760 | return await Request( 761 | this.webstoreIdentifier, 762 | this.privateKey, 763 | "get", 764 | this.webstoreIdentifier, 765 | "accounts", 766 | `/baskets/${basketIdent}/auth`, 767 | { 768 | returnUrl, 769 | } 770 | ); 771 | } 772 | 773 | /** 774 | * @function addPackageToBasket 775 | * @description A function to add a package to a basket from the Tebex Headless API 776 | * 777 | * @param {string} basketIdent The identifier of the basket 778 | * @param {number} package_id The ID of the package 779 | * @param {number} quantity The quantity of the package 780 | * @param {PackageType} type The type of the package 781 | * @param {Record} variable_data The variable data of the package 782 | * 783 | * @returns {Promise} 784 | */ 785 | async addPackageToBasket( 786 | basketIdent: string, 787 | package_id: number, 788 | quantity: number, 789 | type?: PackageType, 790 | variable_data?: Record 791 | ): Promise { 792 | const { data }: Data = await Request( 793 | this.webstoreIdentifier, 794 | this.privateKey, 795 | "post", 796 | basketIdent, 797 | "baskets", 798 | "/packages", 799 | {}, 800 | { 801 | package_id, 802 | quantity, 803 | type, 804 | variable_data, 805 | } 806 | ); 807 | 808 | return data; 809 | } 810 | 811 | /** 812 | * @function giftPackage 813 | * @description A function to gift a package to a user from the Tebex Headless API 814 | * 815 | * @param {string} basketIdent The identifier of the basket 816 | * @param {number} package_id The ID of the package 817 | * @param {string} target_username_id The ID of the user to gift the package to 818 | * 819 | * @returns {Promise} 820 | */ 821 | async giftPackage( 822 | basketIdent: string, 823 | package_id: number, 824 | target_username_id: string 825 | ): Promise { 826 | const { data }: Data = await Request( 827 | this.webstoreIdentifier, 828 | this.privateKey, 829 | "post", 830 | basketIdent, 831 | "baskets", 832 | "/packages", 833 | {}, 834 | { 835 | package_id, 836 | target_username_id, 837 | } 838 | ); 839 | 840 | return data; 841 | } 842 | 843 | /** 844 | * @function removePackage 845 | * @description A function to remove a package from a basket from the Tebex Headless API 846 | * 847 | * @param {string} basketIdent The identifier of the basket 848 | * @param {number} package_id The ID of the package 849 | * 850 | * @returns {Promise} 851 | */ 852 | async removePackage( 853 | basketIdent: string, 854 | package_id: number 855 | ): Promise { 856 | const { data }: Data = await Request( 857 | this.webstoreIdentifier, 858 | this.privateKey, 859 | "post", 860 | basketIdent, 861 | "baskets", 862 | "/packages/remove", 863 | {}, 864 | { 865 | package_id, 866 | } 867 | ); 868 | 869 | return data; 870 | } 871 | 872 | /** 873 | * @function updateQuantity 874 | * @description A function to update the quantity of a package in a basket from the Tebex Headless API 875 | * 876 | * @param {string} basketIdent The identifier of the basket 877 | * @param {number} package_id The ID of the package 878 | * @param {number} quantity The quantity of the package 879 | * 880 | * @returns {Promise} 881 | */ 882 | async updateQuantity( 883 | basketIdent: string, 884 | package_id: number, 885 | quantity: number 886 | ): Promise { 887 | const { data }: Data = await Request( 888 | this.webstoreIdentifier, 889 | this.privateKey, 890 | "put", 891 | basketIdent, 892 | "baskets", 893 | `/packages/${package_id}`, 894 | {}, 895 | { 896 | quantity, 897 | } 898 | ); 899 | 900 | return data; 901 | } 902 | 903 | /** 904 | * @function getWebstore 905 | * @description A function to get the webstore from the Tebex Headless API 906 | * 907 | * @returns {Promise} 908 | */ 909 | async getWebstore(): Promise { 910 | const { data }: Data = await Request( 911 | this.webstoreIdentifier, 912 | this.privateKey, 913 | "get", 914 | this.webstoreIdentifier, 915 | "accounts" 916 | ); 917 | return data; 918 | } 919 | 920 | /** 921 | * @function getPages 922 | * @description A function to get the pages from the Tebex Headless API 923 | * 924 | * @returns {Promise} 925 | */ 926 | async getPages(): Promise> { 927 | const { data }: Data> = await Request( 928 | this.webstoreIdentifier, 929 | this.privateKey, 930 | "get", 931 | this.webstoreIdentifier, 932 | "accounts", 933 | "/pages" 934 | ); 935 | 936 | return data; 937 | } 938 | 939 | /** 940 | * @function updateTier 941 | * @description Update an tier of an package 942 | * 943 | * @param {unknown} tierId The ID of the tier 944 | * @param {number} package_id The ID of the package 945 | * 946 | * @returns {Promise} 947 | */ 948 | async updateTier(tierId: unknown, package_id: number): Promise { 949 | return await Request( 950 | this.webstoreIdentifier, 951 | this.privateKey, 952 | "patch", 953 | this.webstoreIdentifier, 954 | "accounts", 955 | `/tiers/${tierId}`, 956 | {}, 957 | { 958 | package_id, 959 | } 960 | ); 961 | } 962 | } 963 | --------------------------------------------------------------------------------