ICS React Native App
1openapi: 3.0.3
2info:
3 title: Banking Demo API
4 version: 1.0.0
5 description: |
6 Minimal spec matching the current Express+SQLite implementation with request/response validation.
7 ⚠️ Demo only: `/cards` returns full PAN + CVV as stored.
8
9servers:
10 - url: http://localhost:3001
11
12components:
13 securitySchemes:
14 BearerAuth:
15 type: http
16 scheme: bearer
17 bearerFormat: JWT
18
19 responses:
20 Error400:
21 description: Bad Request (validation error)
22 content:
23 application/json:
24 schema:
25 $ref: "#/components/schemas/Error"
26 Error401:
27 description: Unauthorized / missing or invalid credentials
28 content:
29 application/json:
30 schema:
31 $ref: "#/components/schemas/Error"
32 Error403:
33 description: Forbidden
34 content:
35 application/json:
36 schema:
37 $ref: "#/components/schemas/Error"
38 Error500:
39 description: Internal Server Error
40 content:
41 application/json:
42 schema:
43 $ref: "#/components/schemas/Error"
44
45 schemas:
46 LoginRequest:
47 type: object
48 required: [username, password]
49 properties:
50 username:
51 type: string
52 example: test@test.test
53 password:
54 type: string
55 example: password@123
56
57 TokenPair:
58 type: object
59 required: [accessToken, refreshToken, expires]
60 properties:
61 accessToken:
62 type: string
63 description: Access JWT (short-lived).
64 refreshToken:
65 type: string
66 description: Refresh JWT (longer-lived).
67 expires:
68 type: string
69 format: date-time
70 description: Access token expiry timestamp (ISO 8601). Present on /login, omitted on /refresh-token.
71 example: "2024-06-01T10:05:00Z"
72
73 RefreshRequest:
74 type: object
75 required: [refreshToken]
76 properties:
77 refreshToken:
78 type: string
79
80 Account:
81 type: object
82 required: [id, user_id, name, iban, balance]
83 properties:
84 id: { type: integer }
85 user_id: { type: integer }
86 iban: { type: string }
87 name: { type: string }
88 balance:
89 type: number
90 format: float
91 description: Calculated from transactions; 0 if none.
92 example:
93 id: 1
94 user_id: 1
95 name: Checking
96 balance: 1680.16
97
98 Card:
99 type: object
100 required: [id, user_id, number, expiry, cvv]
101 properties:
102 id: { type: integer }
103 user_id: { type: integer }
104 number:
105 type: string
106 description: Full PAN (as stored). Returned as-is by the current API.
107 example: "4111111111111111"
108 expiry: { type: string, example: "12/26" }
109 cvv: { type: string, example: "123" }
110
111 PaginationMeta:
112 type: object
113 required: [page, limit, total, hasMore]
114 properties:
115 page:
116 type: integer
117 description: Current page number (1-based)
118 limit:
119 type: integer
120 description: Page size
121 hasMore:
122 type: boolean
123 description: True if there are more pages after the current one
124 total:
125 type: integer
126 description: Total number of matching items
127
128 PaginatedTransactions:
129 type: object
130 required: [data, meta]
131 properties:
132 data:
133 type: array
134 items:
135 $ref: "#/components/schemas/Transaction"
136 meta:
137 $ref: "#/components/schemas/PaginationMeta"
138
139 TransactionType:
140 type: object
141 required: [name, count]
142 properties:
143 name: { type: string }
144 count: { type: integer }
145
146 Transaction:
147 type: object
148 required: [id, userId, accountId, amount, type, description, date]
149 properties:
150 id: { type: integer }
151 userId: { type: integer }
152 accountId: { type: integer }
153 amount:
154 type: number
155 format: float
156 description: Positive for credits, negative for debits.
157 type:
158 type: string
159 description:
160 type: string
161 date:
162 type: string
163 format: date-time
164 description: ISO 8601 timestamp.
165 example: "2024-06-01T10:00:00Z"
166
167 User:
168 type: object
169 required: [id, username, fullname, created]
170 properties:
171 id:
172 type: integer
173 description: Unique user ID
174 example: 2
175 username:
176 type: string
177 description: login/username of the user
178 example: nmokkenstorm
179 fullname:
180 type: string
181 description: government name of the user
182 example: Niels Mokkenstorm
183 created:
184 type: string
185 format: date-time
186 description: ISO 8601 timestamp.
187 example: "2024-06-01T10:00:00Z"
188
189 Error:
190 type: object
191 properties:
192 message:
193 type: string
194
195 LoginError:
196 type: object
197 description: Standard validation/error envelope.
198 required: [errors]
199 properties:
200 errors:
201 type: array
202 description: Non-field/global errors.
203 items:
204 type: string
205 properties:
206 type: object
207 description: Per-field validation errors.
208 properties:
209 username:
210 $ref: "#/components/schemas/FieldError"
211 password:
212 $ref: "#/components/schemas/FieldError"
213
214 example:
215 errors: []
216 properties:
217 username:
218 errors: ["Invalid email address"]
219 password:
220 errors: ["Too small: expected string to have >=8 characters"]
221
222 FieldError:
223 type: object
224 required: [errors]
225 properties:
226 errors:
227 type: array
228 items:
229 type: string
230
231tags:
232 - name: Meta
233 - name: Auth
234 - name: Accounts
235 - name: Cards
236 - name: Transactions
237
238paths:
239 /:
240 get:
241 summary: Swagger Documentation
242 description: Serves the Swagger UI for this API.
243 tags: [Meta]
244 responses:
245 "200":
246 description: Documentation page
247 content:
248 text/html:
249 schema:
250 type: string
251
252 /openapi.yaml:
253 get:
254 summary: OpenAPI Spec
255 description: Serves the OpenAPI YAML document used by the validator.
256 tags: [Meta]
257 responses:
258 "200":
259 description: OpenAPI spec (YAML)
260 content:
261 application/yaml:
262 schema:
263 type: string
264 /me:
265 get:
266 summary: Retrieves information about the authenticated user
267 tags: [Auth]
268 security:
269 - BearerAuth: []
270 responses:
271 "200":
272 description: User object
273 content:
274 application/json:
275 schema:
276 $ref: "#/components/schemas/User"
277 "401":
278 $ref: "#/components/responses/Error401"
279 "403":
280 $ref: "#/components/responses/Error403"
281 "500":
282 $ref: "#/components/responses/Error500"
283 /login:
284 post:
285 summary: Login with username and password
286 tags: [Auth]
287 requestBody:
288 required: true
289 content:
290 application/json:
291 schema:
292 $ref: "#/components/schemas/LoginRequest"
293 responses:
294 "200":
295 description: Token pair issued
296 content:
297 application/json:
298 schema:
299 $ref: "#/components/schemas/TokenPair"
300 "400":
301 $ref: "#/components/responses/Error400"
302 "401":
303 description: Invalid credentials
304 content:
305 application/json:
306 schema:
307 $ref: "#/components/schemas/LoginError"
308 "500":
309 $ref: "#/components/responses/Error500"
310
311 /refresh-token:
312 post:
313 summary: Exchange refresh token for new access & refresh tokens
314 tags: [Auth]
315 requestBody:
316 required: true
317 content:
318 application/json:
319 schema:
320 $ref: "#/components/schemas/RefreshRequest"
321 responses:
322 "200":
323 description: New token pair
324 content:
325 application/json:
326 schema:
327 $ref: "#/components/schemas/TokenPair"
328 "400":
329 $ref: "#/components/responses/Error400"
330 "401":
331 $ref: "#/components/responses/Error401"
332 "500":
333 $ref: "#/components/responses/Error500"
334
335 /accounts:
336 get:
337 summary: List accounts for the authenticated user, including calculated balances
338 tags: [Accounts]
339 security:
340 - BearerAuth: []
341 responses:
342 "200":
343 description: Array of accounts
344 content:
345 application/json:
346 schema:
347 type: array
348 items:
349 $ref: "#/components/schemas/Account"
350 "401":
351 $ref: "#/components/responses/Error401"
352 "403":
353 $ref: "#/components/responses/Error403"
354 "500":
355 $ref: "#/components/responses/Error500"
356
357 /accounts/{accountId}:
358 get:
359 summary: Retrieves a single account for the authenticated user, including calculated balances
360 parameters:
361 - in: path
362 name: accountId
363 schema:
364 type: integer
365 required: true
366 description: Numeric ID of the account to get
367 tags: [Accounts]
368 security:
369 - BearerAuth: []
370 responses:
371 "200":
372 description: Account object
373 content:
374 application/json:
375 schema:
376 $ref: "#/components/schemas/Account"
377 "401":
378 $ref: "#/components/responses/Error401"
379 "403":
380 $ref: "#/components/responses/Error403"
381 "500":
382 $ref: "#/components/responses/Error500"
383
384 /cards:
385 get:
386 summary: List stored cards for the authenticated user
387 description: Returns full PAN and CVV as currently implemented. **Do not use in production.**
388 tags: [Cards]
389 security:
390 - BearerAuth: []
391 responses:
392 "200":
393 description: Array of cards
394 content:
395 application/json:
396 schema:
397 type: array
398 items:
399 $ref: "#/components/schemas/Card"
400 "401":
401 $ref: "#/components/responses/Error401"
402 "403":
403 $ref: "#/components/responses/Error403"
404 "500":
405 $ref: "#/components/responses/Error500"
406
407 /transaction-types:
408 get:
409 summary: Find transaction types for the authenticated user
410 tags: [Transactions]
411 security:
412 - BearerAuth: []
413 parameters:
414 - in: query
415 name: accountId
416 schema:
417 type: integer
418 description: Filter by account ID
419 responses:
420 "200":
421 description: Array of transaction types
422 content:
423 application/json:
424 schema:
425 type: array
426 items:
427 $ref: "#/components/schemas/TransactionType"
428 "400":
429 $ref: "#/components/responses/Error400"
430 "401":
431 $ref: "#/components/responses/Error401"
432 "403":
433 $ref: "#/components/responses/Error403"
434 "500":
435 $ref: "#/components/responses/Error500"
436
437 /transactions:
438 get:
439 summary: Search/sort/paginate transactions for the authenticated user
440 tags: [Transactions]
441 security:
442 - BearerAuth: []
443 parameters:
444 - in: query
445 name: search
446 schema:
447 type: string
448 description: Case-insensitive LIKE search against description and type.
449 example: Shopping
450 - in: query
451 name: sort
452 schema:
453 type: string
454 default: date
455 description: Column to sort by (free-form; current API does not enforce an allowlist).
456 example: date
457 - in: query
458 name: order
459 schema:
460 type: string
461 default: desc
462 enum: [asc, desc]
463 - in: query
464 name: page
465 schema:
466 type: integer
467 default: 1
468 minimum: 1
469 - in: query
470 name: limit
471 schema:
472 type: integer
473 default: 25
474 description: Page size
475 - in: query
476 name: accountId
477 schema:
478 type: integer
479 description: Filter by account ID
480 - in: query
481 name: type
482 schema:
483 type: string
484 description: Filter by transaction type (withdrawal, deposit, etc.)
485 responses:
486 "200":
487 description: Array of transactions (page slice)
488 content:
489 application/json:
490 schema:
491 $ref: "#/components/schemas/PaginatedTransactions"
492 "400":
493 $ref: "#/components/responses/Error400"
494 "401":
495 $ref: "#/components/responses/Error401"
496 "403":
497 $ref: "#/components/responses/Error403"
498 "500":
499 $ref: "#/components/responses/Error500"