-
Notifications
You must be signed in to change notification settings - Fork 0
/
swagger.json
951 lines (951 loc) · 37.3 KB
/
swagger.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
{
"swagger": "2.0",
"info": {
"title": "Betsson Expense Tool",
"version": "1.0.0",
"description": "The following are a list of API resources required for the Betsson Expense Tool Implementation. One can observe that most of the endpoints have /1/ in them. Their purpose for the API developers to keep version control of API endpoints, hence be able to service old versions of the app."
},
"host": "www.betssongroup.com",
"basePath": "/1",
"schemes": [
"http"
],
"produces": [
"application/json"
],
"consumes": [
"application/json"
],
"securityDefinitions": {
"token": {
"type": "apiKey",
"in": "header",
"name": "token"
}
},
"security": [
{
"token": []
}
],
"paths": {
"/sessions": {
"post": {
"summary": "Authenticate User",
"description": "Once the user is successfully logged in, the server will return an authentication token to the client in the header.\nEvery time there is a call to the service, the token lifetime will be extended.",
"parameters": [
{
"name": "credentials",
"in": "body",
"description": "Loggin credentials",
"required": true,
"schema": {
"$ref": "#/definitions/Credentials"
}
}
],
"security": [
{
"token": []
}
],
"responses": {
"200": {
"description": "OK",
"headers": {
"Location": {
"description": "Login was successful.",
"type": "string"
}
}
},
"401": {
"description": "Incorrect Credentials",
"schema": {
"$ref": "#/definitions/Error"
}
},
"403": {
"description": "Forbidden / Blocked",
"schema": {
"$ref": "#/definitions/Error"
}
}
},
"tags": [
"Session"
]
},
"put": {
"summary": "Keep-Alive",
"description": "The authentication token will have an expiry time and when the token expires, all API endpoints that require a valid token will return an HTTP Status 403 (forbidden). This situation can occur if the user is interacting with the app, but he leaves the mobile in the same screen until the token expires. He will still be considered as logged in for the app's purposes, but the token will expire, and API calls start to fail.An easy and clean solution for this problem is to have a Keep-Alive service, and if the app is running, the app will automatically hit this endpoint upon fixed times (say every 5-10 minutes, as advised by the API developers) so that if the token is about to expire, the API will renew the token so that the authentication will be retained.",
"parameters": [],
"security": [
{
"token": []
}
],
"tags": [
"Session"
],
"responses": {
"200": {
"description": "OK - Token is renewed"
},
"401": {
"description": "Incorrect Credentials",
"schema": {
"$ref": "#/definitions/Error"
}
},
"403": {
"description": "Forbidden / Blocked",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
}
},
"/currencies": {
"get": {
"summary": "Get Currencies",
"description": "This service will retrieve a list of all included currencies and exchange rates that will later on be used in currency selectors, and calculations involving exchange rates. Data is returned in alphabetical order sorted by currency.",
"tags": [
"Currency"
],
"parameters": [],
"security": [
{
"token": []
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Currency"
}
}
},
"401": {
"description": "Unauthorised - invalid or non existing token",
"schema": {
"$ref": "#/definitions/Error"
}
},
"403": {
"description": "Forbidden / Blocked",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
}
},
"/expensetypes": {
"get": {
"summary": "Get Expense Types",
"description": "This service will retrieve a list of all available expense types defined by business. Data is returned in alphabetical order sorted by name. The expense types are required by the API in order to be able to determine who will be the manager who needs to authorise which expense.",
"tags": [
"ExpenseType"
],
"parameters": [],
"security": [
{
"token": []
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/ExpenseType"
}
}
},
"401": {
"description": "Incorrect Credentials",
"schema": {
"$ref": "#/definitions/Error"
}
},
"403": {
"description": "Forbidden / Blocked",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
}
},
"/trips/{id}": {
"get": {
"summary": "Find trip by id",
"description": "Load a trip by the id provided",
"tags": [
"Trips"
],
"parameters": [
{
"in": "path",
"name": "id",
"type": "number",
"format": "int64",
"description": "The trip id that is being edited",
"required": true
}
],
"security": [
{
"token": []
}
],
"responses": {
"200": {
"description": "OK - Returns the found trip",
"schema": {
"$ref": "#/definitions/Trip"
}
},
"401": {
"description": "Incorrect Credentials",
"schema": {
"$ref": "#/definitions/Error"
}
},
"403": {
"description": "Forbidden / Blocked",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
},
"put": {
"summary": "Update Trip",
"description": "Loads the trip with the id provided and update the data accordingly",
"tags": [
"Trips"
],
"parameters": [
{
"in": "path",
"name": "id",
"type": "number",
"format": "int64",
"description": "The trip id that is being edited",
"required": true
},
{
"in": "body",
"name": "trip",
"description": "The trip object you want to persist",
"required": true,
"schema": {
"$ref": "#/definitions/Trip"
}
}
],
"security": [
{
"token": []
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/Trip"
}
},
"401": {
"description": "Incorrect Credentials",
"schema": {
"$ref": "#/definitions/Error"
}
},
"403": {
"description": "Forbidden / Blocked",
"schema": {
"$ref": "#/definitions/Error"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
}
},
"/expenses/{id}": {
"get": {
"summary": "Find Expenses By Search Criteria",
"description": "Returns a list of Expenses based on the search criteria provided in query string parameters",
"security": [
{
"token": []
}
],
"parameters": [
{
"in": "query",
"name": "pageNumber",
"type": "number",
"format": "int32",
"description": "The data page number that needs to be returned. Default- 0",
"required": false
},
{
"in": "query",
"name": "pageCount",
"type": "number",
"format": "int32",
"description": "The amount of data contained in one single page. Default- 100"
},
{
"in": "query",
"name": "type",
"type": "string",
"description": "Specify which type of expense you want to retrieve. Default- null (no type condition applied)",
"enum": [
"TRIP",
"ONE_OFF"
],
"required": false
},
{
"in": "query",
"name": "settled",
"type": "boolean",
"description": "When true - return expenses with status APPROVED, APPROVED_REVISED. When false - return expenses with status OPEN, SENT, REJECTED. Default- null (no status condition applied)",
"required": false
}
],
"responses": {
"200": {
"description": "OK - Returns the Paged Expenses",
"schema": {
"$ref": "#/definitions/PagedExpenses"
}
},
"401": {
"description": "Incorrect Credentials",
"schema": {
"$ref": "#/definitions/Error"
}
},
"403": {
"description": "Forbidden / Blocked",
"schema": {
"$ref": "#/definitions/Error"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/Error"
}
}
},
"tags": [
"Expense"
]
},
"post": {
"summary": "Create Expense",
"description": "An expense is essentially the glue that ties a trip to a list of receipts, and includes information of what expenses were carried out during the trip.",
"security": [
{
"token": []
}
],
"parameters": [
{
"in": "body",
"name": "expense",
"description": "The expense object that will be persisted. If a trip object is defined inside the Expense Create Request model, then a trip will be created and associated with the expense",
"required": true,
"schema": {
"$ref": "#/definitions/ExpenseCreateRequest"
}
}
],
"responses": {
"200": {
"description": "OK - Returns the created Expense",
"schema": {
"$ref": "#/definitions/Expense"
}
},
"401": {
"description": "Incorrect Credentials",
"schema": {
"$ref": "#/definitions/Error"
}
},
"403": {
"description": "Forbidden / Blocked",
"schema": {
"$ref": "#/definitions/Error"
}
}
},
"tags": [
"Expense"
]
},
"put": {
"summary": "Update Expense",
"description": "An expense can be updated",
"tags": [
"Expense"
],
"parameters": [
{
"name": "id",
"in": "path",
"description": "The expense id to update",
"required": true,
"type": "string"
},
{
"in": "body",
"name": "expense",
"description": "The expense object that will be updated",
"required": true,
"schema": {
"$ref": "#/definitions/ExpenseUpdateRequest"
}
}
],
"responses": {
"200": {
"description": "OK - Returns the matched Expense",
"schema": {
"$ref": "#/definitions/Expense"
}
},
"401": {
"description": "Incorrect Credentials",
"schema": {
"$ref": "#/definitions/Error"
}
},
"403": {
"description": "Forbidden / Blocked",
"schema": {
"$ref": "#/definitions/Error"
}
},
"404": {
"description": "This is an http status indicating that no expense matched the id provided.",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
},
"delete": {
"summary": "Delete Expense",
"description": "Delete a expense by the *id* provided. The Process will delete the expense, associated trip (if any) and also any the associated scanned receipts. The API developer can opt for physical / virtual deletion as necessary.",
"tags": [
"Expense"
],
"parameters": [
{
"name": "id",
"in": "path",
"description": "",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "OK"
},
"401": {
"description": "Incorrect Credentials",
"schema": {
"$ref": "#/definitions/Error"
}
},
"403": {
"description": "Forbidden / Blocked",
"schema": {
"$ref": "#/definitions/Error"
}
},
"404": {
"description": "This is an http status indicating that no expense matched the id provided.",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
}
},
"/receipt/{id}": {
"post": {
"summary": "Create a receipt",
"description": "When a receipt is created, the image url will not be provided inside the payload, mainly because encoding image data inside a json payload will triple the data size and is not considered as a best practice to include binary data inside a json file.",
"tags": [
"Receipts"
],
"parameters": [
{
"in": "query",
"name": "expenseId",
"type": "number",
"format": "int64",
"description": "When provided, the receipt will be associated with the expense requested",
"required": false
},
{
"in": "body",
"name": "receipt",
"description": "The receipt object that will be persisted",
"required": true,
"schema": {
"$ref": "#/definitions/Receipt"
}
}
],
"security": [
{
"token": []
}
],
"responses": {
"200": {
"description": "OK - Returns the newly created receipt",
"schema": {
"$ref": "#/definitions/Receipt"
}
},
"401": {
"description": "Incorrect Credentials",
"schema": {
"$ref": "#/definitions/Error"
}
},
"403": {
"description": "Forbidden / Blocked",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
}
},
"/receipt/{id}/upload": {
"post": {
"summary": "Upload Receipt Scan",
"description": "When a receit is created, the app will upload the receipt scan using a multipart/form-data request. The uploaded file will have its filename as [receiptId]. jpg/png/gif. If possible (to check with Infusion), the API will return the associated Receipt object. Content-type header must be set to multipart/form-data.",
"tags": [
"Receipts"
],
"parameters": [
{
"name": "id",
"in": "path",
"description": "The uploaded image will be associated with the Receipt id provided",
"required": true,
"type": "number",
"format": "int64"
},
{
"name": "data",
"in": "body",
"description": "The image binary data that needs to be uploaded and associated with a receipt",
"type": "string",
"required": true
}
],
"security": [
{
"token": []
}
],
"responses": {
"200": {
"description": "OK - Returns the matched receipt",
"schema": {
"$ref": "#/definitions/Receipt"
}
},
"401": {
"description": "Incorrect Credentials",
"schema": {
"$ref": "#/definitions/Error"
}
},
"403": {
"description": "Forbidden / Blocked",
"schema": {
"$ref": "#/definitions/Error"
}
},
"404": {
"description": "This is an http status indicating that no matching receipt has been found for the given receipt scan file.",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
}
}
},
"definitions": {
"Error": {
"type": "object",
"properties": {
"message": {
"type": "string",
"description": "Error messge description describing the error message returned by the server"
}
}
},
"Credentials": {
"type": "object",
"properties": {
"username": {
"type": "string",
"description": "The user name",
"example": "johndoe"
},
"password": {
"type": "string",
"description": "The user's password"
},
"deviceid": {
"type": "string",
"description": "The app will pick up the unique device's id and use together with the authentication credentials. The device might be blocked in case the user has lost his mobile phone"
}
}
},
"Currency": {
"type": "object",
"properties": {
"currencyCode": {
"type": "string",
"description": "The currency code",
"example": "eur"
},
"currency": {
"type": "string",
"description": "The currency name",
"example": "EUR"
},
"symbol": {
"type": "string",
"description": "The currency symbol",
"example": "€"
},
"rate": {
"type": "number",
"format": "double",
"example": 1
}
}
},
"ExpenseType": {
"type": "object",
"properties": {
"id": {
"type": "number",
"format": "int32",
"description": "The Expense type reference (possibly an autonumber set up on the server",
"example": 1
},
"name": {
"type": "string",
"description": "The name, that will be displayed on the screen",
"example": "Fitness"
}
}
},
"Trip": {
"type": "object",
"properties": {
"id": {
"type": "number",
"format": "int64",
"description": "The trip's id. This property will be null when a new trip is being created by the client.",
"example": 1001,
"required": false
},
"type": {
"type": "string",
"description": "Trip type, being one of the enum values provided",
"enum": [
"BUSINESS",
"MARKETING"
],
"required": true
},
"campaignId": {
"type": "string",
"description": "Campaign id is required when the trip type is a Marketing trip. The user has to enter a campaign id associated with this expense",
"example": "B1005",
"required": false
},
"name": {
"type": "string",
"description": "Friendly trip name",
"example": "Team Building Activity Travel",
"required": true
},
"destination": {
"type": "string",
"description": "Trip Destination name",
"example": "Stockholm",
"required": true
},
"departure": {
"type": "string",
"description": "This is the departure date and time",
"format": "yyyy-MM-dd'T'HH:mm:ss'Z'",
"required": true
},
"return": {
"type": "string",
"description": "This is the trip's return date and time",
"format": "yyyy-MM-dd'T'HH:mm:ss'Z'",
"required": true
},
"note": {
"type": "string",
"description": "Additional notes that the user might provide together with this trip",
"required": true
},
"privateAccomodation": {
"type": "boolean",
"description": "Enabled if the accomodation is not going to be paid by the company. Default is false"
}
}
},
"Receipt": {
"type": "object",
"properties": {
"id": {
"type": "number",
"format": "int64",
"description": "The receipt's id. This property will be null when a new receipt is being created by the client.",
"example": 100
},
"type": {
"type": "string",
"description": "Trip type, being one of the enum values provided",
"enum": [
"BUSINESS",
"MARKETING"
],
"required": true
},
"campaignId": {
"type": "string",
"description": "Campaign id is required when the trip type is a Marketing trip. The user has to enter a campaign id associated with this expense",
"example": "B1005",
"required": false
},
"description": {
"type": "string",
"description": "Expense description",
"example": "Taxi to hotel"
},
"currency": {
"description": "Stamp of the currency object, including conversion rate at the time when the receipt was created",
"$ref": "#/definitions/Currency"
},
"expenseType": {
"$ref": "#/definitions/ExpenseType"
},
"amount": {
"type": "number",
"format": "double",
"description": "The amount that is displayed on the receipt that the user entered, and will be vetted by the manager.",
"example": 1,
"required": true
},
"date": {
"type": "string",
"format": "yyyy-MM-dd'T'HH:mm:ss'Z'",
"description": "Date and time when the receipt was registered"
},
"note": {
"type": "string",
"description": "This is a special instruction that the user wants to add to the note"
},
"scanUrl": {
"type": "string",
"description": "If a scanned image is uploaded, then this field will contain an absolute url to an image that the app can download to display in a list"
}
}
},
"ExpenseUpdateRequest": {
"type": "object",
"description": "The expense update request model",
"properties": {
"receipts": {
"type": "array",
"items": {
"type": "number",
"format": "int64",
"description": "This is a collection of receipt ids that will be managed by this expense definition",
"collectionFormat": "multi"
},
"required": false
},
"status": {
"type": "string",
"description": "Expense's current status",
"enum": [
"OPEN",
"SENT",
"APPROVED",
"APPROVED_REVISED",
"REJECTED"
],
"required": true
},
"breakfastCount": {
"type": "number",
"format": "int32",
"description": "The amount of breakfasts that the employee is not paying for",
"required": false
},
"lunchCount": {
"type": "number",
"format": "int32",
"description": "The amount of lunches that the employee is not paying for",
"required": false
},
"dinnerCount": {
"type": "number",
"format": "int32",
"description": "The amount of dinners that the employee is not paying for",
"required": false
}
}
},
"ExpenseCreateRequest": {
"type": "object",
"description": "The expense creation request",
"allof": [
{
"$ref": "#/definitions/ExpenseUpdateRequest"
}
],
"properties": {
"trip": {
"description": "The associated trip id. This can be null if the expense is a one-off expense. When defined, the API will create a Trip object together with the Expense object, and bind them together.",
"$ref": "#/definitions/Trip",
"required": false
}
}
},
"Expense": {
"type": "object",
"properties": {
"id": {
"type": "number",
"format": "int64",
"description": "The expense's id. This property will be null when a new expense is created by the client.",
"example": 1003,
"required": true
},
"type": {
"type": "string",
"description": "An enumeration value indicating the type of expense it is. Currently only Trip / one-of expenses are supported, but we might have more in the future.",
"enum": [
"TRIP",
"ONE_OFF"
],
"required": true
},
"trip": {
"description": "The trip associated with this expense",
"$ref": "#/definitions/Trip",
"required": false
},
"receipts": {
"type": "array",
"items": {
"$ref": "#/definitions/Receipt"
},
"required": false
},
"statusTimestamp": {
"type": "string",
"format": "yyyy-MM-dd'T'HH:mm:ss'Z'",
"description": "The timestamp of the date the last status was updated. This is updated by the server.",
"required": true
},
"status": {
"type": "string",
"description": "Expense's current status",
"enum": [
"OPEN",
"SENT",
"APPROVED",
"APPROVED_REVISED",
"REJECTED"
],
"required": true
},
"rejectedReason": {
"type": "string",
"description": "If the trip has been rejected, the manager can add a note informing the user why the trip has been rejected. Field is expected to be null if the status is not REJECTED",
"required": false
},
"breakfastCount": {
"type": "number",
"format": "int32",
"description": "The amount of breakfasts that the employee is not paying for",
"required": false
},
"lunchCount": {
"type": "number",
"format": "int32",
"description": "The amount of lunches that the employee is not paying for",
"required": false
},
"dinnerCount": {
"type": "number",
"format": "int32",
"description": "The amount of dinners that the employee is not paying for",
"required": false
}
}
},
"PagedExpenses": {
"type": "object",
"properties": {
"count": {
"type": "number",
"format": "int32",
"description": "The amount of data returned by the search."
},
"page": {
"type": "number",
"format": "int32",
"description": "The page number that is currently being viewed"
},
"data": {
"type": "array",
"items": {
"$ref": "#/definitions/Expense"
}
}
}
}
}
}