@unifetch/fortnox 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -0,0 +1,181 @@
1
+ # @unifetch/fortnox
2
+
3
+ TypeScript SDK for the [Fortnox API](https://api.fortnox.se/apidocs), fully typed from the official OpenAPI specification — with corrections applied where the spec has incorrect or overly permissive types.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @unifetch/fortnox
9
+ # or
10
+ pnpm add @unifetch/fortnox
11
+ ```
12
+
13
+ ## Initialization
14
+
15
+ There are two ways to initialize the client.
16
+
17
+ ### 1. Access token
18
+
19
+ Use this if you manage your own oAuth flow and already have a Fortnox access token.
20
+
21
+ ```ts
22
+ import { initFortnox } from "@unifetch/fortnox";
23
+
24
+ const fortnox = initFortnox({
25
+ accessToken: "your-access-token",
26
+ });
27
+ ```
28
+
29
+ ### 2. Proxy via unifetch.dev
30
+
31
+ [unifetch.dev](https://unifetch.dev) acts as a proxy layer that internally handles OAuth and token rotation, removing the need to manage credentials yourself.
32
+
33
+ ```ts
34
+ import { initFortnox } from "@unifetch/fortnox";
35
+
36
+ const fortnox = initFortnox({
37
+ proxy: {
38
+ baseUrl: "https://proxy.unifetch.dev/fortnox",
39
+ apiKey: "your-api-key", // You generate it on unifetch.dev dashboard
40
+ tenantId: "your-tenant-id", // Your company's unique fortnox id. You can see it on unifetch.dev dashboard.
41
+ },
42
+ });
43
+ ```
44
+
45
+ ## Usage
46
+
47
+ Every response is a discriminated union of `{ error: null; data: T }` or `{ error: ErrorResponse; data: null }`. Once you handle (or narrow) the error branch, TypeScript automatically infers that `data` is non-null.
48
+
49
+ There are two ways to call the API.
50
+
51
+ ### Resource-based API (recommended)
52
+
53
+ Access resources by name and call operations by their ID. Both the resource name and operation ID are autocompleted by TypeScript.
54
+
55
+ > **Note:** The operation names (e.g. `getList`, `create`, `bookkeep`) are **manually curated** and are not derived from the official Fortnox OpenAPI specification. The official spec uses operation ids that are inconsistent and ambiguous across endpoints. The names used here follow a consistent, human-readable convention defined in [`overrides/operation-ids.json`](overrides/operation-ids.json).
56
+
57
+ ```ts
58
+ const { data, error } = await fortnox.invoices.getList();
59
+
60
+ if (error) {
61
+ console.error(error.ErrorInformation.message);
62
+ } else {
63
+ // data is non-null here — TypeScript knows this after the error check
64
+ console.log(data.Invoices);
65
+ }
66
+ ```
67
+
68
+ #### With query parameters
69
+
70
+ ```ts
71
+ const { data, error } = await fortnox.invoices.getList({
72
+ query: { fromdate: "2024-01-01", todate: "2024-12-31" },
73
+ });
74
+
75
+ if (error) throw error;
76
+
77
+ for (const invoice of data.Invoices) {
78
+ console.log(invoice.DocumentNumber, invoice.Total);
79
+ }
80
+ ```
81
+
82
+ #### Creating a resource
83
+
84
+ ```ts
85
+ const { data, error } = await fortnox.invoices.create({
86
+ body: {
87
+ Invoice: {
88
+ CustomerNumber: "1",
89
+ InvoiceRows: [
90
+ { ArticleNumber: "A1", DeliveredQuantity: 2 },
91
+ ],
92
+ },
93
+ },
94
+ });
95
+
96
+ if (error) throw error;
97
+
98
+ console.log(data.Invoice.DocumentNumber);
99
+ ```
100
+
101
+ #### Fetching a single resource by ID
102
+
103
+ ```ts
104
+ const { data, error } = await fortnox.invoices.get({
105
+ params: { DocumentNumber: "100" },
106
+ });
107
+
108
+ if (error) throw error;
109
+
110
+ console.log(data.Invoice.CustomerName);
111
+ ```
112
+
113
+ #### Calling an action on a resource
114
+
115
+ ```ts
116
+ const { data, error } = await fortnox.invoices.bookkeep({
117
+ params: { DocumentNumber: "100" },
118
+ });
119
+ ```
120
+
121
+ ### Path-based API
122
+
123
+ If you want to access an endpoint directly by its raw path, use `fortnox.path()`. This is equivalent to the resource-based API under the hood. The path and all the parameters are fully typed.
124
+
125
+ ```ts
126
+ const { data, error } = await fortnox.path("/3/invoices").get();
127
+
128
+ if (error) throw error;
129
+
130
+ console.log(data.Invoices);
131
+ ```
132
+
133
+ ```ts
134
+ const { data, error } = await fortnox.path("/3/invoices/{DocumentNumber}").get({
135
+ params: { DocumentNumber: "100" },
136
+ });
137
+ ```
138
+
139
+ ## Type definitions
140
+
141
+ ### `@unifetch/fortnox` (default) — patched types
142
+
143
+ The default import uses **patched type definitions**. Fortnox's official OpenAPI spec has a number of incorrect or missing type constraints (e.g. response wrapper properties marked as optional when they are always present). This package fixes those issues so the types accurately reflect real API behavior. But some of the "patched" types can still be incorrect since we do not have clear documentation.
144
+
145
+ ```ts
146
+ import { initFortnox } from "@unifetch/fortnox";
147
+ // or equivalently:
148
+ import { initFortnox } from "@unifetch/fortnox/patched";
149
+ ```
150
+
151
+ ### `@unifetch/fortnox/official` — unmodified types
152
+
153
+ If you need the raw types exactly as they appear in Fortnox's official OpenAPI specification, import from the `/official` subpath.
154
+
155
+ ```ts
156
+ import { initFortnox } from "@unifetch/fortnox/official";
157
+ ```
158
+
159
+ > **Note:** The official types may include inaccuracies inherited from the upstream spec. Prefer the default (patched) import unless you have a specific reason to use the unmodified types.
160
+
161
+ ## Error handling
162
+
163
+ The error object has the following shape:
164
+
165
+ ```ts
166
+ type ErrorResponse = {
167
+ ErrorSource: "fortnox" | "unknown";
168
+ ErrorInformation: {
169
+ error: number;
170
+ message: string;
171
+ code: number;
172
+ };
173
+ };
174
+ ```
175
+
176
+ - `ErrorSource: "fortnox"` — the Fortnox API returned a non-2xx response.
177
+ - `ErrorSource: "unknown"` — a network or unexpected error occurred.
178
+
179
+ ## License
180
+
181
+ ISC