├── src ├── server │ ├── index.ts │ └── app.ts ├── utils │ ├── generateOperationID.ts │ ├── logger.ts │ └── validateParameters.ts ├── routes │ ├── ProductsStock │ │ └── index.ts │ ├── Public │ │ └── index.ts │ ├── Device │ │ └── index.ts │ └── User │ │ └── index.ts └── controllers │ ├── ProductsStock │ └── index.ts │ ├── Device │ ├── device.types.ts │ └── index.ts │ ├── Public │ └── index.ts │ └── User │ └── index.ts ├── .dockerignore ├── tsconfig.json ├── .gitignore ├── Dockerfile ├── package.json ├── TODO.md ├── LICENSE ├── README.md └── swagger ├── Public-1.json └── User-1.json /src/server/index.ts: -------------------------------------------------------------------------------- 1 | import app from './app'; 2 | import logger from '../utils/logger'; 3 | 4 | const PORT = process.env.PORT || 3000; 5 | 6 | app.listen(PORT, () => { 7 | logger.info(`Zimra FDMS Mock Server is running on port ${PORT}`); 8 | }); 9 | -------------------------------------------------------------------------------- /src/utils/generateOperationID.ts: -------------------------------------------------------------------------------- 1 | const generateOperationID = (): string => { 2 | const randomPart = Math.random().toString(36).substring(2, 10).toUpperCase(); 3 | const timestamp = Date.now().toString(36).toUpperCase(); 4 | return `0HMPH${randomPart}${timestamp}`.substring(0, 60); 5 | }; 6 | 7 | 8 | export default generateOperationID; -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | # Version control 2 | .git 3 | .gitignore 4 | 5 | # Dependencies 6 | node_modules 7 | npm-debug.log 8 | 9 | # Build output 10 | dist 11 | 12 | # Environment variables 13 | .env 14 | .env.* 15 | 16 | # Development files 17 | README.md 18 | .vscode 19 | .idea 20 | *.md 21 | *.log 22 | 23 | # Docker files 24 | Dockerfile 25 | .dockerignore 26 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "outDir": "./dist", 6 | "rootDir": "./src", 7 | "strict": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "forceConsistentCasingInFileNames": true 11 | }, 12 | "include": ["src/**/*"], 13 | "exclude": ["node_modules"] 14 | } 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | node_modules/ 3 | npm-debug.log 4 | yarn-debug.log 5 | yarn-error.log 6 | 7 | # Build output 8 | dist/ 9 | build/ 10 | 11 | # Environment variables 12 | .env 13 | .env.local 14 | .env.*.local 15 | 16 | # IDE specific files 17 | .idea/ 18 | .vscode/ 19 | *.swp 20 | *.swo 21 | 22 | # OS specific files 23 | .DS_Store 24 | Thumbs.db 25 | 26 | # Logs 27 | logs/ 28 | *.log 29 | -------------------------------------------------------------------------------- /src/routes/ProductsStock/index.ts: -------------------------------------------------------------------------------- 1 | import { Router } from 'express'; 2 | import * as productsStockController from '../../controllers/ProductsStock'; 3 | 4 | const router = Router(); 5 | 6 | // Add your products stock routes here 7 | // Example: router.get('/', productsStockController.getAllProducts); 8 | 9 | 10 | router.get('/v1/:deviceID/Search', productsStockController.getProductsStock); 11 | 12 | export { router as default }; 13 | -------------------------------------------------------------------------------- /src/utils/logger.ts: -------------------------------------------------------------------------------- 1 | import pino from 'pino'; 2 | 3 | const transport = pino.transport({ 4 | target: 'pino-pretty', 5 | options: { 6 | colorize: true, 7 | levelFirst: true, 8 | translateTime: 'yyyy-mm-dd HH:MM:ss', 9 | }, 10 | }); 11 | 12 | const logger = pino({ 13 | level: process.env.LOG_LEVEL || 'info', 14 | base: { 15 | env: process.env.NODE_ENV || 'development', 16 | }, 17 | }, transport); 18 | 19 | export default logger; 20 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Use Node.js LTS version as the base image 2 | FROM node:18-alpine 3 | 4 | # Create app directory 5 | WORKDIR /usr/src/app 6 | 7 | # Copy package files 8 | COPY package*.json ./ 9 | 10 | # Install dependencies 11 | RUN npm install 12 | 13 | # Copy source code 14 | COPY . . 15 | 16 | # Build TypeScript code 17 | RUN npm run build 18 | 19 | # Expose the port the app runs on 20 | EXPOSE 3000 21 | 22 | # Command to run the application 23 | CMD ["npm", "start"] 24 | -------------------------------------------------------------------------------- /src/routes/Public/index.ts: -------------------------------------------------------------------------------- 1 | import { Router } from 'express'; 2 | 3 | // @ts-ignore 4 | import * as publicController from '../../controllers/Public'; 5 | 6 | const router = Router(); 7 | 8 | router.post('/v1/:deviceID/RegisterDevice', publicController.registerDevice); 9 | router.get('/v1/GetServerCertificate', publicController.getServerCertificate); 10 | router.post('/v1/:deviceID/VerifyTaxpayerInformation', publicController.verifyTaxpayerInformation); 11 | 12 | export { router as default }; 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zimra-fdms-mock-server", 3 | "version": "1.0.0", 4 | "description": "ZIMRA FDMS Mock Server", 5 | "main": "dist/server/index.js", 6 | "scripts": { 7 | "start": "node dist/server/index.js", 8 | "dev": "nodemon src/server/index.ts", 9 | "build": "tsc", 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "keywords": [], 13 | "author": "", 14 | "license": "ISC", 15 | "dependencies": { 16 | "@types/express": "^4.17.17", 17 | "@types/node": "^20.5.0", 18 | "express": "^4.18.2", 19 | "nodemon": "^3.0.1", 20 | "pino": "^9.6.0", 21 | "pino-pretty": "^13.0.0", 22 | "ts-node": "^10.9.1", 23 | "typescript": "^5.1.6" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # Todo 2 | ✅ Device endpoints
3 | ✅ Public endpoints
4 | ✅ User endpoints
5 | ✅ ProductsStock endpoints
6 | ⏳ Make mock server as realistic as possible
7 | 8 | 9 | ## Realism 10 | 11 | ⏳ Mock expired certificate response at middleware level
12 | ⏳ Mock server error response at middleware level
13 | ⏳ Add realistic token
14 | ⏳ Implement realistic device check
15 | ⏳ Implement realistic certificate check
16 | 17 | ### More research needed 18 | ⏳ Implement realistic user check (maybe not necessary) {use sqlite here}
19 | ⏳ Implement realistic products stock check (maybe not necessary) {use sqlite here}
20 | ⏳ Implement realistic day check (maybe not necessary) {use sqlite here}
21 | 22 | -------------------------------------------------------------------------------- /src/utils/validateParameters.ts: -------------------------------------------------------------------------------- 1 | export const checkDeviceID = (id: number): boolean => { 2 | 3 | try { 4 | const idNumber = Number(id); 5 | if (isNaN(idNumber) || idNumber <= 0 || idNumber >= 10000000000 || String(idNumber).length !== String(id).length) { 6 | return false; 7 | } 8 | return true; 9 | } catch (error) { 10 | return false; 11 | } 12 | }; 13 | 14 | export const checkActivationKey = (key: string): boolean => { 15 | if (typeof key !== 'string' || key.length > 8 || key.length === 0) { 16 | return false; 17 | } 18 | return true; 19 | }; 20 | 21 | export const checkDeviceSerialNo = (serialNo: string): boolean => { 22 | if (typeof serialNo !== 'string' || serialNo.length > 20 || serialNo.length === 0) { 23 | return false; 24 | } 25 | return true; 26 | }; 27 | 28 | -------------------------------------------------------------------------------- /src/routes/Device/index.ts: -------------------------------------------------------------------------------- 1 | import { Router } from 'express'; 2 | 3 | // @ts-ignore 4 | 5 | import * as deviceController from '../../controllers/Device'; 6 | 7 | const router = Router(); 8 | 9 | router.get('/v1/:deviceID/GetConfig', deviceController.getConfig); 10 | router.get('/v1/:deviceID/GetStatus', deviceController.getStatus); 11 | router.post('/v1/:deviceID/OpenDay', deviceController.openDay); 12 | router.post('/v1/:deviceID/CloseDay', deviceController.closeDay); 13 | router.post('/v1/:deviceID/IssueCertificate', deviceController.issueCertificate); 14 | router.post('/v1/:deviceID/SubmitReciept', deviceController.submitReciept); 15 | router.post('/v1/:deviceID/Ping', deviceController.ping); 16 | router.post('/v1/:deviceID/SubmitFile', deviceController.submitFile); 17 | router.get('/v1/:deviceID/SubmittedFileList', deviceController.submittedFileList); 18 | 19 | 20 | export { router as default }; 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Takunda Madechangu 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. -------------------------------------------------------------------------------- /src/routes/User/index.ts: -------------------------------------------------------------------------------- 1 | import { Router } from 'express'; 2 | import * as userController from '../../controllers/User'; 3 | 4 | const router = Router(); 5 | 6 | // Add your user routes here 7 | // Example: router.get('/', userController.getAllUsers); 8 | 9 | 10 | router.get('/v1/:deviceID/GetUsersList', userController.getUsersList); 11 | router.post('/v1/:deviceID/SendSecurityCodeToTaxpayer', userController.sendSecurityCodeToTaxpayer); 12 | router.post('/v1/:deviceID/CreateUser', userController.createUser); 13 | router.post('/v1/:deviceID/Login', userController.loginUser); 14 | router.post('/v1/:deviceID/SendSecurityCodeToUserPhone', userController.sendSecurityCodeToUserPhone); 15 | router.post('/v1/:deviceID/SendSecurityCodeToUserEmail', userController.sendSecurityCodeToUserEmail); 16 | router.post('/v1/:deviceID/ConfirmUser', userController.confirmUser); 17 | router.post('/v1/:deviceID/ChangePassword', userController.changePassword); 18 | router.post('/v1/:deviceID/ResetPassword', userController.resetPassword); 19 | router.post('/v1/:deviceID/ConfirmContact', userController.confirmContact); 20 | router.post('/v1/:deviceID/Update', userController.update); 21 | router.post('/v1/:deviceID/ConfirmPasswordReset', userController.confirmPasswordReset); 22 | 23 | 24 | export { router as default }; 25 | -------------------------------------------------------------------------------- /src/server/app.ts: -------------------------------------------------------------------------------- 1 | import express, { Application } from 'express'; 2 | import deviceRoutes from '../routes/Device'; 3 | import publicRoutes from '../routes/Public'; 4 | import userRoutes from '../routes/User'; 5 | import productsStockRoutes from '../routes/ProductsStock'; 6 | import logger from '../utils/logger'; 7 | 8 | class App { 9 | public app: Application; 10 | 11 | constructor() { 12 | this.app = express(); 13 | this.config(); 14 | this.routes(); 15 | } 16 | 17 | private config(): void { 18 | // Log all requests 19 | this.app.use((req, res, next) => { 20 | logger.info({ 21 | method: req.method, 22 | url: req.url, 23 | query: req.query, 24 | body: req.body, 25 | }, 'Incoming request'); 26 | next(); 27 | }); 28 | 29 | this.app.use(express.json()); 30 | this.app.use(express.urlencoded({ extended: true })); 31 | } 32 | 33 | private routes(): void { 34 | this.app.use('/Device', deviceRoutes); 35 | this.app.use('/Public', publicRoutes); 36 | this.app.use('/User', userRoutes); 37 | this.app.use('/ProductsStock', productsStockRoutes); 38 | } 39 | } 40 | 41 | export default new App().app; 42 | -------------------------------------------------------------------------------- /src/controllers/ProductsStock/index.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from 'express'; 2 | import generateOperationID from '../../utils/generateOperationID'; 3 | 4 | 5 | interface ProductsStockGetListDto { 6 | hsCode: string; 7 | goodName: string; 8 | quantity: number; 9 | taxPayerId: number; 10 | taxPayerName: string; 11 | taxPayerTIN: string; 12 | branchId?: number; 13 | branchName?: string; 14 | } 15 | 16 | export const getProductsStock = async (req: Request, res: Response) => { 17 | try { 18 | const { 19 | HsCode, GoodName, Sort, Order, Offset, Limit, Operator, DeviceModelName, DeviceModelVersion 20 | } = req.query; 21 | 22 | const { deviceID } = req.params; 23 | 24 | console.log('Received parameters:', req.query); 25 | 26 | const offset = parseInt(Offset as string); 27 | const limit = parseInt(Limit as string); 28 | 29 | if (isNaN(offset) || isNaN(limit)) { 30 | return res.status(400).json({ 31 | "type": "https://httpstatuses.io/422", 32 | "title": "Bad request", 33 | "status": 400, 34 | "detail": "Offset and Limit must be integers" 35 | }); 36 | } 37 | 38 | // Example of interacting with a database or service 39 | const products: ProductsStockGetListDto[] = [ 40 | { 41 | hsCode: '12345678', 42 | goodName: 'Sample Product', 43 | quantity: 100, 44 | taxPayerId: 1, 45 | taxPayerName: 'Tax Payer 1', 46 | taxPayerTIN: 'TIN12345', 47 | }, 48 | // Add more mock data if needed 49 | ] 50 | 51 | if (deviceID === 'invalid' || deviceID === '0') { 52 | return res.status(404).json({ 53 | "type": "https://httpstatuses.io/422", 54 | "title": "Unprocessable Entity", 55 | "status": 422, 56 | "detail": "Device fiscal day status must be FiscalDayClosed" 57 | }); 58 | } 59 | 60 | 61 | res.status(200).json({ 62 | total: products.length, // Assuming the total length here, or use a count query in DB 63 | rows: products 64 | }); 65 | } catch (error) { 66 | console.error(error); 67 | res.status(500).json({ 68 | "type": "https://httpstatuses.io/500", 69 | "title": "Server error", 70 | "status": 500, 71 | "operationID": generateOperationID() 72 | }); 73 | } 74 | }; 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ZIMRA FDMS Mock Server 🧾 2 | 3 | This is a mock server designed to simulate requests and responses as specified in the ZIMRA FDMS API documentation: https://fdmsapitest.zimra.co.zw/swagger/index.html 4 | 5 | 6 | > [!NOTE] 7 | > This mock server is particularly useful for developers who do not have immediate access to a fiscalized ID. However, please note that it is recommended to test with the original server whenever possible, as the responses may differ from those provided by this mock implementation. 8 | 9 | ## Stack 10 | 11 | - Node.js 12 | - Express 13 | - TypeScript 14 | - Docker 15 | 16 | ## Installation 17 | 18 | 1. Clone the repository: 19 | ```sh 20 | git clone https://github.com/takumade/zimra-fdms-mock-server.git 21 | cd zimra-fdms-mock-server 22 | ``` 23 | 24 | 2. Install dependencies: 25 | - Using npm/yarn/pnpm: 26 | ```sh 27 | npm install 28 | ``` 29 | 30 | 3. Start the server: 31 | - Using npm/yarn/pnpm: 32 | ```sh 33 | npm start 34 | ``` 35 | 36 | NB: In place of `npm` you can use `yarn`, or `pnpm`. 37 | 38 | NB: The server will start running on `http://localhost:3000`. 39 | 40 | 41 | ## Deploying 42 | 43 | ### Docker 44 | 45 | To deploy the ZIMRA FDMS Mock Server using Docker, follow these steps: 46 | 47 | 1. Ensure Docker is installed on your system. 48 | 2. Navigate to the project root directory. 49 | 3. Build and run the Docker container: 50 | 51 | ```sh 52 | # Build the Docker image 53 | docker build -t zimra-mock-server . 54 | 55 | # Run the container 56 | docker run -p 3000:3000 zimra-mock-server 57 | ``` 58 | 59 | The server will be accessible at `http://localhost:3000`. 60 | 61 | 62 | 63 | ### Live Endpoint 64 | 65 | You can access the live endpoint at: 66 | 67 | [https://zimra-fdms-mock-server.onrender.com](https://zimra-fdms-mock-server.onrender.com) 68 | 69 | 70 | > [!NOTE] 71 | > While this runs on a free tier and won't dip into my pocket, please don't abuse it. 72 | 73 | ## Contribution 74 | This project is open source and contributions are welcome. Please fork the repository and submit pull requests. 75 | 76 | > [!NOTE] 77 | > Given that it's a mock server, contributions are most welcome in the form of bug fixes and realism enhancements. 78 | 79 | ### Todo 80 | ✅ Device endpoints
81 | ✅ Public endpoints
82 | ✅ User endpoints
83 | ✅ ProductsStock endpoints
84 | ⏳ Make mock server as realistic as possible
85 | 86 | 87 | > [!NOTE] 88 | > Most of the endpoints are mocked but I want it to be as realistic as possible. An average user shouldnt tell the difference between the mock server and the original server. 😊 For more info see [TODO.md](TODO.md) 89 | 90 | 91 | 92 | ### Directory Structure 93 | 94 | ``` 95 | src/ 96 | ├── controllers/ 97 | │ ├── Device/ 98 | │ ├── Public/ 99 | │ ├── Public/ 100 | │ ├── User/ 101 | │ └── ProductsStock/ 102 | ├── routes/ 103 | │ ├── Device/ 104 | │ ├── Public/ 105 | │ ├── User/ 106 | │ └── ProductsStock/ 107 | └── server/ 108 | ├── app.ts 109 | └── index.ts 110 | ``` -------------------------------------------------------------------------------- /src/controllers/Device/device.types.ts: -------------------------------------------------------------------------------- 1 | export interface OpenDayRequest { 2 | fiscalDayNo: number; 3 | fiscalDayOpened: string; 4 | } 5 | 6 | export interface FiscalCounter { 7 | fiscalCounterType: "SaleByTax" | "SaleTaxByTax" | "CreditNoteByTax" | "CreditNoteTaxByTax" | "DebitNoteByTax" | "DebitNoteTaxByTax" | "BalanceByMoneyType" | "PayoutByTax" | "PayoutTaxByTax"; 8 | fiscalCounterCurrency: string; 9 | fiscalCounterTaxPercent?: number; 10 | fiscalCounterTaxID?: number; 11 | fiscalCounterMoneyType?: "Cash" | "CreditCard" | "DebitCard" | "Check" | "WireTransfer" | "MobileMoney" | "Voucher" | "Other"; 12 | fiscalCounterValue: number; 13 | } 14 | 15 | export interface CloseDayRequest { 16 | fiscalDayNo: number; 17 | fiscalDayCounters: FiscalCounter[]; 18 | fiscalDayDeviceSignature: { 19 | "hash": string, 20 | "signature": string 21 | }; 22 | receiptCounter: number; 23 | } 24 | 25 | export interface IssueCertificateRequest { 26 | certificateRequest: string 27 | } 28 | 29 | export interface PingResponse { 30 | reportingFrequency: number; 31 | operationID: string; 32 | } 33 | 34 | export interface SubmittedFileHeaderDtoListResponse { 35 | files: Array<{ 36 | fileName: string; 37 | uploadedAt: string; 38 | status: string; 39 | }>; 40 | } 41 | 42 | export interface SubmitReceiptRequest { 43 | receiptType: "FiscalInvoice" | "FiscalInvoiceProforma" | "FiscalReceipt" | "NonFiscalReceipt" | "CreditNote" | "DebitNote" | "CreditNoteProforma" | "DebitNoteProforma"; 44 | receiptCurrency: string; 45 | receiptCounter: number; 46 | receiptGlobalNo: number; 47 | invoiceNo: string; 48 | buyerData?: { 49 | buyerRegisterName: string; 50 | buyerTradeName: string; 51 | vatNumber?: string; 52 | buyerTIN?: string; 53 | buyerContacts?: { 54 | phoneNo?: string; 55 | email?: string; 56 | }; 57 | buyerAddress?: { 58 | province?: string; 59 | city?: string; 60 | street?: string; 61 | houseNo?: string; 62 | district?: string; 63 | }; 64 | }; 65 | receiptNotes?: string; 66 | receiptDate: string; 67 | creditDebitNote?: { 68 | receiptID?: number; 69 | deviceID?: number; 70 | receiptGlobalNo?: number; 71 | fiscalDayNo?: number; 72 | }; 73 | receiptLinesTaxInclusive: boolean; 74 | receiptLines: Array<{ 75 | receiptLineType: "Sale" | "Discount"; 76 | receiptLineNo: number; 77 | receiptLineHSCode?: string; 78 | receiptLineName: string; 79 | receiptLinePrice?: number; 80 | receiptLineQuantity: number; 81 | receiptLineTotal: number; 82 | taxCode?: string; 83 | taxPercent?: number; 84 | taxID: number; 85 | }>; 86 | receiptTaxes: Array<{ 87 | taxCode?: string; 88 | taxPercent?: number; 89 | taxID: number; 90 | taxAmount: number; 91 | salesAmountWithTax: number; 92 | }>; 93 | receiptPayments: Array<{ 94 | moneyTypeCode: "Cash" | "CreditCard" | "DebitCard" | "Check" | "WireTransfer" | "MobileMoney" | "Voucher" | "Other"; 95 | paymentAmount: number; 96 | }>; 97 | receiptTotal: number; 98 | receiptPrintForm?: "Receipt48" | "InvoiceA4"; 99 | receiptDeviceSignature: { 100 | hash: string; 101 | signature: string; 102 | }; 103 | } 104 | 105 | export interface Receipt { 106 | receiptType: string; 107 | receiptCurrency: string; 108 | receiptCounter: number; 109 | receiptGlobalNo: number; 110 | invoiceNo: string; 111 | receiptDate: string; 112 | receiptLinesTaxInclusive: boolean; 113 | receiptLines: Array<{ 114 | receiptLineType: string; 115 | receiptLineNo: number; 116 | receiptLineHSCode: string; 117 | receiptLineName: string; 118 | receiptLinePrice: number; 119 | receiptLineQuantity: number; 120 | receiptLineTotal: number; 121 | taxCode: string; 122 | taxPercent: number; 123 | taxID: number; 124 | }>; 125 | receiptTaxes: Array<{ 126 | taxCode: string; 127 | taxPercent: number; 128 | taxID: number; 129 | taxAmount: number; 130 | salesAmountWithTax: number; 131 | }>; 132 | receiptPayments: Array<{ 133 | moneyTypeCode: string; 134 | paymentAmount: number; 135 | }>; 136 | receiptTotal: number; 137 | receiptPrintForm: string; 138 | receiptDeviceSignature: { 139 | hash: string; 140 | signature: string; 141 | }; 142 | } 143 | 144 | export interface RequestBody { 145 | header: { 146 | deviceId: number; 147 | fiscalDayNo: number; 148 | fiscalDayOpened: string; 149 | fileSequence: number; 150 | }; 151 | content: { 152 | receipts: Receipt[]; 153 | }; 154 | footer: { 155 | fiscalDayCounters: Array; 156 | fiscalDayDeviceSignature: { 157 | hash: string; 158 | signature: string; 159 | }; 160 | receiptCounter: number; 161 | fiscalDayClosed: string; 162 | }; 163 | } 164 | -------------------------------------------------------------------------------- /src/controllers/Public/index.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from 'express'; 2 | import generateOperationID from '../../utils/generateOperationID'; 3 | 4 | // Add your public controller methods here 5 | // Example: 6 | // export const getPublicInfo = async (req: Request, res: Response) => { 7 | // try { 8 | // // Implementation 9 | // } catch (error) { 10 | // res.status(500).json({ error: 'Internal server error' }); 11 | // } 12 | // }; 13 | 14 | export const registerDevice = async (req: Request, res: Response) => { 15 | const { deviceID } = req.params; 16 | const DeviceModelName = req.header('DeviceModelName'); 17 | const DeviceModelVersion = req.header('DeviceModelVersion'); 18 | const requestBody = req.body; 19 | 20 | if (!deviceID || isNaN(Number(deviceID))) { 21 | return res.status(400).json({ 22 | errorCode: "BAD_REQUEST", 23 | type: "https://httpstatuses.io/400", 24 | title: "Bad Request", 25 | status: 400, 26 | detail: "Invalid or missing device ID", 27 | operationID: generateOperationID(), 28 | }); 29 | } 30 | 31 | if (!DeviceModelName || !DeviceModelVersion) { 32 | return res.status(400).json({ 33 | errorCode: "BAD_REQUEST", 34 | type: "https://httpstatuses.io/400", 35 | title: "Bad Request", 36 | status: 400, 37 | detail: "Missing required headers", 38 | operationID: generateOperationID(), 39 | }); 40 | } 41 | 42 | if (!requestBody || !requestBody.activationKey || !requestBody.certificateRequest || requestBody.certificateRequest == "invalid" 43 | || requestBody.activationKey === "invalid") { 44 | return res.status(422).json({ 45 | errorCode: "DEV01", 46 | type: "https://httpstatuses.io/422", 47 | title: "Unprocessable Entity", 48 | status: 422, 49 | detail: "Device not found or not active", 50 | operationID: generateOperationID(), 51 | }); 52 | } 53 | 54 | try { 55 | const response = { 56 | operationID: generateOperationID(), 57 | certificate: "-----BEGIN CERTIFICATE-----\nMIIC6TCCAdGgAwIBAgIFAKsSzWowDQYJKoZIhvcNAQELBQAwZDELMAkGA1UEBhMC\nTFQxETAPBgNVBAoMCEdvb2QgTHRkMScwJQYDVQQLDB5Hb29kIEx0ZCBDZXJ0aWZp\nY2F0ZSBBdXRob3JpdHkxGTAXBgNVBAMMEEdvb2QgTHRkIFJvb3QgQ0EwHhcNMTkx\nMDAzMTU1NzA1WhcNMjAxMDEyMTU1NzA1WjBfMQswCQYDVQQGEwJUWjERMA8GA1UE\nCAwIWmFuemliYXIxHzAdBgNVBAoMFlphbnppYmFyIFJldmVudWUgQm9hcmQxHDAa\nBgNVBAMME1pSQi1lVkZELTAwMDAwMDAwNDIwWTATBgcqhkjOPQIBBggqhkjOPQMB\nBwNCAAT7v3DvY7pRg4lz2Z87wSMwSX27KwlpYnSRV6WUiPjpq2XsUAbg2lhUN7q3\nmlNJaUzqoKPmop5qURIpqUydXfapo3IwcDAJBgNVHRMEAjAAMB8GA1UdIwQYMBaA\nFK1RXHm1plvaintqlWaXDs1X3LX+MB0GA1UdDgQWBBRqr96XrCUbuwCQawxO0//n\nTOCoNTAOBgNVHQ8BAf8EBAMCBeAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDQYJKoZI\nhvcNAQELBQADggEBANr1Wk1cVZB96yobFgK3rQQv9oXW+Jle7Jh36J2o4wSSB+RH\nlfMojDrqKVQCLrFDcF+8JIA3RTRKdduIXgBAr13xQ8JkHd1/o23yN6a2DaYgh0wr\nDrndlR6y1yG0vQuurJ3IgXmC0ldM5+VhalgmoCKFV9JsUD+GhOyJ6NWlc0SqvJCs\n3RZLYwZ4MNViPbRy0Kbp0ufY1zTbh02Gw9aVfFzUwL8GS00iMb4MnSav1xur7wQh\nBoF3PpNvu003P7f1eVJ62qVD2LWWntfn0mL1aRmDe2wpMQKAKhxto+sDb2mfJ6G6\nPFtwMHe7BUfiwTzGYqav21h1w/amPkxNVQ7Li4M=\n-----END CERTIFICATE-----", 58 | }; 59 | res.status(200).json(response); 60 | } catch (error) { 61 | res.status(500).json({ 62 | type: "https://httpstatuses.io/500", 63 | title: "Server error", 64 | status: 500, 65 | operationID: generateOperationID(), 66 | }); 67 | } 68 | } 69 | 70 | export const getServerCertificate = async (req: Request, res: Response) => { 71 | 72 | const { thumbprint } = req.query; 73 | const operationId = "0HMPHA0KCMPHN:00000005"; 74 | 75 | if (thumbprint && typeof thumbprint !== "string") { 76 | return res.status(400).json({ 77 | type: "https://httpstatuses.io/400", 78 | title: "Bad Request", 79 | status: 400, 80 | operationID: operationId, 81 | detail: "Invalid thumbprint format." 82 | }); 83 | } 84 | 85 | if (thumbprint === "notfound") { 86 | return res.status(404).json({ 87 | type: "https://httpstatuses.io/404", 88 | title: "Not Found", 89 | status: 404, 90 | operationID: operationId 91 | }); 92 | } 93 | 94 | if (thumbprint === "invalid") { 95 | return res.status(422).json({ 96 | errorCode: "DEV01", 97 | type: "https://httpstatuses.io/422", 98 | title: "Unprocessable Entity", 99 | status: 422, 100 | detail: "Device not found or not active", 101 | operationID: operationId 102 | }); 103 | } 104 | 105 | if (thumbprint === "error") { 106 | return res.status(500).json({ 107 | type: "https://httpstatuses.io/500", 108 | title: "Server error", 109 | status: 500, 110 | operationID: operationId 111 | }); 112 | } 113 | 114 | return res.status(200).json({ 115 | operationID: operationId, 116 | certificate: [ 117 | "-----BEGIN CERTIFICATE-----\nMIIDQTCCAikCFFLwDNnN3ZnAriN4wanJF439cX53MA0GCSqGSIb3DQEBCwUAMF0x\nCzAJBgNVBAYTAkxUMRMwEQYDVQQIDApFTEVLVFJFTkFJMRMwEQYDVQQHDApFTEVL\nVFJFTkFJMREwDwYDVQQKDAhldHJvbmlrYTERMA8GA1UEAwwIemltcmFfQ0EwHhcN\nMjMwMzE2MTA1NDAxWhcNMzMwMzEzMTA1NDAxWjBdMQswCQYDVQQGEwJMVDETMBEG\nA1UECAwKRUxFS1RSRU5BSTETMBEGA1UEBwwKRUxFS1RSRU5BSTERMA8GA1UECgwI\nZXRyb25pa2ExETAPBgNVBAMMCHppbXJhX0NBMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEA30dU24HCzSd+y4/ho41at23gh1g2Yjhk8SnUNo5PLn2uoUvj\nUemQNuJFjg14LvBPoubcIfOZW6cp9TCGy8KqG3WyVrT9z9sEl4fQMlEsCegmCEIE\nng7PvtsdJL9CaC7x11KK4az5UpzqUQ2gyYOryF6M8BT6wH5U61og2SWfv4M5ttQc\nbBDFbReeCYBLvSzFisI1CAVnc3CLqLhBN5jHxfraeZyAvLzBFnbYj7RBcv28iGRz\ny6LXtgE9yDeRdtCk8UqrgyMe//LWmlu+mmLb2IdIeD66GkD637FURa9lAcDJksUP\nUep2TyXq44JjMeNz7CyPbJ0wlV49cUlKc+/ZVQIDAQABMA0GCSqGSIb3DQEBCwUA\nA4IBAQAPVhhMAvjpQRm9OqZz3k97/yygqxeNKdTjxc/zVO8gj0pRBclVhxCnfj+P\nA1wc1nBEHvZ0oh03JviGQ8wxTLWUc0vWlZICmST7heC3DeA+xh90mLZOb2kK3cko\nY7kTAQ8cLV+ddI4UI46WQ6q/bhueOZQjMf1K2IP0fUhXxgFtrPXXrlkiUNX4tisg\ncy986/JjIHk2sY3OyBqYeFwq5J6DO2kMfLgHzwlaVWnTiXJ/etK17fynETImldZU\n9qSHYEyURqKuDyjELRThDLDTGwnsL5HU31+RCmGCZuNpjqkdne8hedNISdyCsMvD\ndDY0A7Vf+2WmfxWzg0wbhf6cIjxS\n-----END CERTIFICATE-----", 118 | "-----BEGIN CERTIFICATE-----\nMIIDcDCCAligAwIBAgIISVJfo63v2tswDQYJKoZIhvcNAQELBQAwXTELMAkGA1UE\nBhMCTFQxEzARBgNVBAgMCkVMRUtUUkVOQUkxEzARBgNVBAcMCkVMRUtUUkVOQUkx\nETAPBgNVBAoMCGV0cm9uaWthMREwDwYDVQQDDAh6aW1yYV9DQTAeFw0yMzAzMjAx\nOTM5NTVaFw0yNjAzMjAyMTIzMTBaMGwxCzAJBgNVBAYTAlpXMREwDwYDVQQIDAha\naW1iYWJ3ZTEsMCoGA1UECgwjWmltYmFid2UgRmlzY2FsaXNhdGlvbiBPcmdhbml6\nYXRpb24xHDAaBgNVBAMME1pSQi1lVkZELTAwMDAwMDAwNDIwWTATBgcqhkjOPQIB\nBggqhkjOPQMBBwNCAAT7v3DvY7pRg4lz2Z87wSMwSX27KwlpYnSRV6WUiPjpq2Xs\nUAbg2lhUN7q3mlNJaUzqoKPmop5qURIpqUydXfapo4HvMIHsMAkGA1UdEwQCMAAw\nHQYDVR0OBBYEFGqv3pesJRu7AJBrDE7T/+dM4Kg1MIGaBgNVHSMEgZIwgY+AFIKH\n58WkIDv0AUhEr+O0qvs6Dk7VoWGkXzBdMQswCQYDVQQGEwJMVDETMBEGA1UECAwK\nRUxFS1RSRU5BSTETMBEGA1UEBwwKRUxFS1RSRU5BSTERMA8GA1UECgwIZXRyb25p\na2ExETAPBgNVBAMMCHppbXJhX0NBghRS8AzZzd2ZwK4jeMGpyReN/XF+dzAOBgNV\nHQ8BAf8EBAMCBeAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQAD\nggEBAMkQykLAfhUGYaMR71kdwgFShstjK12v0sg69ruNtnlIajs3H9vaYoZRvPOV\n5jkdKlzF4Erp8D9URTJQD9aNCHqOZg1wSytuQqxedoThaWSYL3eiUf3Rig+II/fG\n/F+sr0pC6QrriJKRHH8aeAUF2jXD/CyI/GcftBIMTr91egV5Bn3Pjwfh8aEFzq7R\nqF4p0p8UBPwJtFUSqC4JkwLkpfG8bMpNHYic97+PRRLlrqiSPrQF/rlLQDC4IpMc\n9oMHuYHi2CmMcpnXLNZhgeFhHpILKOloU/AGtsExDS4gHCm/LfkUAz3p0KTIxnfx\nj5QjByFH8P3rY05BmSdE4aFUnxM=\n-----END CERTIFICATE-----" 119 | ], 120 | certificateValidTill: "2026-03-20T21:23:10" 121 | }); 122 | } 123 | 124 | export const verifyTaxpayerInformation = async (req: Request, res: Response) => { 125 | 126 | const { deviceID } = req.params; 127 | const requestBody = req.body; 128 | const operationID = "0HMPDRRQL1C0G:00000005"; 129 | 130 | if (!deviceID || isNaN(Number(deviceID))) { 131 | return res.status(400).json({ 132 | type: "https://httpstatuses.io/400", 133 | title: "Bad Request", 134 | status: 400, 135 | operationID 136 | }); 137 | } 138 | 139 | if (!requestBody || !requestBody.activationKey || !requestBody.deviceSerialNo || requestBody.deviceSerialNo == "invalid" 140 | || requestBody.activationKey === "invalid") { 141 | return res.status(422).json({ 142 | errorCode: "DEV01", 143 | type: "https://httpstatuses.io/422", 144 | title: "Unprocessable Entity", 145 | status: 422, 146 | detail: "Device not found or not active", 147 | operationID 148 | }); 149 | } 150 | 151 | // Simulating success response 152 | return res.status(200).json({ 153 | operationID, 154 | taxpayerVerified: true, 155 | message: "Taxpayer information verified successfully" 156 | }); 157 | } 158 | 159 | -------------------------------------------------------------------------------- /src/controllers/User/index.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from 'express'; 2 | import generateOperationID from '../../utils/generateOperationID'; 3 | 4 | export const getUsersList = (req: Request, res: Response) => { 5 | const { deviceID } = req.params; 6 | const { Sort, Order, Offset, Limit, Operator } = req.query; 7 | const DeviceModelName = req.header("DeviceModelName"); 8 | const DeviceModelVersion = req.header("DeviceModelVersion"); 9 | 10 | if (!deviceID || !Offset || !Limit) { 11 | return res.status(400).json({ message: "Missing required parameters" }); 12 | } 13 | 14 | res.status(200).json({ 15 | operationID: generateOperationID(), 16 | total: 10, 17 | rows: [ 18 | { 19 | userName: "mockUser", 20 | personName: "John", 21 | personSurname: "Doe", 22 | userRole: "Admin", 23 | email: "john.doe@example.com", 24 | phoneNo: "+123456789", 25 | userStatus: "Active", 26 | }, 27 | ], 28 | }); 29 | }; 30 | 31 | export const sendSecurityCodeToTaxpayer = (req: Request, res: Response) => { 32 | const { deviceID } = req.params; 33 | const DeviceModelName = req.header("DeviceModelName"); 34 | const DeviceModelVersion = req.header("DeviceModelVersion"); 35 | const { userName } = req.body; 36 | 37 | if (!deviceID || !userName) { 38 | return res.status(400).json({ message: "Missing required parameters" }); 39 | } 40 | 41 | res.status(200).json({ 42 | operationID: generateOperationID() 43 | }); 44 | }; 45 | 46 | export const createUser = (req: Request, res: Response) => { 47 | const { deviceID } = req.params; 48 | const DeviceModelName = req.header("DeviceModelName"); 49 | const DeviceModelVersion = req.header("DeviceModelVersion"); 50 | const { userName, personName, personSurname, userRole } = req.body; 51 | 52 | if (!deviceID || !userName || !personName || !personSurname || !userRole) { 53 | return res.status(400).json({ 54 | "type": "https://httpstatuses.io/400", 55 | "title": "Bad Request", 56 | "status": 400, 57 | "detail": "Missing required parameters" 58 | }); 59 | } 60 | 61 | res.status(200).json({ 62 | operationID: generateOperationID(), 63 | message: "User created successfully.", 64 | }); 65 | }; 66 | 67 | export const loginUser = (req: Request, res: Response) => { 68 | const { deviceID } = req.params; 69 | const DeviceModelName = req.header("DeviceModelName"); 70 | const DeviceModelVersion = req.header("DeviceModelVersion"); 71 | const { userName, password } = req.body; 72 | 73 | if (!deviceID || !userName || !password) { 74 | return res.status(400).json({ 75 | "type": "https://httpstatuses.io/400", 76 | "title": "Bad Request", 77 | "status": 400, 78 | "detail": "Missing required parameters" 79 | }); 80 | } 81 | 82 | res.status(200).json({ 83 | operationID: generateOperationID(), 84 | token: "mock-jwt-token", 85 | user: { 86 | userName, 87 | personName: "John", 88 | personSurname: "Doe", 89 | userRole: "Admin", 90 | email: "john.doe@example.com", 91 | phoneNo: "+123456789", 92 | }, 93 | }); 94 | }; 95 | 96 | export const sendSecurityCodeToUserEmail = (req: Request, res: Response) => { 97 | const { deviceID } = req.params; 98 | const Token = req.header("Token"); 99 | const DeviceModelName = req.header("DeviceModelName"); 100 | const DeviceModelVersion = req.header("DeviceModelVersion"); 101 | const { userEmail } = req.body; 102 | 103 | if (!deviceID || !Token || !userEmail) { 104 | return res.status(400).json({ 105 | "type": "https://httpstatuses.io/400", 106 | "title": "Bad Request", 107 | "status": 400, 108 | "detail": "Missing required parameters" 109 | }); 110 | } 111 | 112 | res.status(200).json({ 113 | operationID: generateOperationID() 114 | }); 115 | }; 116 | 117 | 118 | export const sendSecurityCodeToUserPhone = (req: Request, res: Response) => { 119 | const { deviceID } = req.params; 120 | const Token = req.header("Token"); 121 | const DeviceModelName = req.header("DeviceModelName"); 122 | const DeviceModelVersion = req.header("DeviceModelVersion"); 123 | const { phoneNo } = req.body; 124 | 125 | if (!deviceID || !Token || !phoneNo) { 126 | return res.status(400).json({ 127 | "type": "https://httpstatuses.io/400", 128 | "title": "Bad Request", 129 | "status": 400, 130 | "detail": "Missing required parameters" 131 | }); 132 | } 133 | 134 | res.status(200).json({ 135 | operationID: generateOperationID() 136 | }); 137 | }; 138 | 139 | 140 | export const confirmUser = (req: Request, res: Response) => { 141 | const { deviceID } = req.params; 142 | const DeviceModelName = req.header("DeviceModelName"); 143 | const DeviceModelVersion = req.header("DeviceModelVersion"); 144 | const { userName, password, securityCode } = req.body; 145 | 146 | if (!deviceID || !userName || !password || !securityCode) { 147 | return res.status(400).json({ 148 | "type": "https://httpstatuses.io/400", 149 | "title": "Bad Request", 150 | "status": 400, 151 | "detail": "Missing required parameters" 152 | }); 153 | } 154 | 155 | // Check if userName is wrong 156 | if (userName === "invalid" || password === "invalid" || securityCode === "invalid") { 157 | return res.status(400).json({ 158 | type: "https://httpstatuses.io/400", 159 | title: "Bad Request", 160 | status: 400, 161 | detail: "Invalid details" 162 | }); 163 | } 164 | 165 | 166 | res.status(200).json({ 167 | operationID: generateOperationID(), 168 | "user": { 169 | "userName": "johndoe123", 170 | "personName": "John", 171 | "personSurname": "Doe", 172 | "userRole": "User", 173 | "email": "john.doe@example.com", 174 | "phoneNo": "+1234567890" 175 | }, 176 | "token": "string" 177 | }); 178 | }; 179 | 180 | export const changePassword = (req: Request, res: Response) => { 181 | const { deviceID } = req.params; 182 | const Token = req.header("Token"); 183 | const DeviceModelName = req.header("DeviceModelName"); 184 | const DeviceModelVersion = req.header("DeviceModelVersion"); 185 | const { oldPassword, newPassword } = req.body; 186 | 187 | if (!deviceID || !Token || !oldPassword || !newPassword) { 188 | return res.status(400).json({ 189 | "type": "https://httpstatuses.io/400", 190 | "title": "Bad Request", 191 | "status": 400, 192 | "detail": "Missing required parameters" 193 | }); 194 | } 195 | 196 | // Check if oldPassword is wrong 197 | if (oldPassword === "invalid") { 198 | return res.status(400).json({ 199 | type: "https://httpstatuses.io/400", 200 | title: "Bad Request", 201 | status: 400, 202 | detail: "Invalid old password" 203 | }); 204 | } 205 | 206 | res.status(200).json({ 207 | operationID: generateOperationID(), 208 | "user": { 209 | "userName": "johndoe123", 210 | "personName": "John", 211 | "personSurname": "Doe", 212 | "userRole": "User", 213 | "email": "john.doe@example.com", 214 | "phoneNo": "+1234567890" 215 | }, 216 | "token": "string" 217 | }); 218 | }; 219 | 220 | 221 | 222 | export const resetPassword = (req: Request, res: Response) => { 223 | const { deviceID } = req.params; 224 | const DeviceModelName = req.header("DeviceModelName"); 225 | const DeviceModelVersion = req.header("DeviceModelVersion"); 226 | const { userName, channel } = req.body; 227 | 228 | if (!deviceID || !userName || !channel) { 229 | return res.status(400).json({ 230 | "type": "https://httpstatuses.io/400", 231 | "title": "Bad Request", 232 | "status": 400, 233 | "detail": "Missing required parameters" 234 | }); 235 | } 236 | 237 | // Check if oldPassword is wrong 238 | if (userName === "invalid" || channel === "invalid") { 239 | return res.status(400).json({ 240 | type: "https://httpstatuses.io/400", 241 | title: "Bad Request", 242 | status: 400, 243 | detail: "Invalid user name or channel" 244 | }); 245 | } 246 | 247 | res.status(200).json({ 248 | operationID: generateOperationID() 249 | }); 250 | }; 251 | 252 | 253 | export const confirmContact = (req: Request, res: Response) => { 254 | const { deviceID } = req.params; 255 | 256 | const Token = req.header("Token"); 257 | 258 | const DeviceModelName = req.header("DeviceModelName"); 259 | const DeviceModelVersion = req.header("DeviceModelVersion"); 260 | const { securityCode,channel } = req.body; 261 | 262 | if (!deviceID || !securityCode || !channel) { 263 | return res.status(400).json({ 264 | "type": "https://httpstatuses.io/400", 265 | "title": "Bad Request", 266 | "status": 400, 267 | "detail": "Missing required parameters" 268 | }); 269 | } 270 | 271 | // Check if userName is wrong 272 | if (securityCode === "invalid" || channel === "invalid") { 273 | return res.status(400).json({ 274 | type: "https://httpstatuses.io/400", 275 | title: "Bad Request", 276 | status: 400, 277 | detail: "Invalid details" 278 | }); 279 | } 280 | 281 | 282 | res.status(200).json({ 283 | operationID: generateOperationID(), 284 | "user": { 285 | "userName": "johndoe123", 286 | "personName": "John", 287 | "personSurname": "Doe", 288 | "userRole": "User", 289 | "email": "john.doe@example.com", 290 | "phoneNo": "+1234567890" 291 | } 292 | }); 293 | }; 294 | 295 | 296 | 297 | export const update = (req: Request, res: Response) => { 298 | const { deviceID } = req.params; 299 | const Token = req.header("Token"); 300 | const DeviceModelName = req.header("DeviceModelName"); 301 | const DeviceModelVersion = req.header("DeviceModelVersion"); 302 | const { userName, personName, personSurname, userRole, userStatus } = req.body; 303 | 304 | if (!deviceID || !userName || !personName || !personSurname || !userRole || !userStatus) { 305 | return res.status(400).json({ 306 | "type": "https://httpstatuses.io/400", 307 | "title": "Bad Request", 308 | "status": 400, 309 | "detail": "Missing required parameters" 310 | }); 311 | } 312 | 313 | // Check if userName is wrong 314 | if (userName === "invalid") { 315 | return res.status(400).json({ 316 | type: "https://httpstatuses.io/400", 317 | title: "Bad Request", 318 | status: 400, 319 | detail: "Invalid details" 320 | }); 321 | } 322 | 323 | 324 | res.status(200).json({ 325 | operationID: generateOperationID() 326 | }); 327 | }; 328 | 329 | export const confirmPasswordReset = (req: Request, res: Response) => { 330 | const { deviceID } = req.params; 331 | 332 | const DeviceModelName = req.header("DeviceModelName"); 333 | const DeviceModelVersion = req.header("DeviceModelVersion"); 334 | const { userName, securityCode, newPassword } = req.body; 335 | 336 | if (!deviceID || !securityCode || !newPassword || !userName) { 337 | return res.status(400).json({ 338 | "type": "https://httpstatuses.io/400", 339 | "title": "Bad Request", 340 | "status": 400, 341 | "detail": "Missing required parameters" 342 | }); 343 | } 344 | 345 | // Check if userName is wrong 346 | if (securityCode === "invalid" || newPassword === "invalid") { 347 | return res.status(400).json({ 348 | type: "https://httpstatuses.io/400", 349 | title: "Bad Request", 350 | status: 400, 351 | detail: "Invalid details" 352 | }); 353 | } 354 | 355 | 356 | res.status(200).json({ 357 | operationID: generateOperationID(), 358 | "user": { 359 | "userName": "johndoe123", 360 | "personName": "John", 361 | "personSurname": "Doe", 362 | "userRole": "User", 363 | "email": "john.doe@example.com", 364 | "phoneNo": "+1234567890" 365 | }, 366 | "token": "string" 367 | }); 368 | }; -------------------------------------------------------------------------------- /src/controllers/Device/index.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from 'express'; 2 | 3 | import generateOperationID from '../../utils/generateOperationID'; 4 | 5 | 6 | import { 7 | CloseDayRequest, 8 | IssueCertificateRequest, 9 | OpenDayRequest, 10 | PingResponse, 11 | SubmitReceiptRequest, 12 | SubmittedFileHeaderDtoListResponse 13 | } from './device.types'; 14 | 15 | 16 | 17 | export const getConfig = async (req: Request, res: Response) => { 18 | 19 | const { deviceID } = req.params; 20 | const deviceModelName = req.header('DeviceModelName'); 21 | const deviceModelVersion = req.header('DeviceModelVersion'); 22 | 23 | if (!deviceID || isNaN(Number(deviceID))) { 24 | return res.status(400).json({ 25 | operationID: generateOperationID(), 26 | type: "https://httpstatuses.io/400", 27 | title: "Bad Request", 28 | status: 400, 29 | detail: "Invalid or missing deviceID", 30 | }); 31 | } 32 | 33 | if (!deviceModelName || !deviceModelVersion) { 34 | return res.status(422).json({ 35 | operationID: generateOperationID(), 36 | type: "https://httpstatuses.io/422", 37 | title: "Unprocessable Entity", 38 | status: 422, 39 | detail: "Missing required headers", 40 | }); 41 | } 42 | 43 | // Mock expired certificate response 44 | if (deviceID === "999") { 45 | return res.status(401).json({ 46 | operationID: generateOperationID(), 47 | type: "https://httpstatuses.io/401", 48 | title: "Unauthorized", 49 | status: 401, 50 | detail: "Device certificate expired.", 51 | }); 52 | } 53 | 54 | // Mock server error response 55 | if (deviceID === "500") { 56 | return res.status(500).json({ 57 | operationID: generateOperationID(), 58 | type: "https://httpstatuses.io/500", 59 | title: "Server error", 60 | status: 500 61 | }); 62 | } 63 | 64 | // Mock successful response 65 | return res.status(200).json({ 66 | operationID: generateOperationID(), 67 | taxPayerName: "Nienow, Hara and Schinner", 68 | taxPayerTIN: "3796605707", 69 | vatNumber: "3899488439", 70 | deviceSerialNo: `SN-${deviceID}`, 71 | deviceBranchName: "Shoes", 72 | deviceBranchAddress: { 73 | province: "Harare", 74 | street: "Torey Lakes", 75 | houseNo: "566", 76 | city: "Harare", 77 | }, 78 | deviceBranchContacts: { 79 | phoneNo: "(320) 238-4248", 80 | email: "Leland_Gutmann@yahoo.com", 81 | }, 82 | deviceOperatingMode: "Online", 83 | taxPayerDayMaxHrs: 24, 84 | applicableTaxes: [ 85 | { taxPercent: 15, taxName: "15%" }, 86 | { taxPercent: 0, taxName: "0%" }, 87 | { taxName: "exempt" }, 88 | ], 89 | certificateValidTill: "2026-03-30T17:15:40", 90 | qrUrl: "www.qrUrl.com", 91 | taxpayerDayEndNotificationHrs: 20 92 | }); 93 | 94 | }; 95 | 96 | export const getStatus = async (req: Request, res: Response) => { 97 | const { deviceID } = req.params; 98 | const deviceModelName = req.header('DeviceModelName'); 99 | const deviceModelVersion = req.header('DeviceModelVersion'); 100 | 101 | if (!deviceID || isNaN(Number(deviceID))) { 102 | return res.status(400).json({ 103 | operationID: generateOperationID(), 104 | type: "https://httpstatuses.io/400", 105 | title: "Bad Request", 106 | status: 400, 107 | detail: "Invalid or missing deviceID", 108 | }); 109 | } 110 | 111 | if (!deviceModelName || !deviceModelVersion) { 112 | return res.status(422).json({ 113 | operationID: generateOperationID(), 114 | type: "https://httpstatuses.io/422", 115 | title: "Unprocessable Entity", 116 | status: 422, 117 | detail: "Missing required headers", 118 | }); 119 | } 120 | 121 | // Mock expired certificate response 122 | if (deviceID === "999") { 123 | return res.status(401).json({ 124 | operationID: generateOperationID(), 125 | type: "https://httpstatuses.io/401", 126 | title: "Unauthorized", 127 | status: 401, 128 | detail: "Device certificate expired.", 129 | }); 130 | } 131 | 132 | // Mock server error response 133 | if (deviceID === "500") { 134 | return res.status(500).json({ 135 | operationID: generateOperationID(), 136 | type: "https://httpstatuses.io/500", 137 | title: "Server error", 138 | status: 500 139 | }); 140 | } 141 | 142 | // Mock successful response 143 | return res.status(200).json({ 144 | operationID: generateOperationID(), 145 | fiscalDayStatus: "FiscalDayClosed", 146 | fiscalDayReconciliationMode: "Auto", 147 | fiscalDayServerSignature: { 148 | certificateThumbprint: "b785a0b4d8a734a55ba595d143b4cf72834cd88d", 149 | hash: "//To59fLHvuoRe2slUpN2grJu5adaodOW6kW1OYvf/c=", 150 | signature: "YyXTSizBBrMjMk4VQL+sCNr+2AC6aQbDAn9JMV2rk3yJ6MDZwie0wqQW3oisNWrMkeZsuAyFSnFkU2A+pKm91sOHVdjeRBebjQgAQQIMTCVIcYrx+BizQ7Ib9iCdsVI+Jel2nThqQiQzfRef6EgtgsaIAN+PV55xSrHvPkIe+Bc=" 151 | }, 152 | fiscalDayClosed: "2023-03-30T20:15:40", 153 | lastFiscalDayNo: 101, 154 | lastReceiptGlobalNo: 9931, 155 | }); 156 | } 157 | 158 | 159 | export const openDay = async (req: Request, res: Response) => { 160 | const { deviceID } = req.params; 161 | const deviceModelName = req.header('DeviceModelName'); 162 | const deviceModelVersion = req.header('DeviceModelVersion'); 163 | const requestBody: OpenDayRequest = req.body; 164 | 165 | // Check if deviceID is provided and is valid 166 | if (!deviceID || isNaN(Number(deviceID))) { 167 | return res.status(400).json({ 168 | operationID: generateOperationID(), 169 | type: "https://httpstatuses.io/400", 170 | title: "Bad Request", 171 | status: 400, 172 | detail: "Invalid or missing deviceID", 173 | }); 174 | } 175 | 176 | // Validate that the required headers are provided 177 | if (!deviceModelName || !deviceModelVersion) { 178 | return res.status(422).json({ 179 | operationID: generateOperationID(), 180 | type: "https://httpstatuses.io/422", 181 | title: "Unprocessable Entity", 182 | status: 422, 183 | detail: "Missing required headers", 184 | }); 185 | } 186 | 187 | // Simulate expired certificate scenario 188 | if (deviceID === "999") { 189 | return res.status(401).json({ 190 | operationID: generateOperationID(), 191 | type: "https://httpstatuses.io/401", 192 | title: "Unauthorized", 193 | status: 401, 194 | detail: "Device certificate expired.", 195 | }); 196 | } 197 | 198 | // Simulate server error scenario 199 | if (deviceID === "500") { 200 | return res.status(500).json({ 201 | operationID: generateOperationID(), 202 | type: "https://httpstatuses.io/500", 203 | title: "Server error", 204 | status: 500, 205 | }); 206 | } 207 | 208 | // Simulate success response 209 | return res.status(200).json({ 210 | operationID: generateOperationID(), 211 | fiscalDayNo: 102, 212 | }); 213 | } 214 | 215 | export const closeDay = async (req: Request, res: Response) => { 216 | 217 | const { deviceID } = req.params; 218 | const deviceModelName = req.header('DeviceModelName'); 219 | const deviceModelVersion = req.header('DeviceModelVersion'); 220 | const requestBody: CloseDayRequest = req.body; 221 | 222 | // Validate deviceID 223 | if (!deviceID || isNaN(Number(deviceID))) { 224 | return res.status(400).json({ 225 | operationID: generateOperationID(), 226 | type: "https://httpstatuses.io/400", 227 | title: "Bad Request", 228 | status: 400, 229 | detail: "Invalid or missing deviceID", 230 | }); 231 | } 232 | 233 | // Validate required headers 234 | if (!deviceModelName || !deviceModelVersion) { 235 | return res.status(422).json({ 236 | operationID: generateOperationID(), 237 | type: "https://httpstatuses.io/422", 238 | title: "Unprocessable Entity", 239 | status: 422, 240 | detail: "Missing required headers: DeviceModelName or DeviceModelVersion", 241 | }); 242 | } 243 | 244 | // Simulate expired certificate scenario 245 | if (deviceID === "999") { 246 | return res.status(401).json({ 247 | operationID: generateOperationID(), 248 | type: "https://httpstatuses.io/401", 249 | title: "Unauthorized", 250 | status: 401, 251 | detail: "Device certificate expired.", 252 | }); 253 | } 254 | 255 | // Simulate server error scenario 256 | if (deviceID === "500") { 257 | return res.status(500).json({ 258 | operationID: generateOperationID(), 259 | type: "https://httpstatuses.io/500", 260 | title: "Server error", 261 | status: 500 262 | }); 263 | } 264 | 265 | // Simulate successful Close Day response 266 | return res.status(200).json({ 267 | operationID: generateOperationID(), 268 | }); 269 | 270 | } 271 | 272 | 273 | 274 | export const issueCertificate = async (req: Request, res: Response) => { 275 | const { deviceID } = req.params; 276 | const deviceModelName = req.header('DeviceModelName'); 277 | const deviceModelVersion = req.header('DeviceModelVersion'); 278 | const requestBody: IssueCertificateRequest = req.body; 279 | 280 | // Validate deviceID 281 | if (!deviceID || isNaN(Number(deviceID))) { 282 | return res.status(400).json({ 283 | operationID: generateOperationID(), 284 | type: "https://httpstatuses.io/400", 285 | title: "Bad Request", 286 | status: 400, 287 | detail: "Invalid or missing deviceID", 288 | }); 289 | } 290 | 291 | // Validate required headers 292 | if (!deviceModelName || !deviceModelVersion) { 293 | return res.status(422).json({ 294 | operationID: generateOperationID(), 295 | type: "https://httpstatuses.io/422", 296 | title: "Unprocessable Entity", 297 | status: 422, 298 | detail: "Missing required headers: DeviceModelName or DeviceModelVersion", 299 | }); 300 | } 301 | 302 | // Simulate expired certificate scenario 303 | if (deviceID === "999") { 304 | return res.status(401).json({ 305 | operationID: generateOperationID(), 306 | type: "https://httpstatuses.io/401", 307 | title: "Unauthorized", 308 | status: 401, 309 | detail: "Device certificate expired.", 310 | }); 311 | } 312 | 313 | // Simulate server error scenario 314 | if (deviceID === "500") { 315 | return res.status(500).json({ 316 | operationID: generateOperationID(), 317 | type: "https://httpstatuses.io/500", 318 | title: "Server error", 319 | status: 500, 320 | }); 321 | } 322 | 323 | // Simulate successful certificate issuance 324 | return res.status(200).json({ 325 | operationID: generateOperationID(), 326 | certificate: `-----BEGIN CERTIFICATE----- 327 | MIIC6TCCAdGgAwIBAgIFAKsSzWowDQYJKoZIhvcNAQELBQAwZDELMAkGA1UEBhMC 328 | TFQxETAPBgNVBAoMCEdvb2QgTHRkMScwJQYDVQQLDB5Hb29kIEx0ZCBDZXJ0aWZp 329 | Y2F0ZSBBdXRob3JpdHkxGTAXBgNVBAMMEEdvb2QgTHRkIFJvb3QgQ0EwHhcNMTkx 330 | MDAzMTU1NzA1WhcNMjAxMDEyMTU1NzA1WjBfMQswCQYDVQQGEwJUWjERMA8GA1UE 331 | CAwIWmFuemliYXIxHzAdBgNVBAoMFlphbnppYmFyIFJldmVudWUgQm9hcmQxHDAa 332 | BgNVBAMME1pSQi1lVkZELTAwMDAwMDAwNDIwWTATBgcqhkjOPQIBBggqhkjOPQMB 333 | BwNCAAT7v3DvY7pRg4lz2Z87wSMwSX27KwlpYnSRV6WUiPjpq2XsUAbg2lhUN7q3 334 | mlNJaUzqoKPmop5qURIpqUydXfapo3IwcDAJBgNVHRMEAjAAMB8GA1UdIwQYMBaA 335 | FK1RXHm1plvaintqlWaXDs1X3LX+MB0GA1UdDgQWBBRqr96XrCUbuwCQawxO0//n 336 | TOCoNTAOBgNVHQ8BAf8EBAMCBeAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDQYJKoZI 337 | hvcNAQELBQADggEBANr1Wk1cVZB96yobFgK3rQQv9oXW+Jle7Jh36J2o4wSSB+RH 338 | lfMojDrqKVQCLrFDcF+8JIA3RTRKdduIXgBAr13xQ8JkHd1/o23yN6a2DaYgh0wr 339 | DrndlR6y1yG0vQuurJ3IgXmC0ldM5+VhalgmoCKFV9JsUD+GhOyJ6NWlc0SqvJCs 340 | 3RZLYwZ4MNViPbRy0Kbp0ufY1zTbh02Gw9aVfFzUwL8GS00iMb4MnSav1xur7wQh 341 | BoF3PpNvu003P7f1eVJ62qVD2LWWntfn0mL1aRmDe2wpMQKAKhxto+sDb2mfJ6G6 342 | PFtwMHe7BUfiwTzGYqav21h1w/amPkxNVQ7Li4M= 343 | -----END CERTIFICATE-----` 344 | }); 345 | 346 | } 347 | 348 | 349 | export const submitReciept = async (req: Request, res: Response) => { 350 | 351 | const { deviceID } = req.params; // deviceID from path 352 | const deviceModelName = req.header('DeviceModelName'); 353 | const deviceModelVersion = req.header('DeviceModelVersion'); 354 | const requestBody: SubmitReceiptRequest = req.body; // Body of the request 355 | 356 | // Handle mock responses based on some conditions 357 | if (!deviceModelName || !deviceModelVersion) { 358 | return res.status(400).json({ 359 | type: 'https://httpstatuses.io/400', 360 | title: 'Bad Request', 361 | status: 400, 362 | operationID: generateOperationID(), 363 | }); 364 | } 365 | 366 | if (deviceID === '12345') { 367 | return res.status(401).json({ 368 | type: 'https://httpstatuses.io/401', 369 | title: 'Device certificate expired.', 370 | status: 401, 371 | operationID: generateOperationID(), 372 | }); 373 | } 374 | 375 | // Simulate server error for some condition 376 | if (deviceID === '99999') { 377 | return res.status(500).json({ 378 | type: 'https://httpstatuses.io/500', 379 | title: 'Server error', 380 | status: 500, 381 | operationID: generateOperationID(), 382 | }); 383 | } 384 | 385 | // On success, return the mock response 386 | return res.status(200).json({ 387 | receiptID: 600, 388 | serverDate: '2023-05-04T16:45:37', 389 | receiptServerSignature: { 390 | certificateThumbprint: 'F9B295CA65BA22B94F6D4B27E48D08BF6CD7F7C8', 391 | hash: '8IURjBbdTy2b6EnUzSEHHCjIenorq5TdYSCtuzCVisw=', 392 | signature: 'gz/JZQVw5Mk7vCTVx02hrZEQS1vAnMIEnwVdl/eouL9SkYbmZFrfQLVtfhPwxM2SCzgrqf9dpuQi1/t9u7T1t5Vvl/vkMW8FLH0u2IReOXLakxFx9TNWu7XH20FqjCJLXOB3NYAiVshAHtYpwPmU9gYCJBTwfhKAjmJaYpIkUvXE+cXKsV4Zxuvm7y25jOGs2RlLExmVw2uT53aRLoLbHdIxaelq8Pgx+YEJQNz9/AniRyjQRdOD5FyQgu00IU9SydrcpkM6xA01fHsNnB53ATb6CdGBAXv88I42n6o8E784CI8wCGWTF6lEoN6sMnLQPqyxY9YQj0ZxcvW5xhC9uA==', 393 | }, 394 | operationID: generateOperationID(), 395 | }); 396 | } 397 | 398 | 399 | export const ping = async (req: Request, res: Response) => { 400 | // Extract path parameter (deviceID) and headers (DeviceModelName and DeviceModelVersion) 401 | const { deviceID } = req.params; // deviceID from path 402 | const deviceModelName = req.header('DeviceModelName'); 403 | const deviceModelVersion = req.header('DeviceModelVersion'); 404 | 405 | // Check if the required parameters are missing 406 | if (!deviceModelName || !deviceModelVersion) { 407 | return res.status(400).json({ 408 | type: 'https://httpstatuses.io/400', 409 | title: 'Bad Request', 410 | status: 400, 411 | operationID: '00000000', 412 | }); 413 | } 414 | 415 | // Simulate device certificate expiration 416 | if (deviceID === '12345') { 417 | return res.status(401).json({ 418 | type: 'https://httpstatuses.io/401', 419 | title: 'Device certificate expired.', 420 | status: 401, 421 | operationID: '0HMPDRRQL1C0G:00000005', 422 | }); 423 | } 424 | 425 | // Simulate server error for specific deviceID 426 | if (deviceID === '99999') { 427 | return res.status(500).json({ 428 | type: 'https://httpstatuses.io/500', 429 | title: 'Server error', 430 | status: 500, 431 | operationID: '0HMPDRRQL1C0G:00000005', 432 | }); 433 | } 434 | 435 | // Simulate success response with a mock PingResponse 436 | // Return the success response with a 200 status code 437 | return res.status(200).json({ 438 | reportingFrequency: 5, 439 | operationID: '0HMS2LV2BED20:00000001', 440 | }); 441 | 442 | } 443 | 444 | export const submitFile = async (req: Request, res: Response) => { 445 | 446 | const { deviceID } = req.params; 447 | const DeviceModelName = req.header('DeviceModelName'); 448 | const DeviceModelVersion = req.header('DeviceModelVersion'); 449 | const requestBody = req.body; 450 | 451 | if (!requestBody.content) { 452 | return res.status(400).json({ 453 | operationId: generateOperationID(), 454 | type: 'https://httpstatuses.io/400', 455 | title: 'Bad request', 456 | status: 400, 457 | detail: 'Content is empty', 458 | }); 459 | } 460 | 461 | 462 | 463 | if (!deviceID || !DeviceModelName || !DeviceModelVersion || !requestBody) { 464 | return res.status(400).json({ 465 | type: 'https://httpstatuses.io/400', 466 | title: 'Bad request', 467 | status: 400, 468 | detail: 'Required parameters are missing', 469 | }); 470 | } 471 | 472 | if (deviceID !== '1111') { 473 | return res.status(404).json({ 474 | type: 'https://httpstatuses.io/404', 475 | title: 'Not Found', 476 | status: 404, 477 | detail: "Not existing device with provided device id", 478 | }); 479 | } 480 | 481 | if (requestBody.footer.fiscalDayCounters[0].fiscalCounterType !== 'saleByTax') { 482 | return res.status(422).json({ 483 | type: 'https://httpstatuses.io/422', 484 | title: 'Unprocessable Entity', 485 | status: 422, 486 | detail: 'Device fiscal day status must be FiscalDayClosed', 487 | }); 488 | } 489 | 490 | return res.status(200).json({ 491 | operationID: generateOperationID(), 492 | 493 | }); 494 | } 495 | 496 | export const submittedFileList = async (req: Request, res: Response) => { 497 | 498 | const { 499 | OperationID, 500 | FileUploadedFrom, 501 | FileUploadedTill, 502 | Sort, 503 | Order, 504 | Offset, 505 | Limit, 506 | Operator, 507 | } = req.query; 508 | 509 | const { deviceID } = req.params; 510 | const { DeviceModelName, DeviceModelVersion } = req.headers; 511 | 512 | console.log('Received parameters:', req.query); 513 | 514 | // Mock response data 515 | const responseData: SubmittedFileHeaderDtoListResponse = { 516 | files: [ 517 | { 518 | fileName: 'file1.txt', 519 | uploadedAt: '2023-02-11T10:00:00Z', 520 | status: 'processed', 521 | }, 522 | { 523 | fileName: 'file2.txt', 524 | uploadedAt: '2023-02-10T09:30:00Z', 525 | status: 'pending', 526 | }, 527 | ], 528 | }; 529 | 530 | // Mock response codes based on parameters or logic 531 | if (deviceID === 'invalid') { 532 | return res.status(404).json({ 533 | operationId: generateOperationID(), 534 | type: 'https://httpstatuses.io/404', 535 | title: 'Not Found', 536 | status: 404, 537 | detail: 'Not existing device with provided device id', 538 | }); 539 | } 540 | 541 | if (!OperationID) { 542 | return res.status(400).json({ 543 | operationId: generateOperationID(), 544 | type: 'https://httpstatuses.io/400', 545 | title: 'Bad request', 546 | status: 400, 547 | detail: 'Operation ID is missing', 548 | }); 549 | } 550 | 551 | return res.status(200).json({ 552 | operationId: generateOperationID(), 553 | files: responseData.files, 554 | }); 555 | } -------------------------------------------------------------------------------- /swagger/Public-1.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.1", 3 | "info": { 4 | "title": "Fiscal backend FiscalDeviceApi Build:1.0.0.0", 5 | "version": "1.0" 6 | }, 7 | "paths": { 8 | "/Public/v1/{deviceID}/RegisterDevice": { 9 | "post": { 10 | "tags": [ 11 | "Public" 12 | ], 13 | "description": "Endpoint is used to get device certificate and register device in Fiscalisation Backend (link device with Fiscalisation Backend).", 14 | "parameters": [ 15 | { 16 | "name": "deviceID", 17 | "in": "path", 18 | "description": "Sold or active device ID", 19 | "required": true, 20 | "schema": { 21 | "type": "integer", 22 | "format": "int32" 23 | } 24 | }, 25 | { 26 | "name": "DeviceModelName", 27 | "in": "header", 28 | "description": "Device model name as registered in Tax Authority", 29 | "required": true, 30 | "schema": { 31 | "type": "string" 32 | } 33 | }, 34 | { 35 | "name": "DeviceModelVersion", 36 | "in": "header", 37 | "description": "Device model version number as registered in Tax Authority", 38 | "required": true, 39 | "schema": { 40 | "type": "string" 41 | } 42 | } 43 | ], 44 | "requestBody": { 45 | "description": "", 46 | "content": { 47 | "application/json": { 48 | "schema": { 49 | "allOf": [ 50 | { 51 | "$ref": "#/components/schemas/RegisterDeviceRequest" 52 | } 53 | ] 54 | } 55 | } 56 | }, 57 | "required": true 58 | }, 59 | "responses": { 60 | "400": { 61 | "description": "Bad Request", 62 | "headers": { 63 | "operationId": { 64 | "description": "unique operation id", 65 | "schema": { 66 | "type": "string", 67 | "description": "unique operation id", 68 | "format": "" 69 | } 70 | } 71 | }, 72 | "content": { 73 | "application/problem+json": { 74 | "schema": { 75 | "$ref": "#/components/schemas/ValidationProblemDetails" 76 | } 77 | } 78 | } 79 | }, 80 | "422": { 81 | "description": "Operation failed because of provided data or invalid object state in Fiscal backend. Returns problem details structure as described in https://www.rfc-editor.org/rfc/rfc7807 with errorCode field to specify error.", 82 | "headers": { 83 | "operationId": { 84 | "description": "unique operation id", 85 | "schema": { 86 | "type": "string", 87 | "description": "unique operation id", 88 | "format": "" 89 | } 90 | } 91 | }, 92 | "content": { 93 | "application/problem+json": { 94 | "schema": { 95 | "$ref": "#/components/schemas/ApiProblemDetails" 96 | }, 97 | "example": { 98 | "errorCode": "DEV01", 99 | "type": "https://httpstatuses.io/422", 100 | "title": "Unprocessable Entity", 101 | "status": 422, 102 | "detail": "Device not found or not active", 103 | "operationID": "0HMPDRRQL1C0G:00000005" 104 | } 105 | } 106 | } 107 | }, 108 | "500": { 109 | "description": "Server encountered temporary issues.", 110 | "headers": { 111 | "operationId": { 112 | "description": "unique operation id", 113 | "schema": { 114 | "type": "string", 115 | "description": "unique operation id", 116 | "format": "" 117 | } 118 | } 119 | }, 120 | "content": { 121 | "application/problem+json": { 122 | "schema": { 123 | "$ref": "#/components/schemas/ProblemDetails" 124 | }, 125 | "example": { 126 | "type": "https://httpstatuses.io/500", 127 | "title": "Server error", 128 | "status": 500, 129 | "operationID": "0HMPDRRQL1C0G:00000005" 130 | } 131 | } 132 | } 133 | }, 134 | "200": { 135 | "description": "Success", 136 | "headers": { 137 | "operationId": { 138 | "description": "unique operation id", 139 | "schema": { 140 | "type": "string", 141 | "description": "unique operation id", 142 | "format": "" 143 | } 144 | } 145 | }, 146 | "content": { 147 | "application/json": { 148 | "schema": { 149 | "$ref": "#/components/schemas/RegisterDeviceResponse" 150 | }, 151 | "example": { 152 | "operationID": "0HMPH9AF0QKKE:00000005", 153 | "certificate": "-----BEGIN CERTIFICATE-----\nMIIC6TCCAdGgAwIBAgIFAKsSzWowDQYJKoZIhvcNAQELBQAwZDELMAkGA1UEBhMC\nTFQxETAPBgNVBAoMCEdvb2QgTHRkMScwJQYDVQQLDB5Hb29kIEx0ZCBDZXJ0aWZp\nY2F0ZSBBdXRob3JpdHkxGTAXBgNVBAMMEEdvb2QgTHRkIFJvb3QgQ0EwHhcNMTkx\nMDAzMTU1NzA1WhcNMjAxMDEyMTU1NzA1WjBfMQswCQYDVQQGEwJUWjERMA8GA1UE\nCAwIWmFuemliYXIxHzAdBgNVBAoMFlphbnppYmFyIFJldmVudWUgQm9hcmQxHDAa\nBgNVBAMME1pSQi1lVkZELTAwMDAwMDAwNDIwWTATBgcqhkjOPQIBBggqhkjOPQMB\nBwNCAAT7v3DvY7pRg4lz2Z87wSMwSX27KwlpYnSRV6WUiPjpq2XsUAbg2lhUN7q3\nmlNJaUzqoKPmop5qURIpqUydXfapo3IwcDAJBgNVHRMEAjAAMB8GA1UdIwQYMBaA\nFK1RXHm1plvaintqlWaXDs1X3LX+MB0GA1UdDgQWBBRqr96XrCUbuwCQawxO0//n\nTOCoNTAOBgNVHQ8BAf8EBAMCBeAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDQYJKoZI\nhvcNAQELBQADggEBANr1Wk1cVZB96yobFgK3rQQv9oXW+Jle7Jh36J2o4wSSB+RH\nlfMojDrqKVQCLrFDcF+8JIA3RTRKdduIXgBAr13xQ8JkHd1/o23yN6a2DaYgh0wr\nDrndlR6y1yG0vQuurJ3IgXmC0ldM5+VhalgmoCKFV9JsUD+GhOyJ6NWlc0SqvJCs\n3RZLYwZ4MNViPbRy0Kbp0ufY1zTbh02Gw9aVfFzUwL8GS00iMb4MnSav1xur7wQh\nBoF3PpNvu003P7f1eVJ62qVD2LWWntfn0mL1aRmDe2wpMQKAKhxto+sDb2mfJ6G6\nPFtwMHe7BUfiwTzGYqav21h1w/amPkxNVQ7Li4M=\n-----END CERTIFICATE-----" 154 | } 155 | } 156 | } 157 | } 158 | } 159 | } 160 | }, 161 | "/Public/v1/GetServerCertificate": { 162 | "get": { 163 | "tags": [ 164 | "Public" 165 | ], 166 | "description": "Endpoint is used to retrieve Fiscalisation Backend certificate for Fiscalisation Backend signature validation. Despite of the parameter is provided or not, and despite what certificate in the chain thumbprint indicates (first, second or third level certificate), full certificate chain is returned", 167 | "parameters": [ 168 | { 169 | "name": "thumbprint", 170 | "in": "query", 171 | "description": "Thumbprint of Fiscalisation Backend certificate which should be returned. If field is not provided, currently active Fiscalisation Backend signing certificate is returned", 172 | "schema": { 173 | "maxLength": 40, 174 | "minLength": 0, 175 | "type": "string" 176 | }, 177 | "example": "b785a0b4d8a734a55ba595d143b4cf72834cd88d" 178 | } 179 | ], 180 | "responses": { 181 | "400": { 182 | "description": "Bad Request", 183 | "headers": { 184 | "operationId": { 185 | "description": "unique operation id", 186 | "schema": { 187 | "type": "string", 188 | "description": "unique operation id", 189 | "format": "" 190 | } 191 | } 192 | }, 193 | "content": { 194 | "application/problem+json": { 195 | "schema": { 196 | "$ref": "#/components/schemas/ValidationProblemDetails" 197 | } 198 | } 199 | } 200 | }, 201 | "422": { 202 | "description": "Operation failed because of provided data or invalid object state in Fiscal backend. Returns problem details structure as described in https://www.rfc-editor.org/rfc/rfc7807 with errorCode field to specify error.", 203 | "headers": { 204 | "operationId": { 205 | "description": "unique operation id", 206 | "schema": { 207 | "type": "string", 208 | "description": "unique operation id", 209 | "format": "" 210 | } 211 | } 212 | }, 213 | "content": { 214 | "application/problem+json": { 215 | "schema": { 216 | "$ref": "#/components/schemas/ApiProblemDetails" 217 | }, 218 | "example": { 219 | "errorCode": "DEV01", 220 | "type": "https://httpstatuses.io/422", 221 | "title": "Unprocessable Entity", 222 | "status": 422, 223 | "detail": "Device not found or not active", 224 | "operationID": "0HMPDRRQL1C0G:00000005" 225 | } 226 | } 227 | } 228 | }, 229 | "500": { 230 | "description": "Server encountered temporary issues.", 231 | "headers": { 232 | "operationId": { 233 | "description": "unique operation id", 234 | "schema": { 235 | "type": "string", 236 | "description": "unique operation id", 237 | "format": "" 238 | } 239 | } 240 | }, 241 | "content": { 242 | "application/problem+json": { 243 | "schema": { 244 | "$ref": "#/components/schemas/ProblemDetails" 245 | }, 246 | "example": { 247 | "type": "https://httpstatuses.io/500", 248 | "title": "Server error", 249 | "status": 500, 250 | "operationID": "0HMPDRRQL1C0G:00000005" 251 | } 252 | } 253 | } 254 | }, 255 | "200": { 256 | "description": "Success", 257 | "headers": { 258 | "operationId": { 259 | "description": "unique operation id", 260 | "schema": { 261 | "type": "string", 262 | "description": "unique operation id", 263 | "format": "" 264 | } 265 | } 266 | }, 267 | "content": { 268 | "application/json": { 269 | "schema": { 270 | "$ref": "#/components/schemas/GetServerCertificateResponse" 271 | }, 272 | "example": { 273 | "operationID": "0HMPHA0KCMPHN:00000005", 274 | "certificate": [ 275 | "-----BEGIN CERTIFICATE-----\nMIIDQTCCAikCFFLwDNnN3ZnAriN4wanJF439cX53MA0GCSqGSIb3DQEBCwUAMF0x\nCzAJBgNVBAYTAkxUMRMwEQYDVQQIDApFTEVLVFJFTkFJMRMwEQYDVQQHDApFTEVL\nVFJFTkFJMREwDwYDVQQKDAhldHJvbmlrYTERMA8GA1UEAwwIemltcmFfQ0EwHhcN\nMjMwMzE2MTA1NDAxWhcNMzMwMzEzMTA1NDAxWjBdMQswCQYDVQQGEwJMVDETMBEG\nA1UECAwKRUxFS1RSRU5BSTETMBEGA1UEBwwKRUxFS1RSRU5BSTERMA8GA1UECgwI\nZXRyb25pa2ExETAPBgNVBAMMCHppbXJhX0NBMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEA30dU24HCzSd+y4/ho41at23gh1g2Yjhk8SnUNo5PLn2uoUvj\nUemQNuJFjg14LvBPoubcIfOZW6cp9TCGy8KqG3WyVrT9z9sEl4fQMlEsCegmCEIE\nng7PvtsdJL9CaC7x11KK4az5UpzqUQ2gyYOryF6M8BT6wH5U61og2SWfv4M5ttQc\nbBDFbReeCYBLvSzFisI1CAVnc3CLqLhBN5jHxfraeZyAvLzBFnbYj7RBcv28iGRz\ny6LXtgE9yDeRdtCk8UqrgyMe//LWmlu+mmLb2IdIeD66GkD637FURa9lAcDJksUP\nUep2TyXq44JjMeNz7CyPbJ0wlV49cUlKc+/ZVQIDAQABMA0GCSqGSIb3DQEBCwUA\nA4IBAQAPVhhMAvjpQRm9OqZz3k97/yygqxeNKdTjxc/zVO8gj0pRBclVhxCnfj+P\nA1wc1nBEHvZ0oh03JviGQ8wxTLWUc0vWlZICmST7heC3DeA+xh90mLZOb2kK3cko\nY7kTAQ8cLV+ddI4UI46WQ6q/bhueOZQjMf1K2IP0fUhXxgFtrPXXrlkiUNX4tisg\ncy986/JjIHk2sY3OyBqYeFwq5J6DO2kMfLgHzwlaVWnTiXJ/etK17fynETImldZU\n9qSHYEyURqKuDyjELRThDLDTGwnsL5HU31+RCmGCZuNpjqkdne8hedNISdyCsMvD\ndDY0A7Vf+2WmfxWzg0wbhf6cIjxS\n-----END CERTIFICATE-----", 276 | "-----BEGIN CERTIFICATE-----\nMIIDcDCCAligAwIBAgIISVJfo63v2tswDQYJKoZIhvcNAQELBQAwXTELMAkGA1UE\nBhMCTFQxEzARBgNVBAgMCkVMRUtUUkVOQUkxEzARBgNVBAcMCkVMRUtUUkVOQUkx\nETAPBgNVBAoMCGV0cm9uaWthMREwDwYDVQQDDAh6aW1yYV9DQTAeFw0yMzAzMjAx\nOTM5NTVaFw0yNjAzMjAyMTIzMTBaMGwxCzAJBgNVBAYTAlpXMREwDwYDVQQIDAha\naW1iYWJ3ZTEsMCoGA1UECgwjWmltYmFid2UgRmlzY2FsaXNhdGlvbiBPcmdhbml6\nYXRpb24xHDAaBgNVBAMME1pSQi1lVkZELTAwMDAwMDAwNDIwWTATBgcqhkjOPQIB\nBggqhkjOPQMBBwNCAAT7v3DvY7pRg4lz2Z87wSMwSX27KwlpYnSRV6WUiPjpq2Xs\nUAbg2lhUN7q3mlNJaUzqoKPmop5qURIpqUydXfapo4HvMIHsMAkGA1UdEwQCMAAw\nHQYDVR0OBBYEFGqv3pesJRu7AJBrDE7T/+dM4Kg1MIGaBgNVHSMEgZIwgY+AFIKH\n58WkIDv0AUhEr+O0qvs6Dk7VoWGkXzBdMQswCQYDVQQGEwJMVDETMBEGA1UECAwK\nRUxFS1RSRU5BSTETMBEGA1UEBwwKRUxFS1RSRU5BSTERMA8GA1UECgwIZXRyb25p\na2ExETAPBgNVBAMMCHppbXJhX0NBghRS8AzZzd2ZwK4jeMGpyReN/XF+dzAOBgNV\nHQ8BAf8EBAMCBeAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQAD\nggEBAMkQykLAfhUGYaMR71kdwgFShstjK12v0sg69ruNtnlIajs3H9vaYoZRvPOV\n5jkdKlzF4Erp8D9URTJQD9aNCHqOZg1wSytuQqxedoThaWSYL3eiUf3Rig+II/fG\n/F+sr0pC6QrriJKRHH8aeAUF2jXD/CyI/GcftBIMTr91egV5Bn3Pjwfh8aEFzq7R\nqF4p0p8UBPwJtFUSqC4JkwLkpfG8bMpNHYic97+PRRLlrqiSPrQF/rlLQDC4IpMc\n9oMHuYHi2CmMcpnXLNZhgeFhHpILKOloU/AGtsExDS4gHCm/LfkUAz3p0KTIxnfx\nj5QjByFH8P3rY05BmSdE4aFUnxM=\n-----END CERTIFICATE-----" 277 | ], 278 | "certificateValidTill": "2026-03-20T21:23:10" 279 | } 280 | } 281 | } 282 | }, 283 | "404": { 284 | "description": "Certificate requested by thumbprint not found", 285 | "headers": { 286 | "operationId": { 287 | "description": "unique operation id", 288 | "schema": { 289 | "type": "string", 290 | "description": "unique operation id", 291 | "format": "" 292 | } 293 | } 294 | }, 295 | "content": { 296 | "application/problem+json": { 297 | "schema": { 298 | "$ref": "#/components/schemas/ProblemDetails" 299 | }, 300 | "example": { 301 | "type": "https://httpstatuses.io/404", 302 | "title": "Not Found", 303 | "status": 400, 304 | "operationID": "0HMPDRRQL1C0G:00000005" 305 | } 306 | } 307 | } 308 | } 309 | } 310 | } 311 | }, 312 | "/Public/v1/{deviceID}/VerifyTaxpayerInformation": { 313 | "post": { 314 | "tags": [ 315 | "Public" 316 | ], 317 | "description": "Endpoint is used to retrieve taxpayer information from system before device registration (in order user could double check if device is going to be registered to correct taxpayer).", 318 | "parameters": [ 319 | { 320 | "name": "deviceID", 321 | "in": "path", 322 | "description": "Sold or active device ID", 323 | "required": true, 324 | "schema": { 325 | "type": "integer", 326 | "format": "int32" 327 | } 328 | } 329 | ], 330 | "requestBody": { 331 | "description": "", 332 | "content": { 333 | "application/json": { 334 | "schema": { 335 | "allOf": [ 336 | { 337 | "$ref": "#/components/schemas/VerifyTaxpayerInformationRequest" 338 | } 339 | ] 340 | } 341 | } 342 | }, 343 | "required": true 344 | }, 345 | "responses": { 346 | "400": { 347 | "description": "Bad Request", 348 | "headers": { 349 | "operationId": { 350 | "description": "unique operation id", 351 | "schema": { 352 | "type": "string", 353 | "description": "unique operation id", 354 | "format": "" 355 | } 356 | } 357 | }, 358 | "content": { 359 | "application/problem+json": { 360 | "schema": { 361 | "$ref": "#/components/schemas/ValidationProblemDetails" 362 | } 363 | } 364 | } 365 | }, 366 | "422": { 367 | "description": "Operation failed because of provided data or invalid object state in Fiscal backend. Returns problem details structure as described in https://www.rfc-editor.org/rfc/rfc7807 with errorCode field to specify error.", 368 | "headers": { 369 | "operationId": { 370 | "description": "unique operation id", 371 | "schema": { 372 | "type": "string", 373 | "description": "unique operation id", 374 | "format": "" 375 | } 376 | } 377 | }, 378 | "content": { 379 | "application/problem+json": { 380 | "schema": { 381 | "$ref": "#/components/schemas/ApiProblemDetails" 382 | }, 383 | "example": { 384 | "errorCode": "DEV01", 385 | "type": "https://httpstatuses.io/422", 386 | "title": "Unprocessable Entity", 387 | "status": 422, 388 | "detail": "Device not found or not active", 389 | "operationID": "0HMPDRRQL1C0G:00000005" 390 | } 391 | } 392 | } 393 | }, 394 | "500": { 395 | "description": "Server encountered temporary issues.", 396 | "headers": { 397 | "operationId": { 398 | "description": "unique operation id", 399 | "schema": { 400 | "type": "string", 401 | "description": "unique operation id", 402 | "format": "" 403 | } 404 | } 405 | }, 406 | "content": { 407 | "application/problem+json": { 408 | "schema": { 409 | "$ref": "#/components/schemas/ProblemDetails" 410 | }, 411 | "example": { 412 | "type": "https://httpstatuses.io/500", 413 | "title": "Server error", 414 | "status": 500, 415 | "operationID": "0HMPDRRQL1C0G:00000005" 416 | } 417 | } 418 | } 419 | }, 420 | "200": { 421 | "description": "Success", 422 | "headers": { 423 | "operationId": { 424 | "description": "unique operation id", 425 | "schema": { 426 | "type": "string", 427 | "description": "unique operation id", 428 | "format": "" 429 | } 430 | } 431 | }, 432 | "content": { 433 | "application/json": { 434 | "schema": { 435 | "$ref": "#/components/schemas/VerifyTaxpayerInformationResponse" 436 | } 437 | } 438 | } 439 | } 440 | } 441 | } 442 | } 443 | }, 444 | "components": { 445 | "schemas": { 446 | "AddressDto": { 447 | "required": [ 448 | "city", 449 | "houseNo", 450 | "province", 451 | "street" 452 | ], 453 | "type": "object", 454 | "properties": { 455 | "province": { 456 | "maxLength": 100, 457 | "minLength": 0, 458 | "type": "string" 459 | }, 460 | "city": { 461 | "maxLength": 100, 462 | "minLength": 0, 463 | "type": "string" 464 | }, 465 | "street": { 466 | "maxLength": 100, 467 | "minLength": 0, 468 | "type": "string" 469 | }, 470 | "houseNo": { 471 | "maxLength": 250, 472 | "minLength": 0, 473 | "type": "string" 474 | }, 475 | "district": { 476 | "maxLength": 100, 477 | "minLength": 0, 478 | "type": "string", 479 | "nullable": true 480 | } 481 | }, 482 | "additionalProperties": false 483 | }, 484 | "ApiProblemDetails": { 485 | "type": "object", 486 | "properties": { 487 | "type": { 488 | "type": "string", 489 | "nullable": true 490 | }, 491 | "title": { 492 | "type": "string", 493 | "nullable": true 494 | }, 495 | "status": { 496 | "type": "integer", 497 | "format": "int32", 498 | "nullable": true 499 | }, 500 | "detail": { 501 | "type": "string", 502 | "nullable": true 503 | }, 504 | "instance": { 505 | "type": "string", 506 | "nullable": true 507 | }, 508 | "errorCode": { 509 | "type": "string", 510 | "nullable": true 511 | } 512 | }, 513 | "additionalProperties": { } 514 | }, 515 | "Contacts": { 516 | "type": "object", 517 | "properties": { 518 | "phoneNo": { 519 | "maxLength": 20, 520 | "minLength": 0, 521 | "type": "string", 522 | "nullable": true 523 | }, 524 | "email": { 525 | "maxLength": 100, 526 | "minLength": 0, 527 | "pattern": "\\A(?:[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?\\.)+[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?)\\Z", 528 | "type": "string", 529 | "nullable": true 530 | } 531 | }, 532 | "additionalProperties": false 533 | }, 534 | "GetServerCertificateResponse": { 535 | "required": [ 536 | "operationID" 537 | ], 538 | "type": "object", 539 | "properties": { 540 | "operationID": { 541 | "maxLength": 60, 542 | "minLength": 0, 543 | "type": "string", 544 | "description": "Operation ID assigned by Fiscalisation Backend.", 545 | "example": "0HMPH9AF0QKKE:00000005" 546 | }, 547 | "certificate": { 548 | "type": "array", 549 | "items": { 550 | "type": "string" 551 | }, 552 | "description": "Fiscalisation Backend certificate chain (according x.509 standard) to validate Fiscalisation Backend signatures.", 553 | "nullable": true 554 | }, 555 | "certificateValidTill": { 556 | "type": "string", 557 | "description": "Date till when Fiscalisation Backend signing certificate is valid (despite that in the certificate parameter all the certificate chain is returned, this field shows validity time of the child certificate in the chain). Times is provided in UTC time.", 558 | "format": "date-time" 559 | } 560 | }, 561 | "additionalProperties": false 562 | }, 563 | "ProblemDetails": { 564 | "type": "object", 565 | "properties": { 566 | "type": { 567 | "type": "string", 568 | "nullable": true 569 | }, 570 | "title": { 571 | "type": "string", 572 | "nullable": true 573 | }, 574 | "status": { 575 | "type": "integer", 576 | "format": "int32", 577 | "nullable": true 578 | }, 579 | "detail": { 580 | "type": "string", 581 | "nullable": true 582 | }, 583 | "instance": { 584 | "type": "string", 585 | "nullable": true 586 | } 587 | }, 588 | "additionalProperties": { } 589 | }, 590 | "RegisterDeviceRequest": { 591 | "required": [ 592 | "activationKey", 593 | "certificateRequest" 594 | ], 595 | "type": "object", 596 | "properties": { 597 | "certificateRequest": { 598 | "minLength": 1, 599 | "type": "string", 600 | "description": "Certificate signing request (CSR) for which certificate will be generated (in PEM format).\r\nAssigned by Tax Authority device name (format: [CLIENT]-[Fiscal_device_serial_no]-[zero_padded_10_digit_deviceId]) should be provided in CSR`s Subject CN.\r\nSupported algorithms and key types (in order of suggested preference):\r\n1)\tECC ECDSA on SECG secp256r1 curve (also named as ANSI prime256v1, NIST P-256); Signature Algorithm: ecdsa-with-SHA256.\r\n2)\tRSA 2048; Signature Algorithm - SHA256WithRSA.", 601 | "example": "-----BEGIN CERTIFICATE REQUEST-----\\nMIHYMIGAAgEAMB4xHDAaBgNVBAMME1pSQi1lVkZELTAwMDAwMDAwNDIwWTATBgcq\\nhkjOPQIBBggqhkjOPQMBBwNCAAT7v3DvY7pRg4lz2Z87wSMwSX27KwlpYnSRV6WU\\niPjpq2XsUAbg2lhUN7q3mlNJaUzqoKPmop5qURIpqUydXfapoAAwCgYIKoZIzj0E\\nAwIDRwAwRAIgLMEJQDh18bUE9waT2UXzP0+8FcGukpcIegMxd1A4JaQCIAZkzmEH\\ne0aaZ2jIcZArZo+rWzI4IwnSXtJqXLrpGUML\\n-----END CERTIFICATE REQUEST-----" 602 | }, 603 | "activationKey": { 604 | "maxLength": 8, 605 | "minLength": 0, 606 | "type": "string", 607 | "description": "Case insensitive 8 symbols key", 608 | "example": "12AXC178" 609 | } 610 | }, 611 | "additionalProperties": false 612 | }, 613 | "RegisterDeviceResponse": { 614 | "required": [ 615 | "certificate", 616 | "operationID" 617 | ], 618 | "type": "object", 619 | "properties": { 620 | "operationID": { 621 | "maxLength": 60, 622 | "minLength": 0, 623 | "type": "string", 624 | "description": "Operation ID assigned by Fiscalisation Backend.", 625 | "example": "0HMPH9AF0QKKE:00000005" 626 | }, 627 | "certificate": { 628 | "minLength": 1, 629 | "type": "string" 630 | } 631 | }, 632 | "additionalProperties": false 633 | }, 634 | "ValidationProblemDetails": { 635 | "type": "object", 636 | "properties": { 637 | "type": { 638 | "type": "string", 639 | "nullable": true 640 | }, 641 | "title": { 642 | "type": "string", 643 | "nullable": true 644 | }, 645 | "status": { 646 | "type": "integer", 647 | "format": "int32", 648 | "nullable": true 649 | }, 650 | "detail": { 651 | "type": "string", 652 | "nullable": true 653 | }, 654 | "instance": { 655 | "type": "string", 656 | "nullable": true 657 | }, 658 | "errors": { 659 | "type": "object", 660 | "additionalProperties": { 661 | "type": "array", 662 | "items": { 663 | "type": "string" 664 | } 665 | }, 666 | "nullable": true 667 | } 668 | }, 669 | "additionalProperties": { } 670 | }, 671 | "VerifyTaxpayerInformationRequest": { 672 | "required": [ 673 | "activationKey", 674 | "deviceSerialNo" 675 | ], 676 | "type": "object", 677 | "properties": { 678 | "activationKey": { 679 | "maxLength": 8, 680 | "minLength": 1, 681 | "type": "string", 682 | "description": "Case insensitive 8 symbols key", 683 | "example": "12AXC178" 684 | }, 685 | "deviceSerialNo": { 686 | "maxLength": 20, 687 | "minLength": 1, 688 | "type": "string", 689 | "description": "Device serial number assigned by manufacturer.", 690 | "example": "SN-001" 691 | } 692 | }, 693 | "additionalProperties": false 694 | }, 695 | "VerifyTaxpayerInformationResponse": { 696 | "required": [ 697 | "deviceBranchAddress", 698 | "deviceBranchName", 699 | "operationID", 700 | "taxPayerName", 701 | "taxPayerTIN" 702 | ], 703 | "type": "object", 704 | "properties": { 705 | "operationID": { 706 | "maxLength": 60, 707 | "minLength": 0, 708 | "type": "string", 709 | "description": "Operation ID assigned by Fiscalisation Backend.", 710 | "example": "0HMPH9AF0QKKE:00000005" 711 | }, 712 | "taxPayerName": { 713 | "maxLength": 250, 714 | "minLength": 1, 715 | "type": "string" 716 | }, 717 | "taxPayerTIN": { 718 | "maxLength": 10, 719 | "minLength": 1, 720 | "type": "string" 721 | }, 722 | "vatNumber": { 723 | "maxLength": 9, 724 | "type": "string", 725 | "nullable": true 726 | }, 727 | "deviceBranchName": { 728 | "maxLength": 250, 729 | "minLength": 1, 730 | "type": "string" 731 | }, 732 | "deviceBranchAddress": { 733 | "allOf": [ 734 | { 735 | "$ref": "#/components/schemas/AddressDto" 736 | } 737 | ] 738 | }, 739 | "deviceBranchContacts": { 740 | "allOf": [ 741 | { 742 | "$ref": "#/components/schemas/Contacts" 743 | } 744 | ], 745 | "nullable": true 746 | } 747 | }, 748 | "additionalProperties": false 749 | } 750 | } 751 | }, 752 | "tags": [ 753 | { 754 | "name": "Public", 755 | "description": "Public endpoints do not require client certificate to authenticate." 756 | } 757 | ] 758 | } -------------------------------------------------------------------------------- /swagger/User-1.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.1", 3 | "info": { 4 | "title": "Fiscal backend FiscalDeviceApi Build:1.0.0.0", 5 | "version": "1.0" 6 | }, 7 | "paths": { 8 | "/User/v1/{deviceID}/GetUsersList": { 9 | "get": { 10 | "tags": [ 11 | "User" 12 | ], 13 | "description": "Endpoint is used to get taxpayer users saved in Fiscal device management sistem list.", 14 | "parameters": [ 15 | { 16 | "name": "Sort", 17 | "in": "query", 18 | "schema": { 19 | "allOf": [ 20 | { 21 | "$ref": "#/components/schemas/GetUsersListEnum" 22 | } 23 | ] 24 | } 25 | }, 26 | { 27 | "name": "Order", 28 | "in": "query", 29 | "schema": { 30 | "allOf": [ 31 | { 32 | "$ref": "#/components/schemas/ListRequestOrderEnum" 33 | } 34 | ] 35 | } 36 | }, 37 | { 38 | "name": "Offset", 39 | "in": "query", 40 | "required": true, 41 | "schema": { 42 | "type": "integer", 43 | "format": "int32" 44 | } 45 | }, 46 | { 47 | "name": "Limit", 48 | "in": "query", 49 | "required": true, 50 | "schema": { 51 | "type": "integer", 52 | "format": "int32" 53 | } 54 | }, 55 | { 56 | "name": "Operator", 57 | "in": "query", 58 | "schema": { 59 | "allOf": [ 60 | { 61 | "$ref": "#/components/schemas/LogicalOperator" 62 | } 63 | ] 64 | } 65 | }, 66 | { 67 | "name": "deviceID", 68 | "in": "path", 69 | "required": true, 70 | "schema": { 71 | "type": "integer", 72 | "format": "int32" 73 | } 74 | }, 75 | { 76 | "name": "DeviceModelName", 77 | "in": "header", 78 | "description": "Device model name as registered in Tax Authority", 79 | "schema": { 80 | "type": "string" 81 | } 82 | }, 83 | { 84 | "name": "DeviceModelVersion", 85 | "in": "header", 86 | "description": "Device model version number as registered in Tax Authority", 87 | "schema": { 88 | "type": "string" 89 | } 90 | } 91 | ], 92 | "responses": { 93 | "401": { 94 | "description": "Device certificate expired.", 95 | "headers": { 96 | "operationId": { 97 | "description": "unique operation id", 98 | "schema": { 99 | "type": "string", 100 | "description": "unique operation id", 101 | "format": "" 102 | } 103 | } 104 | }, 105 | "content": { 106 | "application/problem+json": { 107 | "schema": { 108 | "$ref": "#/components/schemas/ProblemDetails" 109 | } 110 | } 111 | } 112 | }, 113 | "500": { 114 | "description": "Server encountered temporary issues.", 115 | "headers": { 116 | "operationId": { 117 | "description": "unique operation id", 118 | "schema": { 119 | "type": "string", 120 | "description": "unique operation id", 121 | "format": "" 122 | } 123 | } 124 | }, 125 | "content": { 126 | "application/problem+json": { 127 | "schema": { 128 | "$ref": "#/components/schemas/ProblemDetails" 129 | }, 130 | "example": { 131 | "type": "https://httpstatuses.io/500", 132 | "title": "Server error", 133 | "status": 500, 134 | "operationID": "0HMPDRRQL1C0G:00000005" 135 | } 136 | } 137 | } 138 | }, 139 | "200": { 140 | "description": "Success", 141 | "headers": { 142 | "operationId": { 143 | "description": "unique operation id", 144 | "schema": { 145 | "type": "string", 146 | "description": "unique operation id", 147 | "format": "" 148 | } 149 | } 150 | }, 151 | "content": { 152 | "application/json": { 153 | "schema": { 154 | "$ref": "#/components/schemas/GetUsersResponse" 155 | } 156 | } 157 | } 158 | }, 159 | "400": { 160 | "description": "Bad Request", 161 | "headers": { 162 | "operationId": { 163 | "description": "unique operation id", 164 | "schema": { 165 | "type": "string", 166 | "description": "unique operation id", 167 | "format": "" 168 | } 169 | } 170 | }, 171 | "content": { 172 | "application/problem+json": { 173 | "schema": { 174 | "$ref": "#/components/schemas/ValidationProblemDetails" 175 | } 176 | } 177 | } 178 | }, 179 | "422": { 180 | "description": "Operation failed because of provided data or invalid object state in Fiscal backend. Returns problem details structure as described in https://www.rfc-editor.org/rfc/rfc7807 with errorCode field to specify error.", 181 | "headers": { 182 | "operationId": { 183 | "description": "unique operation id", 184 | "schema": { 185 | "type": "string", 186 | "description": "unique operation id", 187 | "format": "" 188 | } 189 | } 190 | }, 191 | "content": { 192 | "application/problem+json": { 193 | "schema": { 194 | "$ref": "#/components/schemas/ApiProblemDetails" 195 | } 196 | } 197 | } 198 | } 199 | } 200 | } 201 | }, 202 | "/User/v1/{deviceID}/SendSecurityCodeToTaxpayer": { 203 | "post": { 204 | "tags": [ 205 | "User" 206 | ], 207 | "description": "Endpoint is responsible for security code sending to taxpayer and branch where device registered emails.", 208 | "parameters": [ 209 | { 210 | "name": "deviceID", 211 | "in": "path", 212 | "required": true, 213 | "schema": { 214 | "type": "integer", 215 | "format": "int32" 216 | } 217 | }, 218 | { 219 | "name": "DeviceModelName", 220 | "in": "header", 221 | "description": "Device model name as registered in Tax Authority", 222 | "schema": { 223 | "type": "string" 224 | } 225 | }, 226 | { 227 | "name": "DeviceModelVersion", 228 | "in": "header", 229 | "description": "Device model version number as registered in Tax Authority", 230 | "schema": { 231 | "type": "string" 232 | } 233 | } 234 | ], 235 | "requestBody": { 236 | "description": "", 237 | "content": { 238 | "application/json": { 239 | "schema": { 240 | "allOf": [ 241 | { 242 | "$ref": "#/components/schemas/SendSecurityCodeToTaxpayerRequest" 243 | } 244 | ] 245 | } 246 | } 247 | }, 248 | "required": true 249 | }, 250 | "responses": { 251 | "401": { 252 | "description": "Device certificate expired.", 253 | "headers": { 254 | "operationId": { 255 | "description": "unique operation id", 256 | "schema": { 257 | "type": "string", 258 | "description": "unique operation id", 259 | "format": "" 260 | } 261 | } 262 | }, 263 | "content": { 264 | "application/problem+json": { 265 | "schema": { 266 | "$ref": "#/components/schemas/ProblemDetails" 267 | } 268 | } 269 | } 270 | }, 271 | "500": { 272 | "description": "Server encountered temporary issues.", 273 | "headers": { 274 | "operationId": { 275 | "description": "unique operation id", 276 | "schema": { 277 | "type": "string", 278 | "description": "unique operation id", 279 | "format": "" 280 | } 281 | } 282 | }, 283 | "content": { 284 | "application/problem+json": { 285 | "schema": { 286 | "$ref": "#/components/schemas/ProblemDetails" 287 | }, 288 | "example": { 289 | "type": "https://httpstatuses.io/500", 290 | "title": "Server error", 291 | "status": 500, 292 | "operationID": "0HMPDRRQL1C0G:00000005" 293 | } 294 | } 295 | } 296 | }, 297 | "200": { 298 | "description": "Success", 299 | "headers": { 300 | "operationId": { 301 | "description": "unique operation id", 302 | "schema": { 303 | "type": "string", 304 | "description": "unique operation id", 305 | "format": "" 306 | } 307 | } 308 | }, 309 | "content": { 310 | "application/json": { 311 | "schema": { 312 | "$ref": "#/components/schemas/SendSecurityCodeToTaxpayerResponse" 313 | } 314 | } 315 | } 316 | }, 317 | "404": { 318 | "description": "Not Found", 319 | "headers": { 320 | "operationId": { 321 | "description": "unique operation id", 322 | "schema": { 323 | "type": "string", 324 | "description": "unique operation id", 325 | "format": "" 326 | } 327 | } 328 | }, 329 | "content": { 330 | "application/problem+json": { 331 | "schema": { 332 | "$ref": "#/components/schemas/ProblemDetails" 333 | } 334 | } 335 | } 336 | }, 337 | "400": { 338 | "description": "Bad Request", 339 | "headers": { 340 | "operationId": { 341 | "description": "unique operation id", 342 | "schema": { 343 | "type": "string", 344 | "description": "unique operation id", 345 | "format": "" 346 | } 347 | } 348 | }, 349 | "content": { 350 | "application/problem+json": { 351 | "schema": { 352 | "$ref": "#/components/schemas/ValidationProblemDetails" 353 | } 354 | } 355 | } 356 | }, 357 | "422": { 358 | "description": "Operation failed because of provided data or invalid object state in Fiscal backend. Returns problem details structure as described in https://www.rfc-editor.org/rfc/rfc7807 with errorCode field to specify error.", 359 | "headers": { 360 | "operationId": { 361 | "description": "unique operation id", 362 | "schema": { 363 | "type": "string", 364 | "description": "unique operation id", 365 | "format": "" 366 | } 367 | } 368 | }, 369 | "content": { 370 | "application/problem+json": { 371 | "schema": { 372 | "$ref": "#/components/schemas/ApiProblemDetails" 373 | } 374 | } 375 | } 376 | } 377 | } 378 | } 379 | }, 380 | "/User/v1/{deviceID}/CreateUser": { 381 | "post": { 382 | "tags": [ 383 | "User" 384 | ], 385 | "description": "Creates new pos user or updates allready existing not comfirmed tenant user", 386 | "parameters": [ 387 | { 388 | "name": "deviceID", 389 | "in": "path", 390 | "required": true, 391 | "schema": { 392 | "type": "integer", 393 | "format": "int32" 394 | } 395 | }, 396 | { 397 | "name": "DeviceModelName", 398 | "in": "header", 399 | "description": "Device model name as registered in Tax Authority", 400 | "schema": { 401 | "type": "string" 402 | } 403 | }, 404 | { 405 | "name": "DeviceModelVersion", 406 | "in": "header", 407 | "description": "Device model version number as registered in Tax Authority", 408 | "schema": { 409 | "type": "string" 410 | } 411 | } 412 | ], 413 | "requestBody": { 414 | "content": { 415 | "application/json": { 416 | "schema": { 417 | "allOf": [ 418 | { 419 | "$ref": "#/components/schemas/CreateUserRequest" 420 | } 421 | ] 422 | } 423 | } 424 | } 425 | }, 426 | "responses": { 427 | "401": { 428 | "description": "Device certificate expired.", 429 | "headers": { 430 | "operationId": { 431 | "description": "unique operation id", 432 | "schema": { 433 | "type": "string", 434 | "description": "unique operation id", 435 | "format": "" 436 | } 437 | } 438 | }, 439 | "content": { 440 | "application/problem+json": { 441 | "schema": { 442 | "$ref": "#/components/schemas/ProblemDetails" 443 | } 444 | } 445 | } 446 | }, 447 | "500": { 448 | "description": "Server encountered temporary issues.", 449 | "headers": { 450 | "operationId": { 451 | "description": "unique operation id", 452 | "schema": { 453 | "type": "string", 454 | "description": "unique operation id", 455 | "format": "" 456 | } 457 | } 458 | }, 459 | "content": { 460 | "application/problem+json": { 461 | "schema": { 462 | "$ref": "#/components/schemas/ProblemDetails" 463 | }, 464 | "example": { 465 | "type": "https://httpstatuses.io/500", 466 | "title": "Server error", 467 | "status": 500, 468 | "operationID": "0HMPDRRQL1C0G:00000005" 469 | } 470 | } 471 | } 472 | }, 473 | "200": { 474 | "description": "Success", 475 | "headers": { 476 | "operationId": { 477 | "description": "unique operation id", 478 | "schema": { 479 | "type": "string", 480 | "description": "unique operation id", 481 | "format": "" 482 | } 483 | } 484 | }, 485 | "content": { 486 | "application/json": { 487 | "schema": { 488 | "$ref": "#/components/schemas/CreateUserResponse" 489 | } 490 | } 491 | } 492 | }, 493 | "400": { 494 | "description": "Bad Request", 495 | "headers": { 496 | "operationId": { 497 | "description": "unique operation id", 498 | "schema": { 499 | "type": "string", 500 | "description": "unique operation id", 501 | "format": "" 502 | } 503 | } 504 | }, 505 | "content": { 506 | "application/problem+json": { 507 | "schema": { 508 | "$ref": "#/components/schemas/ValidationProblemDetails" 509 | } 510 | } 511 | } 512 | }, 513 | "422": { 514 | "description": "Operation failed because of provided data or invalid object state in Fiscal backend. Returns problem details structure as described in https://www.rfc-editor.org/rfc/rfc7807 with errorCode field to specify error.", 515 | "headers": { 516 | "operationId": { 517 | "description": "unique operation id", 518 | "schema": { 519 | "type": "string", 520 | "description": "unique operation id", 521 | "format": "" 522 | } 523 | } 524 | }, 525 | "content": { 526 | "application/problem+json": { 527 | "schema": { 528 | "$ref": "#/components/schemas/ApiProblemDetails" 529 | } 530 | } 531 | } 532 | } 533 | } 534 | } 535 | }, 536 | "/User/v1/{deviceID}/Login": { 537 | "post": { 538 | "tags": [ 539 | "User" 540 | ], 541 | "description": "Endpoint is used to check if sent username and password credentials are correct and user can login to POS.", 542 | "parameters": [ 543 | { 544 | "name": "deviceID", 545 | "in": "path", 546 | "required": true, 547 | "schema": { 548 | "type": "integer", 549 | "format": "int32" 550 | } 551 | }, 552 | { 553 | "name": "DeviceModelName", 554 | "in": "header", 555 | "description": "Device model name as registered in Tax Authority", 556 | "schema": { 557 | "type": "string" 558 | } 559 | }, 560 | { 561 | "name": "DeviceModelVersion", 562 | "in": "header", 563 | "description": "Device model version number as registered in Tax Authority", 564 | "schema": { 565 | "type": "string" 566 | } 567 | } 568 | ], 569 | "requestBody": { 570 | "description": "", 571 | "content": { 572 | "application/json": { 573 | "schema": { 574 | "allOf": [ 575 | { 576 | "$ref": "#/components/schemas/LoginRequest" 577 | } 578 | ] 579 | } 580 | } 581 | } 582 | }, 583 | "responses": { 584 | "401": { 585 | "description": "Device certificate expired.", 586 | "headers": { 587 | "operationId": { 588 | "description": "unique operation id", 589 | "schema": { 590 | "type": "string", 591 | "description": "unique operation id", 592 | "format": "" 593 | } 594 | } 595 | }, 596 | "content": { 597 | "application/problem+json": { 598 | "schema": { 599 | "$ref": "#/components/schemas/ProblemDetails" 600 | } 601 | } 602 | } 603 | }, 604 | "500": { 605 | "description": "Server encountered temporary issues.", 606 | "headers": { 607 | "operationId": { 608 | "description": "unique operation id", 609 | "schema": { 610 | "type": "string", 611 | "description": "unique operation id", 612 | "format": "" 613 | } 614 | } 615 | }, 616 | "content": { 617 | "application/problem+json": { 618 | "schema": { 619 | "$ref": "#/components/schemas/ProblemDetails" 620 | }, 621 | "example": { 622 | "type": "https://httpstatuses.io/500", 623 | "title": "Server error", 624 | "status": 500, 625 | "operationID": "0HMPDRRQL1C0G:00000005" 626 | } 627 | } 628 | } 629 | }, 630 | "200": { 631 | "description": "Success", 632 | "headers": { 633 | "operationId": { 634 | "description": "unique operation id", 635 | "schema": { 636 | "type": "string", 637 | "description": "unique operation id", 638 | "format": "" 639 | } 640 | } 641 | }, 642 | "content": { 643 | "application/json": { 644 | "schema": { 645 | "$ref": "#/components/schemas/LoginResponse" 646 | } 647 | } 648 | } 649 | }, 650 | "400": { 651 | "description": "Bad Request", 652 | "headers": { 653 | "operationId": { 654 | "description": "unique operation id", 655 | "schema": { 656 | "type": "string", 657 | "description": "unique operation id", 658 | "format": "" 659 | } 660 | } 661 | }, 662 | "content": { 663 | "application/problem+json": { 664 | "schema": { 665 | "$ref": "#/components/schemas/ValidationProblemDetails" 666 | } 667 | } 668 | } 669 | }, 670 | "422": { 671 | "description": "Operation failed because of provided data or invalid object state in Fiscal backend. Returns problem details structure as described in https://www.rfc-editor.org/rfc/rfc7807 with errorCode field to specify error.", 672 | "headers": { 673 | "operationId": { 674 | "description": "unique operation id", 675 | "schema": { 676 | "type": "string", 677 | "description": "unique operation id", 678 | "format": "" 679 | } 680 | } 681 | }, 682 | "content": { 683 | "application/problem+json": { 684 | "schema": { 685 | "$ref": "#/components/schemas/ApiProblemDetails" 686 | } 687 | } 688 | } 689 | } 690 | } 691 | } 692 | }, 693 | "/User/v1/{deviceID}/SendSecurityCodeToUserEmail": { 694 | "post": { 695 | "tags": [ 696 | "User" 697 | ], 698 | "description": "Sends security code to confirm user email", 699 | "parameters": [ 700 | { 701 | "name": "Token", 702 | "in": "header", 703 | "required": true, 704 | "schema": { 705 | "type": "string" 706 | } 707 | }, 708 | { 709 | "name": "deviceID", 710 | "in": "path", 711 | "required": true, 712 | "schema": { 713 | "type": "integer", 714 | "format": "int32" 715 | } 716 | }, 717 | { 718 | "name": "DeviceModelName", 719 | "in": "header", 720 | "description": "Device model name as registered in Tax Authority", 721 | "schema": { 722 | "type": "string" 723 | } 724 | }, 725 | { 726 | "name": "DeviceModelVersion", 727 | "in": "header", 728 | "description": "Device model version number as registered in Tax Authority", 729 | "schema": { 730 | "type": "string" 731 | } 732 | } 733 | ], 734 | "requestBody": { 735 | "content": { 736 | "application/json": { 737 | "schema": { 738 | "allOf": [ 739 | { 740 | "$ref": "#/components/schemas/SendSecurityCodeToUserEmailRequest" 741 | } 742 | ] 743 | } 744 | } 745 | } 746 | }, 747 | "responses": { 748 | "401": { 749 | "description": "Device certificate expired.", 750 | "headers": { 751 | "operationId": { 752 | "description": "unique operation id", 753 | "schema": { 754 | "type": "string", 755 | "description": "unique operation id", 756 | "format": "" 757 | } 758 | } 759 | }, 760 | "content": { 761 | "application/problem+json": { 762 | "schema": { 763 | "$ref": "#/components/schemas/ProblemDetails" 764 | } 765 | } 766 | } 767 | }, 768 | "500": { 769 | "description": "Server encountered temporary issues.", 770 | "headers": { 771 | "operationId": { 772 | "description": "unique operation id", 773 | "schema": { 774 | "type": "string", 775 | "description": "unique operation id", 776 | "format": "" 777 | } 778 | } 779 | }, 780 | "content": { 781 | "application/problem+json": { 782 | "schema": { 783 | "$ref": "#/components/schemas/ProblemDetails" 784 | }, 785 | "example": { 786 | "type": "https://httpstatuses.io/500", 787 | "title": "Server error", 788 | "status": 500, 789 | "operationID": "0HMPDRRQL1C0G:00000005" 790 | } 791 | } 792 | } 793 | }, 794 | "200": { 795 | "description": "Success", 796 | "headers": { 797 | "operationId": { 798 | "description": "unique operation id", 799 | "schema": { 800 | "type": "string", 801 | "description": "unique operation id", 802 | "format": "" 803 | } 804 | } 805 | }, 806 | "content": { 807 | "application/json": { 808 | "schema": { 809 | "$ref": "#/components/schemas/SendSecurityCodeToUserEmailResponse" 810 | } 811 | } 812 | } 813 | }, 814 | "400": { 815 | "description": "Bad Request", 816 | "headers": { 817 | "operationId": { 818 | "description": "unique operation id", 819 | "schema": { 820 | "type": "string", 821 | "description": "unique operation id", 822 | "format": "" 823 | } 824 | } 825 | }, 826 | "content": { 827 | "application/problem+json": { 828 | "schema": { 829 | "$ref": "#/components/schemas/ValidationProblemDetails" 830 | } 831 | } 832 | } 833 | }, 834 | "422": { 835 | "description": "Operation failed because of provided data or invalid object state in Fiscal backend. Returns problem details structure as described in https://www.rfc-editor.org/rfc/rfc7807 with errorCode field to specify error.", 836 | "headers": { 837 | "operationId": { 838 | "description": "unique operation id", 839 | "schema": { 840 | "type": "string", 841 | "description": "unique operation id", 842 | "format": "" 843 | } 844 | } 845 | }, 846 | "content": { 847 | "application/problem+json": { 848 | "schema": { 849 | "$ref": "#/components/schemas/ApiProblemDetails" 850 | } 851 | } 852 | } 853 | } 854 | } 855 | } 856 | }, 857 | "/User/v1/{deviceID}/SendSecurityCodeToUserPhone": { 858 | "post": { 859 | "tags": [ 860 | "User" 861 | ], 862 | "description": "Sends security code to confirm user phone", 863 | "parameters": [ 864 | { 865 | "name": "Token", 866 | "in": "header", 867 | "required": true, 868 | "schema": { 869 | "type": "string" 870 | } 871 | }, 872 | { 873 | "name": "deviceID", 874 | "in": "path", 875 | "required": true, 876 | "schema": { 877 | "type": "integer", 878 | "format": "int32" 879 | } 880 | }, 881 | { 882 | "name": "DeviceModelName", 883 | "in": "header", 884 | "description": "Device model name as registered in Tax Authority", 885 | "schema": { 886 | "type": "string" 887 | } 888 | }, 889 | { 890 | "name": "DeviceModelVersion", 891 | "in": "header", 892 | "description": "Device model version number as registered in Tax Authority", 893 | "schema": { 894 | "type": "string" 895 | } 896 | } 897 | ], 898 | "requestBody": { 899 | "content": { 900 | "application/json": { 901 | "schema": { 902 | "allOf": [ 903 | { 904 | "$ref": "#/components/schemas/SendSecurityCodeToUserPhoneRequest" 905 | } 906 | ] 907 | } 908 | } 909 | } 910 | }, 911 | "responses": { 912 | "401": { 913 | "description": "Device certificate expired.", 914 | "headers": { 915 | "operationId": { 916 | "description": "unique operation id", 917 | "schema": { 918 | "type": "string", 919 | "description": "unique operation id", 920 | "format": "" 921 | } 922 | } 923 | }, 924 | "content": { 925 | "application/problem+json": { 926 | "schema": { 927 | "$ref": "#/components/schemas/ProblemDetails" 928 | } 929 | } 930 | } 931 | }, 932 | "500": { 933 | "description": "Server encountered temporary issues.", 934 | "headers": { 935 | "operationId": { 936 | "description": "unique operation id", 937 | "schema": { 938 | "type": "string", 939 | "description": "unique operation id", 940 | "format": "" 941 | } 942 | } 943 | }, 944 | "content": { 945 | "application/problem+json": { 946 | "schema": { 947 | "$ref": "#/components/schemas/ProblemDetails" 948 | }, 949 | "example": { 950 | "type": "https://httpstatuses.io/500", 951 | "title": "Server error", 952 | "status": 500, 953 | "operationID": "0HMPDRRQL1C0G:00000005" 954 | } 955 | } 956 | } 957 | }, 958 | "200": { 959 | "description": "Success", 960 | "headers": { 961 | "operationId": { 962 | "description": "unique operation id", 963 | "schema": { 964 | "type": "string", 965 | "description": "unique operation id", 966 | "format": "" 967 | } 968 | } 969 | }, 970 | "content": { 971 | "application/json": { 972 | "schema": { 973 | "$ref": "#/components/schemas/SendSecurityCodeToUserPhoneResponse" 974 | } 975 | } 976 | } 977 | }, 978 | "400": { 979 | "description": "Bad Request", 980 | "headers": { 981 | "operationId": { 982 | "description": "unique operation id", 983 | "schema": { 984 | "type": "string", 985 | "description": "unique operation id", 986 | "format": "" 987 | } 988 | } 989 | }, 990 | "content": { 991 | "application/problem+json": { 992 | "schema": { 993 | "$ref": "#/components/schemas/ValidationProblemDetails" 994 | } 995 | } 996 | } 997 | }, 998 | "422": { 999 | "description": "Operation failed because of provided data or invalid object state in Fiscal backend. Returns problem details structure as described in https://www.rfc-editor.org/rfc/rfc7807 with errorCode field to specify error.", 1000 | "headers": { 1001 | "operationId": { 1002 | "description": "unique operation id", 1003 | "schema": { 1004 | "type": "string", 1005 | "description": "unique operation id", 1006 | "format": "" 1007 | } 1008 | } 1009 | }, 1010 | "content": { 1011 | "application/problem+json": { 1012 | "schema": { 1013 | "$ref": "#/components/schemas/ApiProblemDetails" 1014 | } 1015 | } 1016 | } 1017 | } 1018 | } 1019 | } 1020 | }, 1021 | "/User/v1/{deviceID}/ConfirmUser": { 1022 | "post": { 1023 | "tags": [ 1024 | "User" 1025 | ], 1026 | "description": "Endpoint is user creation confirmation by taxpayer.", 1027 | "parameters": [ 1028 | { 1029 | "name": "deviceID", 1030 | "in": "path", 1031 | "required": true, 1032 | "schema": { 1033 | "type": "integer", 1034 | "format": "int32" 1035 | } 1036 | }, 1037 | { 1038 | "name": "DeviceModelName", 1039 | "in": "header", 1040 | "description": "Device model name as registered in Tax Authority", 1041 | "schema": { 1042 | "type": "string" 1043 | } 1044 | }, 1045 | { 1046 | "name": "DeviceModelVersion", 1047 | "in": "header", 1048 | "description": "Device model version number as registered in Tax Authority", 1049 | "schema": { 1050 | "type": "string" 1051 | } 1052 | } 1053 | ], 1054 | "requestBody": { 1055 | "description": "", 1056 | "content": { 1057 | "application/json": { 1058 | "schema": { 1059 | "allOf": [ 1060 | { 1061 | "$ref": "#/components/schemas/ConfirmUserRequest" 1062 | } 1063 | ] 1064 | } 1065 | } 1066 | } 1067 | }, 1068 | "responses": { 1069 | "401": { 1070 | "description": "Device certificate expired.", 1071 | "headers": { 1072 | "operationId": { 1073 | "description": "unique operation id", 1074 | "schema": { 1075 | "type": "string", 1076 | "description": "unique operation id", 1077 | "format": "" 1078 | } 1079 | } 1080 | }, 1081 | "content": { 1082 | "application/problem+json": { 1083 | "schema": { 1084 | "$ref": "#/components/schemas/ProblemDetails" 1085 | } 1086 | } 1087 | } 1088 | }, 1089 | "500": { 1090 | "description": "Server encountered temporary issues.", 1091 | "headers": { 1092 | "operationId": { 1093 | "description": "unique operation id", 1094 | "schema": { 1095 | "type": "string", 1096 | "description": "unique operation id", 1097 | "format": "" 1098 | } 1099 | } 1100 | }, 1101 | "content": { 1102 | "application/problem+json": { 1103 | "schema": { 1104 | "$ref": "#/components/schemas/ProblemDetails" 1105 | }, 1106 | "example": { 1107 | "type": "https://httpstatuses.io/500", 1108 | "title": "Server error", 1109 | "status": 500, 1110 | "operationID": "0HMPDRRQL1C0G:00000005" 1111 | } 1112 | } 1113 | } 1114 | }, 1115 | "200": { 1116 | "description": "Success", 1117 | "headers": { 1118 | "operationId": { 1119 | "description": "unique operation id", 1120 | "schema": { 1121 | "type": "string", 1122 | "description": "unique operation id", 1123 | "format": "" 1124 | } 1125 | } 1126 | }, 1127 | "content": { 1128 | "application/json": { 1129 | "schema": { 1130 | "$ref": "#/components/schemas/LoginResponse" 1131 | } 1132 | } 1133 | } 1134 | }, 1135 | "400": { 1136 | "description": "Bad Request", 1137 | "headers": { 1138 | "operationId": { 1139 | "description": "unique operation id", 1140 | "schema": { 1141 | "type": "string", 1142 | "description": "unique operation id", 1143 | "format": "" 1144 | } 1145 | } 1146 | }, 1147 | "content": { 1148 | "application/problem+json": { 1149 | "schema": { 1150 | "$ref": "#/components/schemas/ValidationProblemDetails" 1151 | } 1152 | } 1153 | } 1154 | }, 1155 | "422": { 1156 | "description": "Operation failed because of provided data or invalid object state in Fiscal backend. Returns problem details structure as described in https://www.rfc-editor.org/rfc/rfc7807 with errorCode field to specify error.", 1157 | "headers": { 1158 | "operationId": { 1159 | "description": "unique operation id", 1160 | "schema": { 1161 | "type": "string", 1162 | "description": "unique operation id", 1163 | "format": "" 1164 | } 1165 | } 1166 | }, 1167 | "content": { 1168 | "application/problem+json": { 1169 | "schema": { 1170 | "$ref": "#/components/schemas/ApiProblemDetails" 1171 | } 1172 | } 1173 | } 1174 | } 1175 | } 1176 | } 1177 | }, 1178 | "/User/v1/{deviceID}/ChangePassword": { 1179 | "post": { 1180 | "tags": [ 1181 | "User" 1182 | ], 1183 | "description": "Endpoint is used to change user password.", 1184 | "parameters": [ 1185 | { 1186 | "name": "Token", 1187 | "in": "header", 1188 | "description": "", 1189 | "required": true, 1190 | "schema": { 1191 | "type": "string" 1192 | } 1193 | }, 1194 | { 1195 | "name": "deviceID", 1196 | "in": "path", 1197 | "required": true, 1198 | "schema": { 1199 | "type": "integer", 1200 | "format": "int32" 1201 | } 1202 | }, 1203 | { 1204 | "name": "DeviceModelName", 1205 | "in": "header", 1206 | "description": "Device model name as registered in Tax Authority", 1207 | "schema": { 1208 | "type": "string" 1209 | } 1210 | }, 1211 | { 1212 | "name": "DeviceModelVersion", 1213 | "in": "header", 1214 | "description": "Device model version number as registered in Tax Authority", 1215 | "schema": { 1216 | "type": "string" 1217 | } 1218 | } 1219 | ], 1220 | "requestBody": { 1221 | "description": "", 1222 | "content": { 1223 | "application/json": { 1224 | "schema": { 1225 | "allOf": [ 1226 | { 1227 | "$ref": "#/components/schemas/ChangePasswordRequest" 1228 | } 1229 | ] 1230 | } 1231 | } 1232 | } 1233 | }, 1234 | "responses": { 1235 | "401": { 1236 | "description": "Device certificate expired.", 1237 | "headers": { 1238 | "operationId": { 1239 | "description": "unique operation id", 1240 | "schema": { 1241 | "type": "string", 1242 | "description": "unique operation id", 1243 | "format": "" 1244 | } 1245 | } 1246 | }, 1247 | "content": { 1248 | "application/problem+json": { 1249 | "schema": { 1250 | "$ref": "#/components/schemas/ProblemDetails" 1251 | } 1252 | } 1253 | } 1254 | }, 1255 | "500": { 1256 | "description": "Server encountered temporary issues.", 1257 | "headers": { 1258 | "operationId": { 1259 | "description": "unique operation id", 1260 | "schema": { 1261 | "type": "string", 1262 | "description": "unique operation id", 1263 | "format": "" 1264 | } 1265 | } 1266 | }, 1267 | "content": { 1268 | "application/problem+json": { 1269 | "schema": { 1270 | "$ref": "#/components/schemas/ProblemDetails" 1271 | }, 1272 | "example": { 1273 | "type": "https://httpstatuses.io/500", 1274 | "title": "Server error", 1275 | "status": 500, 1276 | "operationID": "0HMPDRRQL1C0G:00000005" 1277 | } 1278 | } 1279 | } 1280 | }, 1281 | "200": { 1282 | "description": "Success", 1283 | "headers": { 1284 | "operationId": { 1285 | "description": "unique operation id", 1286 | "schema": { 1287 | "type": "string", 1288 | "description": "unique operation id", 1289 | "format": "" 1290 | } 1291 | } 1292 | }, 1293 | "content": { 1294 | "application/json": { 1295 | "schema": { 1296 | "$ref": "#/components/schemas/LoginResponse" 1297 | } 1298 | } 1299 | } 1300 | }, 1301 | "400": { 1302 | "description": "Bad Request", 1303 | "headers": { 1304 | "operationId": { 1305 | "description": "unique operation id", 1306 | "schema": { 1307 | "type": "string", 1308 | "description": "unique operation id", 1309 | "format": "" 1310 | } 1311 | } 1312 | }, 1313 | "content": { 1314 | "application/problem+json": { 1315 | "schema": { 1316 | "$ref": "#/components/schemas/ValidationProblemDetails" 1317 | } 1318 | } 1319 | } 1320 | }, 1321 | "422": { 1322 | "description": "Operation failed because of provided data or invalid object state in Fiscal backend. Returns problem details structure as described in https://www.rfc-editor.org/rfc/rfc7807 with errorCode field to specify error.", 1323 | "headers": { 1324 | "operationId": { 1325 | "description": "unique operation id", 1326 | "schema": { 1327 | "type": "string", 1328 | "description": "unique operation id", 1329 | "format": "" 1330 | } 1331 | } 1332 | }, 1333 | "content": { 1334 | "application/problem+json": { 1335 | "schema": { 1336 | "$ref": "#/components/schemas/ApiProblemDetails" 1337 | } 1338 | } 1339 | } 1340 | } 1341 | } 1342 | } 1343 | }, 1344 | "/User/v1/{deviceID}/ResetPassword": { 1345 | "post": { 1346 | "tags": [ 1347 | "User" 1348 | ], 1349 | "description": "Endpoint is used to change user password.", 1350 | "parameters": [ 1351 | { 1352 | "name": "deviceID", 1353 | "in": "path", 1354 | "required": true, 1355 | "schema": { 1356 | "type": "integer", 1357 | "format": "int32" 1358 | } 1359 | }, 1360 | { 1361 | "name": "DeviceModelName", 1362 | "in": "header", 1363 | "description": "Device model name as registered in Tax Authority", 1364 | "schema": { 1365 | "type": "string" 1366 | } 1367 | }, 1368 | { 1369 | "name": "DeviceModelVersion", 1370 | "in": "header", 1371 | "description": "Device model version number as registered in Tax Authority", 1372 | "schema": { 1373 | "type": "string" 1374 | } 1375 | } 1376 | ], 1377 | "requestBody": { 1378 | "description": "", 1379 | "content": { 1380 | "application/json": { 1381 | "schema": { 1382 | "allOf": [ 1383 | { 1384 | "$ref": "#/components/schemas/ResetPasswordRequest" 1385 | } 1386 | ] 1387 | } 1388 | } 1389 | } 1390 | }, 1391 | "responses": { 1392 | "401": { 1393 | "description": "Device certificate expired.", 1394 | "headers": { 1395 | "operationId": { 1396 | "description": "unique operation id", 1397 | "schema": { 1398 | "type": "string", 1399 | "description": "unique operation id", 1400 | "format": "" 1401 | } 1402 | } 1403 | }, 1404 | "content": { 1405 | "application/problem+json": { 1406 | "schema": { 1407 | "$ref": "#/components/schemas/ProblemDetails" 1408 | } 1409 | } 1410 | } 1411 | }, 1412 | "500": { 1413 | "description": "Server encountered temporary issues.", 1414 | "headers": { 1415 | "operationId": { 1416 | "description": "unique operation id", 1417 | "schema": { 1418 | "type": "string", 1419 | "description": "unique operation id", 1420 | "format": "" 1421 | } 1422 | } 1423 | }, 1424 | "content": { 1425 | "application/problem+json": { 1426 | "schema": { 1427 | "$ref": "#/components/schemas/ProblemDetails" 1428 | }, 1429 | "example": { 1430 | "type": "https://httpstatuses.io/500", 1431 | "title": "Server error", 1432 | "status": 500, 1433 | "operationID": "0HMPDRRQL1C0G:00000005" 1434 | } 1435 | } 1436 | } 1437 | }, 1438 | "200": { 1439 | "description": "Success", 1440 | "headers": { 1441 | "operationId": { 1442 | "description": "unique operation id", 1443 | "schema": { 1444 | "type": "string", 1445 | "description": "unique operation id", 1446 | "format": "" 1447 | } 1448 | } 1449 | }, 1450 | "content": { 1451 | "application/json": { 1452 | "schema": { 1453 | "$ref": "#/components/schemas/ResetPasswordResponse" 1454 | } 1455 | } 1456 | } 1457 | }, 1458 | "400": { 1459 | "description": "Bad Request", 1460 | "headers": { 1461 | "operationId": { 1462 | "description": "unique operation id", 1463 | "schema": { 1464 | "type": "string", 1465 | "description": "unique operation id", 1466 | "format": "" 1467 | } 1468 | } 1469 | }, 1470 | "content": { 1471 | "application/problem+json": { 1472 | "schema": { 1473 | "$ref": "#/components/schemas/ValidationProblemDetails" 1474 | } 1475 | } 1476 | } 1477 | }, 1478 | "422": { 1479 | "description": "Operation failed because of provided data or invalid object state in Fiscal backend. Returns problem details structure as described in https://www.rfc-editor.org/rfc/rfc7807 with errorCode field to specify error.", 1480 | "headers": { 1481 | "operationId": { 1482 | "description": "unique operation id", 1483 | "schema": { 1484 | "type": "string", 1485 | "description": "unique operation id", 1486 | "format": "" 1487 | } 1488 | } 1489 | }, 1490 | "content": { 1491 | "application/problem+json": { 1492 | "schema": { 1493 | "$ref": "#/components/schemas/ApiProblemDetails" 1494 | } 1495 | } 1496 | } 1497 | } 1498 | } 1499 | } 1500 | }, 1501 | "/User/v1/{deviceID}/ConfirmContact": { 1502 | "post": { 1503 | "tags": [ 1504 | "User" 1505 | ], 1506 | "description": "Endpoint is used for user contact change confirmation.", 1507 | "parameters": [ 1508 | { 1509 | "name": "Token", 1510 | "in": "header", 1511 | "description": "", 1512 | "required": true, 1513 | "schema": { 1514 | "type": "string" 1515 | } 1516 | }, 1517 | { 1518 | "name": "deviceID", 1519 | "in": "path", 1520 | "required": true, 1521 | "schema": { 1522 | "type": "integer", 1523 | "format": "int32" 1524 | } 1525 | }, 1526 | { 1527 | "name": "DeviceModelName", 1528 | "in": "header", 1529 | "description": "Device model name as registered in Tax Authority", 1530 | "schema": { 1531 | "type": "string" 1532 | } 1533 | }, 1534 | { 1535 | "name": "DeviceModelVersion", 1536 | "in": "header", 1537 | "description": "Device model version number as registered in Tax Authority", 1538 | "schema": { 1539 | "type": "string" 1540 | } 1541 | } 1542 | ], 1543 | "requestBody": { 1544 | "description": "", 1545 | "content": { 1546 | "application/json": { 1547 | "schema": { 1548 | "allOf": [ 1549 | { 1550 | "$ref": "#/components/schemas/ConfirmContactRequest" 1551 | } 1552 | ] 1553 | } 1554 | } 1555 | } 1556 | }, 1557 | "responses": { 1558 | "401": { 1559 | "description": "Device certificate expired.", 1560 | "headers": { 1561 | "operationId": { 1562 | "description": "unique operation id", 1563 | "schema": { 1564 | "type": "string", 1565 | "description": "unique operation id", 1566 | "format": "" 1567 | } 1568 | } 1569 | }, 1570 | "content": { 1571 | "application/problem+json": { 1572 | "schema": { 1573 | "$ref": "#/components/schemas/ProblemDetails" 1574 | } 1575 | } 1576 | } 1577 | }, 1578 | "500": { 1579 | "description": "Server encountered temporary issues.", 1580 | "headers": { 1581 | "operationId": { 1582 | "description": "unique operation id", 1583 | "schema": { 1584 | "type": "string", 1585 | "description": "unique operation id", 1586 | "format": "" 1587 | } 1588 | } 1589 | }, 1590 | "content": { 1591 | "application/problem+json": { 1592 | "schema": { 1593 | "$ref": "#/components/schemas/ProblemDetails" 1594 | }, 1595 | "example": { 1596 | "type": "https://httpstatuses.io/500", 1597 | "title": "Server error", 1598 | "status": 500, 1599 | "operationID": "0HMPDRRQL1C0G:00000005" 1600 | } 1601 | } 1602 | } 1603 | }, 1604 | "200": { 1605 | "description": "Success", 1606 | "headers": { 1607 | "operationId": { 1608 | "description": "unique operation id", 1609 | "schema": { 1610 | "type": "string", 1611 | "description": "unique operation id", 1612 | "format": "" 1613 | } 1614 | } 1615 | }, 1616 | "content": { 1617 | "application/json": { 1618 | "schema": { 1619 | "$ref": "#/components/schemas/ConfirmContactResponse" 1620 | } 1621 | } 1622 | } 1623 | }, 1624 | "400": { 1625 | "description": "Bad Request", 1626 | "headers": { 1627 | "operationId": { 1628 | "description": "unique operation id", 1629 | "schema": { 1630 | "type": "string", 1631 | "description": "unique operation id", 1632 | "format": "" 1633 | } 1634 | } 1635 | }, 1636 | "content": { 1637 | "application/problem+json": { 1638 | "schema": { 1639 | "$ref": "#/components/schemas/ValidationProblemDetails" 1640 | } 1641 | } 1642 | } 1643 | }, 1644 | "422": { 1645 | "description": "Operation failed because of provided data or invalid object state in Fiscal backend. Returns problem details structure as described in https://www.rfc-editor.org/rfc/rfc7807 with errorCode field to specify error.", 1646 | "headers": { 1647 | "operationId": { 1648 | "description": "unique operation id", 1649 | "schema": { 1650 | "type": "string", 1651 | "description": "unique operation id", 1652 | "format": "" 1653 | } 1654 | } 1655 | }, 1656 | "content": { 1657 | "application/problem+json": { 1658 | "schema": { 1659 | "$ref": "#/components/schemas/ApiProblemDetails" 1660 | } 1661 | } 1662 | } 1663 | } 1664 | } 1665 | } 1666 | }, 1667 | "/User/v1/{deviceID}/Update": { 1668 | "post": { 1669 | "tags": [ 1670 | "User" 1671 | ], 1672 | "description": "Endpoint is used to update user.", 1673 | "parameters": [ 1674 | { 1675 | "name": "Token", 1676 | "in": "header", 1677 | "description": "", 1678 | "required": true, 1679 | "schema": { 1680 | "type": "string" 1681 | } 1682 | }, 1683 | { 1684 | "name": "deviceID", 1685 | "in": "path", 1686 | "required": true, 1687 | "schema": { 1688 | "type": "integer", 1689 | "format": "int32" 1690 | } 1691 | }, 1692 | { 1693 | "name": "DeviceModelName", 1694 | "in": "header", 1695 | "description": "Device model name as registered in Tax Authority", 1696 | "schema": { 1697 | "type": "string" 1698 | } 1699 | }, 1700 | { 1701 | "name": "DeviceModelVersion", 1702 | "in": "header", 1703 | "description": "Device model version number as registered in Tax Authority", 1704 | "schema": { 1705 | "type": "string" 1706 | } 1707 | } 1708 | ], 1709 | "requestBody": { 1710 | "description": "", 1711 | "content": { 1712 | "application/json": { 1713 | "schema": { 1714 | "allOf": [ 1715 | { 1716 | "$ref": "#/components/schemas/UpdateUserRequest" 1717 | } 1718 | ] 1719 | } 1720 | } 1721 | } 1722 | }, 1723 | "responses": { 1724 | "401": { 1725 | "description": "Device certificate expired.", 1726 | "headers": { 1727 | "operationId": { 1728 | "description": "unique operation id", 1729 | "schema": { 1730 | "type": "string", 1731 | "description": "unique operation id", 1732 | "format": "" 1733 | } 1734 | } 1735 | }, 1736 | "content": { 1737 | "application/problem+json": { 1738 | "schema": { 1739 | "$ref": "#/components/schemas/ProblemDetails" 1740 | } 1741 | } 1742 | } 1743 | }, 1744 | "500": { 1745 | "description": "Server encountered temporary issues.", 1746 | "headers": { 1747 | "operationId": { 1748 | "description": "unique operation id", 1749 | "schema": { 1750 | "type": "string", 1751 | "description": "unique operation id", 1752 | "format": "" 1753 | } 1754 | } 1755 | }, 1756 | "content": { 1757 | "application/problem+json": { 1758 | "schema": { 1759 | "$ref": "#/components/schemas/ProblemDetails" 1760 | }, 1761 | "example": { 1762 | "type": "https://httpstatuses.io/500", 1763 | "title": "Server error", 1764 | "status": 500, 1765 | "operationID": "0HMPDRRQL1C0G:00000005" 1766 | } 1767 | } 1768 | } 1769 | }, 1770 | "200": { 1771 | "description": "Success", 1772 | "headers": { 1773 | "operationId": { 1774 | "description": "unique operation id", 1775 | "schema": { 1776 | "type": "string", 1777 | "description": "unique operation id", 1778 | "format": "" 1779 | } 1780 | } 1781 | }, 1782 | "content": { 1783 | "application/json": { 1784 | "schema": { 1785 | "$ref": "#/components/schemas/UpdateUserResponse" 1786 | } 1787 | } 1788 | } 1789 | }, 1790 | "400": { 1791 | "description": "Bad Request", 1792 | "headers": { 1793 | "operationId": { 1794 | "description": "unique operation id", 1795 | "schema": { 1796 | "type": "string", 1797 | "description": "unique operation id", 1798 | "format": "" 1799 | } 1800 | } 1801 | }, 1802 | "content": { 1803 | "application/problem+json": { 1804 | "schema": { 1805 | "$ref": "#/components/schemas/ValidationProblemDetails" 1806 | } 1807 | } 1808 | } 1809 | }, 1810 | "422": { 1811 | "description": "Operation failed because of provided data or invalid object state in Fiscal backend. Returns problem details structure as described in https://www.rfc-editor.org/rfc/rfc7807 with errorCode field to specify error.", 1812 | "headers": { 1813 | "operationId": { 1814 | "description": "unique operation id", 1815 | "schema": { 1816 | "type": "string", 1817 | "description": "unique operation id", 1818 | "format": "" 1819 | } 1820 | } 1821 | }, 1822 | "content": { 1823 | "application/problem+json": { 1824 | "schema": { 1825 | "$ref": "#/components/schemas/ApiProblemDetails" 1826 | } 1827 | } 1828 | } 1829 | } 1830 | } 1831 | } 1832 | }, 1833 | "/User/v1/{deviceID}/ConfirmPasswordReset": { 1834 | "post": { 1835 | "tags": [ 1836 | "User" 1837 | ], 1838 | "summary": "Endpoint for confirming password reset", 1839 | "parameters": [ 1840 | { 1841 | "name": "deviceID", 1842 | "in": "path", 1843 | "required": true, 1844 | "schema": { 1845 | "type": "integer", 1846 | "format": "int32" 1847 | } 1848 | }, 1849 | { 1850 | "name": "DeviceModelName", 1851 | "in": "header", 1852 | "description": "Device model name as registered in Tax Authority", 1853 | "schema": { 1854 | "type": "string" 1855 | } 1856 | }, 1857 | { 1858 | "name": "DeviceModelVersion", 1859 | "in": "header", 1860 | "description": "Device model version number as registered in Tax Authority", 1861 | "schema": { 1862 | "type": "string" 1863 | } 1864 | } 1865 | ], 1866 | "requestBody": { 1867 | "description": "", 1868 | "content": { 1869 | "application/json": { 1870 | "schema": { 1871 | "allOf": [ 1872 | { 1873 | "$ref": "#/components/schemas/ConfirmPasswordResetRequest" 1874 | } 1875 | ] 1876 | } 1877 | } 1878 | } 1879 | }, 1880 | "responses": { 1881 | "401": { 1882 | "description": "Device certificate expired.", 1883 | "headers": { 1884 | "operationId": { 1885 | "description": "unique operation id", 1886 | "schema": { 1887 | "type": "string", 1888 | "description": "unique operation id", 1889 | "format": "" 1890 | } 1891 | } 1892 | }, 1893 | "content": { 1894 | "application/problem+json": { 1895 | "schema": { 1896 | "$ref": "#/components/schemas/ProblemDetails" 1897 | } 1898 | } 1899 | } 1900 | }, 1901 | "500": { 1902 | "description": "Server encountered temporary issues.", 1903 | "headers": { 1904 | "operationId": { 1905 | "description": "unique operation id", 1906 | "schema": { 1907 | "type": "string", 1908 | "description": "unique operation id", 1909 | "format": "" 1910 | } 1911 | } 1912 | }, 1913 | "content": { 1914 | "application/problem+json": { 1915 | "schema": { 1916 | "$ref": "#/components/schemas/ProblemDetails" 1917 | }, 1918 | "example": { 1919 | "type": "https://httpstatuses.io/500", 1920 | "title": "Server error", 1921 | "status": 500, 1922 | "operationID": "0HMPDRRQL1C0G:00000005" 1923 | } 1924 | } 1925 | } 1926 | }, 1927 | "200": { 1928 | "description": "Success", 1929 | "headers": { 1930 | "operationId": { 1931 | "description": "unique operation id", 1932 | "schema": { 1933 | "type": "string", 1934 | "description": "unique operation id", 1935 | "format": "" 1936 | } 1937 | } 1938 | }, 1939 | "content": { 1940 | "application/json": { 1941 | "schema": { 1942 | "$ref": "#/components/schemas/LoginResponse" 1943 | } 1944 | } 1945 | } 1946 | }, 1947 | "400": { 1948 | "description": "Bad Request", 1949 | "headers": { 1950 | "operationId": { 1951 | "description": "unique operation id", 1952 | "schema": { 1953 | "type": "string", 1954 | "description": "unique operation id", 1955 | "format": "" 1956 | } 1957 | } 1958 | }, 1959 | "content": { 1960 | "application/problem+json": { 1961 | "schema": { 1962 | "$ref": "#/components/schemas/ValidationProblemDetails" 1963 | } 1964 | } 1965 | } 1966 | }, 1967 | "422": { 1968 | "description": "Operation failed because of provided data or invalid object state in Fiscal backend. Returns problem details structure as described in https://www.rfc-editor.org/rfc/rfc7807 with errorCode field to specify error.", 1969 | "headers": { 1970 | "operationId": { 1971 | "description": "unique operation id", 1972 | "schema": { 1973 | "type": "string", 1974 | "description": "unique operation id", 1975 | "format": "" 1976 | } 1977 | } 1978 | }, 1979 | "content": { 1980 | "application/problem+json": { 1981 | "schema": { 1982 | "$ref": "#/components/schemas/ApiProblemDetails" 1983 | } 1984 | } 1985 | } 1986 | } 1987 | } 1988 | } 1989 | } 1990 | }, 1991 | "components": { 1992 | "schemas": { 1993 | "ApiProblemDetails": { 1994 | "type": "object", 1995 | "properties": { 1996 | "type": { 1997 | "type": "string", 1998 | "nullable": true 1999 | }, 2000 | "title": { 2001 | "type": "string", 2002 | "nullable": true 2003 | }, 2004 | "status": { 2005 | "type": "integer", 2006 | "format": "int32", 2007 | "nullable": true 2008 | }, 2009 | "detail": { 2010 | "type": "string", 2011 | "nullable": true 2012 | }, 2013 | "instance": { 2014 | "type": "string", 2015 | "nullable": true 2016 | }, 2017 | "errorCode": { 2018 | "type": "string", 2019 | "nullable": true 2020 | } 2021 | }, 2022 | "additionalProperties": { } 2023 | }, 2024 | "ChangePasswordRequest": { 2025 | "required": [ 2026 | "newPassword", 2027 | "oldPassword" 2028 | ], 2029 | "type": "object", 2030 | "properties": { 2031 | "oldPassword": { 2032 | "maxLength": 100, 2033 | "minLength": 1, 2034 | "type": "string" 2035 | }, 2036 | "newPassword": { 2037 | "maxLength": 100, 2038 | "minLength": 1, 2039 | "type": "string" 2040 | } 2041 | }, 2042 | "additionalProperties": false 2043 | }, 2044 | "ConfirmContactRequest": { 2045 | "required": [ 2046 | "channel", 2047 | "securityCode" 2048 | ], 2049 | "type": "object", 2050 | "properties": { 2051 | "securityCode": { 2052 | "maxLength": 10, 2053 | "minLength": 1, 2054 | "type": "string" 2055 | }, 2056 | "channel": { 2057 | "allOf": [ 2058 | { 2059 | "$ref": "#/components/schemas/SendSecurityCodeToEnum" 2060 | } 2061 | ] 2062 | } 2063 | }, 2064 | "additionalProperties": false 2065 | }, 2066 | "ConfirmContactResponse": { 2067 | "required": [ 2068 | "operationID", 2069 | "user" 2070 | ], 2071 | "type": "object", 2072 | "properties": { 2073 | "operationID": { 2074 | "maxLength": 60, 2075 | "minLength": 0, 2076 | "type": "string", 2077 | "description": "Operation ID assigned by Fiscalisation Backend.", 2078 | "example": "0HMPH9AF0QKKE:00000005" 2079 | }, 2080 | "user": { 2081 | "allOf": [ 2082 | { 2083 | "$ref": "#/components/schemas/UserDto" 2084 | } 2085 | ] 2086 | } 2087 | }, 2088 | "additionalProperties": false 2089 | }, 2090 | "ConfirmPasswordResetRequest": { 2091 | "required": [ 2092 | "newPassword", 2093 | "securityCode", 2094 | "userName" 2095 | ], 2096 | "type": "object", 2097 | "properties": { 2098 | "userName": { 2099 | "maxLength": 100, 2100 | "minLength": 1, 2101 | "type": "string" 2102 | }, 2103 | "securityCode": { 2104 | "maxLength": 10, 2105 | "minLength": 1, 2106 | "type": "string" 2107 | }, 2108 | "newPassword": { 2109 | "maxLength": 100, 2110 | "minLength": 1, 2111 | "type": "string" 2112 | } 2113 | }, 2114 | "additionalProperties": false 2115 | }, 2116 | "ConfirmUserRequest": { 2117 | "required": [ 2118 | "password", 2119 | "securityCode", 2120 | "userName" 2121 | ], 2122 | "type": "object", 2123 | "properties": { 2124 | "userName": { 2125 | "maxLength": 100, 2126 | "minLength": 1, 2127 | "type": "string" 2128 | }, 2129 | "securityCode": { 2130 | "maxLength": 10, 2131 | "minLength": 1, 2132 | "type": "string" 2133 | }, 2134 | "password": { 2135 | "maxLength": 100, 2136 | "minLength": 1, 2137 | "type": "string" 2138 | } 2139 | }, 2140 | "additionalProperties": false 2141 | }, 2142 | "CreateUserRequest": { 2143 | "required": [ 2144 | "personName", 2145 | "personSurname", 2146 | "userName", 2147 | "userRole" 2148 | ], 2149 | "type": "object", 2150 | "properties": { 2151 | "userName": { 2152 | "maxLength": 100, 2153 | "minLength": 1, 2154 | "type": "string" 2155 | }, 2156 | "personName": { 2157 | "maxLength": 100, 2158 | "minLength": 1, 2159 | "type": "string" 2160 | }, 2161 | "personSurname": { 2162 | "maxLength": 100, 2163 | "minLength": 1, 2164 | "type": "string" 2165 | }, 2166 | "userRole": { 2167 | "maxLength": 100, 2168 | "minLength": 1, 2169 | "type": "string" 2170 | } 2171 | }, 2172 | "additionalProperties": false 2173 | }, 2174 | "CreateUserResponse": { 2175 | "required": [ 2176 | "operationID" 2177 | ], 2178 | "type": "object", 2179 | "properties": { 2180 | "operationID": { 2181 | "maxLength": 60, 2182 | "minLength": 0, 2183 | "type": "string", 2184 | "description": "Operation ID assigned by Fiscalisation Backend.", 2185 | "example": "0HMPH9AF0QKKE:00000005" 2186 | } 2187 | }, 2188 | "additionalProperties": false 2189 | }, 2190 | "GetUsersListEnum": { 2191 | "enum": [ 2192 | "UserName", 2193 | "PersonName", 2194 | "PersonSurname", 2195 | "UserRole", 2196 | "Email", 2197 | "PhoneNo", 2198 | "UserStatus" 2199 | ], 2200 | "type": "string" 2201 | }, 2202 | "GetUsersResponse": { 2203 | "required": [ 2204 | "operationID" 2205 | ], 2206 | "type": "object", 2207 | "properties": { 2208 | "total": { 2209 | "type": "integer", 2210 | "format": "int32" 2211 | }, 2212 | "rows": { 2213 | "type": "array", 2214 | "items": { 2215 | "$ref": "#/components/schemas/UsersListDto" 2216 | }, 2217 | "nullable": true 2218 | }, 2219 | "operationID": { 2220 | "maxLength": 60, 2221 | "minLength": 0, 2222 | "type": "string", 2223 | "description": "Operation ID assigned by Fiscalisation Backend.", 2224 | "example": "0HMPH9AF0QKKE:00000005" 2225 | } 2226 | }, 2227 | "additionalProperties": false 2228 | }, 2229 | "ListRequestOrderEnum": { 2230 | "enum": [ 2231 | "asc", 2232 | "desc" 2233 | ], 2234 | "type": "string" 2235 | }, 2236 | "LogicalOperator": { 2237 | "enum": [ 2238 | "And", 2239 | "Or" 2240 | ], 2241 | "type": "string" 2242 | }, 2243 | "LoginRequest": { 2244 | "required": [ 2245 | "password", 2246 | "userName" 2247 | ], 2248 | "type": "object", 2249 | "properties": { 2250 | "userName": { 2251 | "maxLength": 100, 2252 | "minLength": 1, 2253 | "type": "string" 2254 | }, 2255 | "password": { 2256 | "maxLength": 500, 2257 | "minLength": 1, 2258 | "type": "string" 2259 | } 2260 | }, 2261 | "additionalProperties": false 2262 | }, 2263 | "LoginResponse": { 2264 | "required": [ 2265 | "operationID", 2266 | "token", 2267 | "user" 2268 | ], 2269 | "type": "object", 2270 | "properties": { 2271 | "operationID": { 2272 | "maxLength": 60, 2273 | "minLength": 0, 2274 | "type": "string", 2275 | "description": "Operation ID assigned by Fiscalisation Backend.", 2276 | "example": "0HMPH9AF0QKKE:00000005" 2277 | }, 2278 | "user": { 2279 | "allOf": [ 2280 | { 2281 | "$ref": "#/components/schemas/UserDto" 2282 | } 2283 | ] 2284 | }, 2285 | "token": { 2286 | "minLength": 1, 2287 | "type": "string" 2288 | } 2289 | }, 2290 | "additionalProperties": false 2291 | }, 2292 | "PosUserStatusEnum": { 2293 | "enum": [ 2294 | "NotConfirmed", 2295 | "Active", 2296 | "Blocked" 2297 | ], 2298 | "type": "string" 2299 | }, 2300 | "ProblemDetails": { 2301 | "type": "object", 2302 | "properties": { 2303 | "type": { 2304 | "type": "string", 2305 | "nullable": true 2306 | }, 2307 | "title": { 2308 | "type": "string", 2309 | "nullable": true 2310 | }, 2311 | "status": { 2312 | "type": "integer", 2313 | "format": "int32", 2314 | "nullable": true 2315 | }, 2316 | "detail": { 2317 | "type": "string", 2318 | "nullable": true 2319 | }, 2320 | "instance": { 2321 | "type": "string", 2322 | "nullable": true 2323 | } 2324 | }, 2325 | "additionalProperties": { } 2326 | }, 2327 | "ResetPasswordRequest": { 2328 | "required": [ 2329 | "channel", 2330 | "userName" 2331 | ], 2332 | "type": "object", 2333 | "properties": { 2334 | "userName": { 2335 | "maxLength": 100, 2336 | "minLength": 1, 2337 | "type": "string" 2338 | }, 2339 | "channel": { 2340 | "allOf": [ 2341 | { 2342 | "$ref": "#/components/schemas/SendSecurityCodeToEnum" 2343 | } 2344 | ] 2345 | } 2346 | }, 2347 | "additionalProperties": false 2348 | }, 2349 | "ResetPasswordResponse": { 2350 | "required": [ 2351 | "operationID" 2352 | ], 2353 | "type": "object", 2354 | "properties": { 2355 | "operationID": { 2356 | "maxLength": 60, 2357 | "minLength": 0, 2358 | "type": "string", 2359 | "description": "Operation ID assigned by Fiscalisation Backend.", 2360 | "example": "0HMPH9AF0QKKE:00000005" 2361 | } 2362 | }, 2363 | "additionalProperties": false 2364 | }, 2365 | "SendSecurityCodeToEnum": { 2366 | "enum": [ 2367 | "Email", 2368 | "PhoneNo" 2369 | ], 2370 | "type": "string" 2371 | }, 2372 | "SendSecurityCodeToTaxpayerRequest": { 2373 | "required": [ 2374 | "userName" 2375 | ], 2376 | "type": "object", 2377 | "properties": { 2378 | "userName": { 2379 | "maxLength": 100, 2380 | "minLength": 1, 2381 | "type": "string" 2382 | } 2383 | }, 2384 | "additionalProperties": false 2385 | }, 2386 | "SendSecurityCodeToTaxpayerResponse": { 2387 | "required": [ 2388 | "operationID" 2389 | ], 2390 | "type": "object", 2391 | "properties": { 2392 | "operationID": { 2393 | "maxLength": 60, 2394 | "minLength": 0, 2395 | "type": "string", 2396 | "description": "Operation ID assigned by Fiscalisation Backend.", 2397 | "example": "0HMPH9AF0QKKE:00000005" 2398 | } 2399 | }, 2400 | "additionalProperties": false 2401 | }, 2402 | "SendSecurityCodeToUserEmailRequest": { 2403 | "required": [ 2404 | "userEmail" 2405 | ], 2406 | "type": "object", 2407 | "properties": { 2408 | "userEmail": { 2409 | "maxLength": 100, 2410 | "minLength": 1, 2411 | "type": "string" 2412 | } 2413 | }, 2414 | "additionalProperties": false 2415 | }, 2416 | "SendSecurityCodeToUserEmailResponse": { 2417 | "required": [ 2418 | "operationID" 2419 | ], 2420 | "type": "object", 2421 | "properties": { 2422 | "operationID": { 2423 | "maxLength": 60, 2424 | "minLength": 0, 2425 | "type": "string", 2426 | "description": "Operation ID assigned by Fiscalisation Backend.", 2427 | "example": "0HMPH9AF0QKKE:00000005" 2428 | } 2429 | }, 2430 | "additionalProperties": false 2431 | }, 2432 | "SendSecurityCodeToUserPhoneRequest": { 2433 | "required": [ 2434 | "phoneNo" 2435 | ], 2436 | "type": "object", 2437 | "properties": { 2438 | "phoneNo": { 2439 | "maxLength": 20, 2440 | "minLength": 1, 2441 | "type": "string" 2442 | } 2443 | }, 2444 | "additionalProperties": false 2445 | }, 2446 | "SendSecurityCodeToUserPhoneResponse": { 2447 | "required": [ 2448 | "operationID" 2449 | ], 2450 | "type": "object", 2451 | "properties": { 2452 | "operationID": { 2453 | "maxLength": 60, 2454 | "minLength": 0, 2455 | "type": "string", 2456 | "description": "Operation ID assigned by Fiscalisation Backend.", 2457 | "example": "0HMPH9AF0QKKE:00000005" 2458 | } 2459 | }, 2460 | "additionalProperties": false 2461 | }, 2462 | "UpdateUserRequest": { 2463 | "required": [ 2464 | "personName", 2465 | "personSurname", 2466 | "userName", 2467 | "userRole", 2468 | "userStatus" 2469 | ], 2470 | "type": "object", 2471 | "properties": { 2472 | "userName": { 2473 | "maxLength": 100, 2474 | "minLength": 1, 2475 | "type": "string" 2476 | }, 2477 | "personName": { 2478 | "maxLength": 100, 2479 | "minLength": 1, 2480 | "type": "string" 2481 | }, 2482 | "personSurname": { 2483 | "maxLength": 100, 2484 | "minLength": 1, 2485 | "type": "string" 2486 | }, 2487 | "userRole": { 2488 | "maxLength": 100, 2489 | "minLength": 1, 2490 | "type": "string" 2491 | }, 2492 | "userStatus": { 2493 | "allOf": [ 2494 | { 2495 | "$ref": "#/components/schemas/UpdateUserStatusEnum" 2496 | } 2497 | ] 2498 | } 2499 | }, 2500 | "additionalProperties": false 2501 | }, 2502 | "UpdateUserResponse": { 2503 | "required": [ 2504 | "operationID" 2505 | ], 2506 | "type": "object", 2507 | "properties": { 2508 | "operationID": { 2509 | "maxLength": 60, 2510 | "minLength": 0, 2511 | "type": "string", 2512 | "description": "Operation ID assigned by Fiscalisation Backend.", 2513 | "example": "0HMPH9AF0QKKE:00000005" 2514 | } 2515 | }, 2516 | "additionalProperties": false 2517 | }, 2518 | "UpdateUserStatusEnum": { 2519 | "enum": [ 2520 | "Active", 2521 | "Blocked" 2522 | ], 2523 | "type": "string" 2524 | }, 2525 | "UserDto": { 2526 | "required": [ 2527 | "email", 2528 | "personName", 2529 | "personSurname", 2530 | "phoneNo", 2531 | "userName", 2532 | "userRole" 2533 | ], 2534 | "type": "object", 2535 | "properties": { 2536 | "userName": { 2537 | "maxLength": 100, 2538 | "minLength": 1, 2539 | "type": "string" 2540 | }, 2541 | "personName": { 2542 | "maxLength": 100, 2543 | "minLength": 1, 2544 | "type": "string" 2545 | }, 2546 | "personSurname": { 2547 | "maxLength": 100, 2548 | "minLength": 1, 2549 | "type": "string" 2550 | }, 2551 | "userRole": { 2552 | "maxLength": 100, 2553 | "minLength": 1, 2554 | "type": "string" 2555 | }, 2556 | "email": { 2557 | "maxLength": 100, 2558 | "minLength": 1, 2559 | "type": "string" 2560 | }, 2561 | "phoneNo": { 2562 | "maxLength": 20, 2563 | "minLength": 1, 2564 | "type": "string" 2565 | } 2566 | }, 2567 | "additionalProperties": false 2568 | }, 2569 | "UsersListDto": { 2570 | "required": [ 2571 | "personName", 2572 | "personSurname", 2573 | "userName", 2574 | "userRole", 2575 | "userStatus" 2576 | ], 2577 | "type": "object", 2578 | "properties": { 2579 | "userName": { 2580 | "maxLength": 100, 2581 | "minLength": 1, 2582 | "type": "string" 2583 | }, 2584 | "personName": { 2585 | "maxLength": 100, 2586 | "minLength": 1, 2587 | "type": "string" 2588 | }, 2589 | "personSurname": { 2590 | "maxLength": 100, 2591 | "minLength": 1, 2592 | "type": "string" 2593 | }, 2594 | "userRole": { 2595 | "maxLength": 100, 2596 | "minLength": 1, 2597 | "type": "string" 2598 | }, 2599 | "email": { 2600 | "maxLength": 100, 2601 | "type": "string", 2602 | "nullable": true 2603 | }, 2604 | "phoneNo": { 2605 | "maxLength": 20, 2606 | "type": "string", 2607 | "nullable": true 2608 | }, 2609 | "userStatus": { 2610 | "allOf": [ 2611 | { 2612 | "$ref": "#/components/schemas/PosUserStatusEnum" 2613 | } 2614 | ] 2615 | } 2616 | }, 2617 | "additionalProperties": false 2618 | }, 2619 | "ValidationProblemDetails": { 2620 | "type": "object", 2621 | "properties": { 2622 | "type": { 2623 | "type": "string", 2624 | "nullable": true 2625 | }, 2626 | "title": { 2627 | "type": "string", 2628 | "nullable": true 2629 | }, 2630 | "status": { 2631 | "type": "integer", 2632 | "format": "int32", 2633 | "nullable": true 2634 | }, 2635 | "detail": { 2636 | "type": "string", 2637 | "nullable": true 2638 | }, 2639 | "instance": { 2640 | "type": "string", 2641 | "nullable": true 2642 | }, 2643 | "errors": { 2644 | "type": "object", 2645 | "additionalProperties": { 2646 | "type": "array", 2647 | "items": { 2648 | "type": "string" 2649 | } 2650 | }, 2651 | "nullable": true 2652 | } 2653 | }, 2654 | "additionalProperties": { } 2655 | } 2656 | } 2657 | }, 2658 | "tags": [ 2659 | { 2660 | "name": "User", 2661 | "description": "All methods are synchronous.\r\nFiscal Device Gateway uses mutual TLS authentication (https://en.wikipedia.org/wiki/Mutual_authentication) to authenticate fiscal device using fiscal device certificate. Fiscal device certificate is validated against issuing certificate to allow or deny access to API endpoints.\r\nAfter authentication provided fiscal device certificate is checked against issued certificate (see registerDevice and issueCertificate methods for fiscal device certificate issuing) to check if the fiscal device certificate was issued to calling device (by method parameter deviceId) and the fiscal device certificate was not revoked" 2662 | } 2663 | ] 2664 | } --------------------------------------------------------------------------------