{"_id":"@anikghosh256/fortnox-node-sdk","_rev":"5-7258c01c2b158f2e86a5f5ba5e70f0e5","name":"@anikghosh256/fortnox-node-sdk","dist-tags":{"latest":"0.3.0"},"versions":{"0.0.1":{"name":"@anikghosh256/fortnox-node-sdk","version":"0.0.1","keywords":["fortnox","api","sdk","accounting","oauth","typescript","node","fetch"],"author":{"name":"Onik G."},"license":"MIT","_id":"@anikghosh256/fortnox-node-sdk@0.0.1","maintainers":[{"name":"anikghosh256","email":"anikghosh46.bd@gmail.com"}],"homepage":"https://github.com/anikghosh256/fortnox-node-sdk#readme","bugs":{"url":"https://github.com/anikghosh256/fortnox-node-sdk/issues"},"dist":{"shasum":"0345deb9f8b0073058ce638fc56ac210974ced99","tarball":"https://registry.npmjs.org/@anikghosh256/fortnox-node-sdk/-/fortnox-node-sdk-0.0.1.tgz","fileCount":42,"integrity":"sha512-nrQgCOtlvnjgZ9422hTsIRv4GCdc5j+Oq/8yeRV7n7yl2EW2x+Nc/X6Rovyes1mltUilWJ3KwXKZhHFFDJ5YbQ==","signatures":[{"sig":"MEUCIQCK5d2Op3fcLAzCMKUAMxyDx57e8WaiGXSvPSzuCZJtJgIgC0VnBratE+H+ykwpynLTAeb3YdGuduF1CPSeEqgYdg0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":62522},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=18.0.0"},"gitHead":"caac02d65211c6c08c52fe4f894422575ad57b59","scripts":{"lint":"eslint src --ext .ts","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","lint:fix":"eslint src --ext .ts --fix","test:watch":"jest --watch","format:check":"prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"","test:coverage":"jest --coverage","prepublishOnly":"npm run lint && npm run test && npm run build"},"_npmUser":{"name":"anikghosh256","email":"anikghosh46.bd@gmail.com"},"repository":{"url":"git+https://github.com/anikghosh256/fortnox-node-sdk.git","type":"git"},"_npmVersion":"11.6.2","description":"Modern Node.js SDK for Fortnox API with native fetch and automatic token refresh","directories":{},"_nodeVersion":"24.11.1","_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^8.56.0","ts-jest":"^29.1.1","ts-node":"^10.9.2","prettier":"^3.1.1","typescript":"^5.3.3","@types/jest":"^29.5.11","@types/node":"^20.10.6","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.2","@typescript-eslint/parser":"^6.17.0","@typescript-eslint/eslint-plugin":"^6.17.0"},"_npmOperationalInternal":{"tmp":"tmp/fortnox-node-sdk_0.0.1_1770274675222_0.15975920116246067","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@anikghosh256/fortnox-node-sdk","version":"0.1.0","keywords":["fortnox","api","sdk","accounting","oauth","typescript","node","fetch"],"author":{"name":"Onik G."},"license":"MIT","_id":"@anikghosh256/fortnox-node-sdk@0.1.0","maintainers":[{"name":"anikghosh256","email":"anikghosh46.bd@gmail.com"}],"homepage":"https://github.com/anikghosh256/fortnox-node-sdk#readme","bugs":{"url":"https://github.com/anikghosh256/fortnox-node-sdk/issues"},"dist":{"shasum":"06f66a80eaad3f8b867c8f433ad24e600e785706","tarball":"https://registry.npmjs.org/@anikghosh256/fortnox-node-sdk/-/fortnox-node-sdk-0.1.0.tgz","fileCount":42,"integrity":"sha512-9DdZs1GjWwKv3E247QRyeZlmnfmBpzQIblaEUxNYIuGDCjYLeNNTwW5cTSzbhwIFv1IV4gC51cHyIptwLkT3Fw==","signatures":[{"sig":"MEYCIQDjV6ok2og6/X8FcolVoWs8I65nh+BY3ZS3yMyzdw8hTAIhAM5+kdZ1wwttrf7dUJzvuWrdjoZZ45SoGeMPd1m71Wpw","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":62557},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=18.0.0"},"gitHead":"96135ddd7f23128f175e3b0f8bde4527558b8bea","scripts":{"lint":"eslint src --ext .ts","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","lint:fix":"eslint src --ext .ts --fix","test:watch":"jest --watch","format:check":"prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"","test:coverage":"jest --coverage","prepublishOnly":"npm run lint && npm run test && npm run build"},"_npmUser":{"name":"anikghosh256","email":"anikghosh46.bd@gmail.com"},"repository":{"url":"git+https://github.com/anikghosh256/fortnox-node-sdk.git","type":"git"},"_npmVersion":"11.6.2","description":"Modern Node.js SDK for Fortnox API with native fetch and automatic token refresh","directories":{},"_nodeVersion":"24.11.1","_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^8.56.0","ts-jest":"^29.1.1","ts-node":"^10.9.2","prettier":"^3.1.1","typescript":"^5.3.3","@types/jest":"^29.5.11","@types/node":"^20.10.6","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.2","@typescript-eslint/parser":"^6.17.0","@typescript-eslint/eslint-plugin":"^6.17.0"},"_npmOperationalInternal":{"tmp":"tmp/fortnox-node-sdk_0.1.0_1771221243763_0.9296010700709452","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@anikghosh256/fortnox-node-sdk","version":"0.2.0","keywords":["fortnox","api","sdk","accounting","invoicing","orders","articles","pricelists","pricing","erp","oauth","oauth2","typescript","node","fetch","e-commerce","b2b"],"author":{"name":"Onik G."},"license":"MIT","_id":"@anikghosh256/fortnox-node-sdk@0.2.0","maintainers":[{"name":"anikghosh256","email":"anikghosh46.bd@gmail.com"}],"homepage":"https://github.com/anikghosh256/fortnox-node-sdk#readme","bugs":{"url":"https://github.com/anikghosh256/fortnox-node-sdk/issues"},"dist":{"shasum":"4b1e9b59e3f2d927be729db92ad0653f9b4569ff","tarball":"https://registry.npmjs.org/@anikghosh256/fortnox-node-sdk/-/fortnox-node-sdk-0.2.0.tgz","fileCount":66,"integrity":"sha512-GE/00d592HbeN7zKMfXDfthvg38/bObRz6ZCCmustKUcrx8OflCOqes70KUl7Xyubcg+yL0YsNynoK9zHOn6WQ==","signatures":[{"sig":"MEUCIFfuHhPmQmE6jkXOfMs4XWerJE3B7yyhjrfeY14Xv6qvAiEA6cA8d74DXePJHAnQGo7yS8GdNaFxRoFipHks2dpDBSo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":130150},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=18.0.0"},"gitHead":"4ef096fff91e582c943c715179e3863ff86cdb38","scripts":{"lint":"eslint src --ext .ts","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","lint:fix":"eslint src --ext .ts --fix","test:watch":"jest --watch","format:check":"prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"","test:coverage":"jest --coverage","prepublishOnly":"npm run lint && npm run test && npm run build"},"_npmUser":{"name":"anikghosh256","email":"anikghosh46.bd@gmail.com"},"repository":{"url":"git+https://github.com/anikghosh256/fortnox-node-sdk.git","type":"git"},"_npmVersion":"11.6.2","description":"Modern Node.js SDK for Fortnox API with OAuth 2.0, automatic token refresh, and support for Articles, Orders, Price Lists, and Pricing","directories":{},"_nodeVersion":"24.11.1","_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^8.56.0","ts-jest":"^29.1.1","ts-node":"^10.9.2","prettier":"^3.1.1","typescript":"^5.3.3","@types/jest":"^29.5.11","@types/node":"^20.10.6","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.2","@typescript-eslint/parser":"^6.17.0","@typescript-eslint/eslint-plugin":"^6.17.0"},"_npmOperationalInternal":{"tmp":"tmp/fortnox-node-sdk_0.2.0_1771235393016_0.505427354911463","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@anikghosh256/fortnox-node-sdk","version":"0.2.1","keywords":["fortnox","api","sdk","accounting","invoicing","orders","articles","customers","pricelists","pricing","erp","oauth","oauth2","typescript","node","fetch","e-commerce","b2b"],"author":{"name":"Onik G."},"license":"MIT","_id":"@anikghosh256/fortnox-node-sdk@0.2.1","maintainers":[{"name":"anikghosh256","email":"anikghosh46.bd@gmail.com"}],"homepage":"https://github.com/anikghosh256/fortnox-node-sdk#readme","bugs":{"url":"https://github.com/anikghosh256/fortnox-node-sdk/issues"},"dist":{"shasum":"88699180ecc8a2bf61097565a1e655703f611ae5","tarball":"https://registry.npmjs.org/@anikghosh256/fortnox-node-sdk/-/fortnox-node-sdk-0.2.1.tgz","fileCount":74,"integrity":"sha512-LkJyMI9oSZ+puFMQVPDEnW/OpMqzOjo807gaohULbAmDquIlh8UFsS6arrVcDs8pOpJ9UixCro2vasB3PJ5nKA==","signatures":[{"sig":"MEUCIQDyLBvcCOnWzJvQvAbbGkS7zIEcNe0/Hh8djqYeumN7kwIgR6nD+y5/gVwykKHEH5vw64DB1cDXxDCRo3NiVPNj43o=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":152125},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=18.0.0"},"gitHead":"5af8ec0f45be16616a6eca75a608bd04737edb8a","scripts":{"lint":"eslint src --ext .ts","test":"jest","build":"tsc","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","lint:fix":"eslint src --ext .ts --fix","test:watch":"jest --watch","format:check":"prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"","test:coverage":"jest --coverage","prepublishOnly":"npm run lint && npm run test && npm run build"},"_npmUser":{"name":"anikghosh256","email":"anikghosh46.bd@gmail.com"},"repository":{"url":"git+https://github.com/anikghosh256/fortnox-node-sdk.git","type":"git"},"_npmVersion":"11.8.0","description":"Modern Node.js SDK for Fortnox API with OAuth 2.0, automatic token refresh, and support for Articles, Customers, Orders, Price Lists, and Pricing","directories":{},"_nodeVersion":"20.19.2","_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^8.56.0","ts-jest":"^29.1.1","ts-node":"^10.9.2","prettier":"^3.1.1","typescript":"^5.3.3","@types/jest":"^29.5.11","@types/node":"^20.10.6","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.2","@typescript-eslint/parser":"^6.17.0","@typescript-eslint/eslint-plugin":"^6.17.0"},"_npmOperationalInternal":{"tmp":"tmp/fortnox-node-sdk_0.2.1_1771395757457_0.34367056940602736","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@anikghosh256/fortnox-node-sdk","version":"0.3.0","description":"Modern Node.js SDK for Fortnox API with OAuth 2.0, automatic token refresh, and support for Articles, Customers, Orders, Invoices, Price Lists, and Pricing","main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"tsc","test":"jest","test:watch":"jest --watch","test:coverage":"jest --coverage","lint":"eslint src --ext .ts","lint:fix":"eslint src --ext .ts --fix","format":"prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"","format:check":"prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"","prepublishOnly":"npm run lint && npm run test && npm run build"},"keywords":["fortnox","api","sdk","accounting","invoicing","invoices","orders","articles","customers","pricelists","pricing","erp","oauth","oauth2","typescript","node","fetch","e-commerce","b2b","bookkeeping"],"author":{"name":"Onik G."},"license":"MIT","engines":{"node":">=18.0.0"},"devDependencies":{"@types/jest":"^29.5.11","@types/node":"^20.10.6","@typescript-eslint/eslint-plugin":"^6.17.0","@typescript-eslint/parser":"^6.17.0","eslint":"^8.56.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.2","jest":"^29.7.0","prettier":"^3.1.1","ts-jest":"^29.1.1","ts-node":"^10.9.2","typescript":"^5.3.3"},"repository":{"type":"git","url":"git+https://github.com/anikghosh256/fortnox-node-sdk.git"},"homepage":"https://github.com/anikghosh256/fortnox-node-sdk#readme","bugs":{"url":"https://github.com/anikghosh256/fortnox-node-sdk/issues"},"publishConfig":{"access":"public"},"gitHead":"cb57f8386eef387e5b7cc13b2baa61db4254161c","_id":"@anikghosh256/fortnox-node-sdk@0.3.0","_nodeVersion":"24.11.1","_npmVersion":"11.6.2","dist":{"integrity":"sha512-0eJRnbbFzSxIWv24+p5HzR7ygjDBytTLuGsNL+JVkBegeJHmq4mSvcO3x7nveOkH/krJignSE+/oZsAh6kuIVA==","shasum":"4ac3a3c7d6369fc724855371d5e595e820a69f0b","tarball":"https://registry.npmjs.org/@anikghosh256/fortnox-node-sdk/-/fortnox-node-sdk-0.3.0.tgz","fileCount":86,"unpackedSize":196661,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCICgfFlbNsVj0W5A5NHTycfduK0QoTpe7xh+r1dZTdTcyAiBb/v2JbxkNUZk/M3pm7LgNB2kRdbj5J7cVmeQ8vLbcqQ=="}]},"_npmUser":{"name":"anikghosh256","email":"anikghosh46.bd@gmail.com"},"directories":{},"maintainers":[{"name":"anikghosh256","email":"anikghosh46.bd@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/fortnox-node-sdk_0.3.0_1771585061235_0.9418963137144263"},"_hasShrinkwrap":false}},"time":{"created":"2026-02-05T06:57:55.129Z","modified":"2026-02-20T10:57:41.486Z","0.0.1":"2026-02-05T06:57:55.368Z","0.1.0":"2026-02-16T05:54:03.907Z","0.2.0":"2026-02-16T09:49:53.155Z","0.2.1":"2026-02-18T06:22:37.613Z","0.3.0":"2026-02-20T10:57:41.386Z"},"bugs":{"url":"https://github.com/anikghosh256/fortnox-node-sdk/issues"},"author":{"name":"Onik G."},"license":"MIT","homepage":"https://github.com/anikghosh256/fortnox-node-sdk#readme","keywords":["fortnox","api","sdk","accounting","invoicing","invoices","orders","articles","customers","pricelists","pricing","erp","oauth","oauth2","typescript","node","fetch","e-commerce","b2b","bookkeeping"],"repository":{"type":"git","url":"git+https://github.com/anikghosh256/fortnox-node-sdk.git"},"description":"Modern Node.js SDK for Fortnox API with OAuth 2.0, automatic token refresh, and support for Articles, Customers, Orders, Invoices, Price Lists, and Pricing","maintainers":[{"name":"anikghosh256","email":"anikghosh46.bd@gmail.com"}],"readme":"# Fortnox Node.js SDK\n\nModern TypeScript SDK for Fortnox API with OAuth 2.0 and automatic token refresh.\n\n[![CI](https://github.com/anikghosh256/fortnox-node-sdk/workflows/CI/badge.svg)](https://github.com/anikghosh256/fortnox-node-sdk/actions)\n[![npm version](https://badge.fury.io/js/%40anikghosh256%2Ffortnox-node-sdk.svg)](https://www.npmjs.com/package/@anikghosh256/fortnox-node-sdk)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n\n## Features\n\n- OAuth 2.0 authentication with CSRF protection\n- Automatic token refresh (proactive before expiry)\n- Config-locked instances (isolated per instance)\n- Native fetch (Node.js 18+, zero dependencies)\n- Full TypeScript support\n- Comprehensive error handling\n- Articles CRUD operations\n- Customers management\n- Orders management with invoicing support\n- **Invoices management** - create, bookkeep, email, print, credit\n- Price Lists and Pricing management\n\n## Installation\n\n```bash\nnpm install @anikghosh256/fortnox-node-sdk\n```\n\n**Requirements:** Node.js >= 18.0.0\n\n## Usage\n\n### Initialize SDK\n\n```typescript\nimport { FortnoxClient } from '@anikghosh256/fortnox-node-sdk';\n\nconst client = new FortnoxClient({\n  clientId: 'your-client-id',\n  clientSecret: 'your-client-secret',\n  redirectUri: 'https://yourapp.com/callback',\n  scopes: ['article', 'companyinformation'],\n  log: true, // Enable debug logging (optional)\n});\n```\n\n### OAuth Authentication\n\n```typescript\n// Generate authorization URL\nconst { url, state } = client.getAuthManager().getAuthorizationUrl();\n// Store state in session: req.session.state = state\n// Redirect user: res.redirect(url)\n\n// Handle callback\nconst tokens = await client.getAuthManager().exchangeCodeForToken(code, state);\n```\n\n### Articles API\n\n```typescript\n// List\nconst articles = await client.articles.list({ page: 1, limit: 10 });\n\n// Get\nconst article = await client.articles.get('ART001');\n\n// Create\nconst newArticle = await client.articles.create({\n  Description: 'Product Name',\n  SalesPrice: 99.99,\n  VAT: 25,\n});\n\n// Update\nawait client.articles.update('ART001', { SalesPrice: 129.99 });\n\n// Delete\nawait client.articles.delete('ART001');\n```\n\n### Customers API\n\n```typescript\n// List all customers\nconst customers = await client.customers.list();\n\n// List active customers only\nconst activeCustomers = await client.customers.list({ \n  filter: 'active',\n  sortby: 'name'\n});\n\n// Search customers by name, city, email, etc.\nconst searchResults = await client.customers.list({\n  name: 'Acme',\n  city: 'Stockholm',\n  email: 'contact@example.com',\n});\n\n// Get specific customer\nconst customer = await client.customers.get('CUST001');\n\n// Create new customer\nconst newCustomer = await client.customers.create({\n  Name: 'Acme Corporation AB',\n  Type: 'COMPANY',\n  OrganisationNumber: '555555-5555',\n  Email: 'contact@acme.com',\n  Phone1: '+46 8 123 456',\n  Address1: 'Main Street 123',\n  City: 'Stockholm',\n  ZipCode: '11122',\n  CountryCode: 'SE',\n  Currency: 'SEK',\n  VATType: 'SEVAT',\n  Active: true,\n  PriceList: 'A',\n  TermsOfPayment: '30',\n});\n\n// Update customer\nconst updated = await client.customers.update('CUST001', {\n  Email: 'newemail@acme.com',\n  Phone1: '+46 8 987 654',\n  Comments: 'VIP customer - priority handling',\n});\n\n// Delete customer\nawait client.customers.delete('CUST001');\n```\n\n### Orders API\n\n```typescript\n// List orders with filters\nconst orders = await client.orders.list({\n  customernumber: 'C001',\n  orderdatefrom: '2024-01-01',\n  orderdateto: '2024-12-31',\n  notcompleted: true,\n  page: 1,\n  limit: 10,\n});\n\n// Get single order\nconst order = await client.orders.get('1');\n\n// Create order\nconst newOrder = await client.orders.create({\n  CustomerNumber: 'C001',\n  OrderDate: '2024-01-15',\n  DeliveryDate: '2024-01-20',\n  OrderRows: [\n    {\n      ArticleNumber: 'ART001',\n      OrderedQuantity: '5',\n      Price: 150,\n      VAT: 25,\n      Discount: 10,\n    },\n  ],\n  Comments: 'Urgent order',\n  Language: 'EN',\n  Freight: 50,\n});\n\n// Update order\nawait client.orders.update('1', {\n  Comments: 'Updated comment',\n  DeliveryDate: '2024-01-18',\n});\n\n// Cancel order\nawait client.orders.cancel('1');\n\n// Create invoice from order\nconst invoice = await client.orders.createInvoice('1');\n\n// Send order by email\nawait client.orders.sendEmail('1');\n\n// Print order (returns PDF buffer)\nconst pdfBuffer = await client.orders.print('1');\n\n// Preview order (returns PDF buffer without marking as printed)\nconst previewBuffer = await client.orders.preview('1');\n\n// Get external print template\nconst printData = await client.orders.externalPrint('1');\n```\n\n### Invoices API\n\n```typescript\n// List invoices with filters\nconst invoices = await client.invoices.list({\n  filter: 'unpaid',\n  customernumber: 'CUST001',\n  fromdate: '2024-01-01',\n  todate: '2024-12-31',\n  sortby: 'invoicedate',\n});\n\n// Get specific invoice\nconst invoice = await client.invoices.get('1');\n\n// Create invoice\nconst newInvoice = await client.invoices.create({\n  CustomerNumber: 'CUST001',\n  InvoiceDate: '2024-02-20',\n  DueDate: '2024-03-20',\n  DeliveryDate: '2024-02-22',\n  Comments: 'Thank you for your business',\n  Language: 'EN',\n  Currency: 'SEK',\n  InvoiceRows: [\n    {\n      ArticleNumber: 'ART001',\n      Description: 'Consulting Services',\n      Price: 1500,\n      VAT: 25,\n      Discount: 10,\n    },\n  ],\n  OurReference: 'John Doe',\n  YourReference: 'Jane Smith',\n  Freight: 100,\n  AdministrationFee: 50,\n});\n\n// Update invoice\nawait client.invoices.update('1', {\n  Comments: 'Updated payment terms',\n  Remarks: 'Payment within 45 days',\n});\n\n// Bookkeep invoice (finalize for accounting)\nconst bookedInvoice = await client.invoices.bookkeep('1');\n\n// Cancel invoice\nconst cancelledInvoice = await client.invoices.cancel('1');\n\n// Create credit invoice\nconst creditInvoice = await client.invoices.credit('1');\n\n// Send invoice by email\nawait client.invoices.sendEmail('1');\n\n// Print invoice (returns PDF buffer)\nconst pdfBuffer = await client.invoices.print('1');\n\n// Preview invoice (returns PDF without marking as sent)\nconst previewBuffer = await client.invoices.preview('1');\n\n// Mark invoice as sent (external print)\nawait client.invoices.externalPrint('1');\n\n// Create invoice with email information\nconst invoiceWithEmail = await client.invoices.create({\n  CustomerNumber: 'CUST001',\n  InvoiceDate: '2024-02-20',\n  Currency: 'SEK',\n  InvoiceRows: [{ ArticleNumber: 'ART001', Price: 999, VAT: 25 }],\n  EmailInformation: {\n    EmailAddressTo: 'customer@example.com',\n    EmailSubject: 'Your Invoice',\n    EmailBody: 'Thank you for your business!',\n  },\n});\n```\n\n### Price Lists API\n\n```typescript\n// List all price lists\nconst priceLists = await client.priceLists.list();\n\n// Get specific price list\nconst priceList = await client.priceLists.get('A');\n\n// Create new price list\nconst newPriceList = await client.priceLists.create({\n  Code: 'WHOLESALE',\n  Description: 'Wholesale Prices',\n  Comments: 'For wholesale customers',\n  PreSelected: false,\n});\n\n// Update price list\nawait client.priceLists.update('WHOLESALE', {\n  Description: 'Updated Wholesale Prices',\n  Comments: 'New comment',\n});\n\n// Delete price list\nawait client.priceLists.delete('WHOLESALE');\n```\n\n### Prices API\n\n```typescript\n// List all prices (optionally filter by price list)\nconst allPrices = await client.prices.list({\n  pricelist: 'A',\n  articlenumber: 'ART001',\n});\n\n// Get specific price\nconst price = await client.prices.get('A', 'ART001');\n\n// Get price for specific quantity level (volume pricing)\nconst bulkPrice = await client.prices.get('A', 'ART001', 100);\n\n// Create new price (using fixed price)\nawait client.prices.create({\n  ArticleNumber: 'ART001',\n  PriceList: 'WHOLESALE',\n  Price: 85.00,\n  FromQuantity: 1,\n});\n\n// Create price using percentage discount\nawait client.prices.create({\n  ArticleNumber: 'ART001',\n  PriceList: 'VIP',\n  Percent: -15, // 15% discount\n  FromQuantity: 1,\n});\n\n// Create volume discount (bulk pricing)\nawait client.prices.create({\n  ArticleNumber: 'ART001',\n  PriceList: 'WHOLESALE',\n  Price: 75.00, // Lower price\n  FromQuantity: 100, // When buying 100+\n});\n\n// Update price\nawait client.prices.update('WHOLESALE', 'ART001', 1, {\n  Price: 80.00,\n});\n\n// Delete price\nawait client.prices.delete('WHOLESALE', 'ART001', 1);\n```\n\n## Configuration\n\n| Option | Type | Required | Description |\n|--------|------|----------|-------------|\n| `clientId` | string | Yes | Fortnox client ID |\n| `clientSecret` | string | Yes | Fortnox client secret |\n| `redirectUri` | string | Yes | OAuth redirect URI |\n| `scopes` | string[] | No | API scopes (default: ['article']) |\n| `baseUrl` | string | No | API base URL |\n| `log` | boolean | No | Enable debug logging (default: false) |\n| `onTokenRefresh` | function | No | Callback when tokens refresh |\n| `onTokenExpire` | function | No | Callback when refresh token expires |\n| `initialAccessToken` | string | No | Existing access token |\n| `initialRefreshToken` | string | No | Existing refresh token |\n\n## Token Management\n\nAccess tokens are automatically refreshed 5 minutes before expiry.\n\n### Persist Tokens\n\n```typescript\nconst client = new FortnoxClient({\n  clientId: 'your-client-id',\n  clientSecret: 'your-client-secret',\n  redirectUri: 'https://yourapp.com/callback',\n  initialAccessToken: loadedAccessToken,\n  initialRefreshToken: loadedRefreshToken,\n  log: false, // Disable logging in production\n  onTokenRefresh: async (tokens) => {\n    await db.saveTokens(tokens);\n  },\n});\n```\n\n**Token Lifetimes:**\n- Access token: 1 hour\n- Refresh token: 45 days\n- Both tokens regenerate on refresh\n\n## Error Handling\n\n```typescript\nimport { AuthenticationError, ValidationError, NotFoundError } from '@anikghosh256/fortnox-node-sdk';\n\ntry {\n  const article = await client.articles.get('ART001');\n} catch (error) {\n  if (error instanceof AuthenticationError) {\n    console.error('Auth failed:', error.message);\n  } else if (error instanceof NotFoundError) {\n    console.error('Not found:', error.message);\n  } else if (error instanceof ValidationError) {\n    console.error('Invalid input:', error.message);\n  }\n}\n```\n\n**Error Types:**\n- `AuthenticationError` - 401/403 responses\n- `ValidationError` - 400 responses\n- `NotFoundError` - 404 responses\n- `RateLimitError` - 429 responses\n- `ApiError` - Other API errors\n\n## Development\n\n```bash\nnpm install          # Install dependencies\nnpm test             # Run tests\nnpm run build        # Build package\nnpm run lint         # Lint code\n```\n\n## License\n\nMIT © [Onik G.](https://github.com/anikghosh256)\n\n## Links\n\n- [Fortnox Developer Portal](https://www.fortnox.se/developer)\n- [Fortnox API Docs](https://apps.fortnox.se/apidocs)\n- [Issues](https://github.com/anikghosh256/fortnox-node-sdk/issues)","readmeFilename":"README.md"}