airalo-sdk 1.0.1__py3-none-any.whl

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.
@@ -0,0 +1,948 @@
1
+ Metadata-Version: 2.4
2
+ Name: airalo-sdk
3
+ Version: 1.0.1
4
+ Summary: Official Airalo Python SDK for Airalo's REST API
5
+ Home-page: https://github.com/Airalo/airalo-python-sdk
6
+ Author: Airalo
7
+ Author-email: Airalo <partner.integration@airalo.com>
8
+ License: MIT License
9
+
10
+ Copyright (c) 2025 Airalo
11
+
12
+ Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ of this software and associated documentation files (the "Software"), to deal
14
+ in the Software without restriction, including without limitation the rights
15
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
+ copies of the Software, and to permit persons to whom the Software is
17
+ furnished to do so, subject to the following conditions:
18
+
19
+ The above copyright notice and this permission notice shall be included in all
20
+ copies or substantial portions of the Software.
21
+
22
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
+ SOFTWARE.
29
+
30
+ Classifier: Programming Language :: Python :: 3
31
+ Classifier: License :: OSI Approved :: MIT License
32
+ Requires-Python: >=3.1
33
+ Description-Content-Type: text/markdown
34
+ License-File: LICENSE
35
+ Requires-Dist: requests
36
+ Requires-Dist: cryptography
37
+ Dynamic: author
38
+ Dynamic: home-page
39
+ Dynamic: license-file
40
+ Dynamic: requires-python
41
+
42
+ # Airalo Python SDK
43
+ Airalo's Python SDK provides simple integration with the REST API and an extra layer of convenience on top.
44
+ The SDK supports:
45
+ - automatic authentication
46
+ - optional caching and rate‑limit handling
47
+ - fetching packages: local, global, country, and all combined
48
+ - auto‑pagination on package endpoints
49
+ - ordering packages
50
+ - bulk ordering different packages and quantities at once
51
+ - top‑up ordering
52
+ - unified JSON responses as standard Python dicts
53
+ - works on Linux, macOS, and Windows
54
+
55
+ # Requisites
56
+ - Python >= `3.11`
57
+ - `requests` installed (the SDK depends on it)
58
+
59
+ # Installation
60
+ Install via pip:
61
+ ```bash
62
+ pip install airalo-sdk
63
+ ```
64
+
65
+ # Initialization
66
+ Object usage:
67
+ ```python
68
+ from airalo import Airalo
69
+
70
+ alo = Airalo({
71
+ "client_id": "<YOUR_API_CLIENT_ID>", # mandatory
72
+ "client_secret": "<YOUR_API_CLIENT_SECRET>", # mandatory
73
+ })
74
+
75
+ all_packages = alo.get_all_packages(flat=True)
76
+ ```
77
+
78
+ # Responses
79
+ The SDK returns standard Python dicts. You can access keys directly or convert to strings with `json.dumps` if needed.
80
+
81
+ # Methods Interface
82
+ <h2> Packages </h2>
83
+
84
+ >**_NOTE:_**
85
+ >Passing `True` to the `flat` parameter makes the response significantly more compact and easy to handle. However it differs from the main one returned from the endpoints. Be mindful when you need the original vs the compact version.
86
+
87
+ `def get_all_packages(flat: bool = False, limit: int | None = None, page: int | None = None) -> dict | None`
88
+ Fetching all Airalo packages.<br>
89
+ NOTE that depending on from the pricing model (field named 'model' in the pricing object) there can be additional fields displayed or hidden. Check the documentation link below for more details.<br>
90
+ By default the response mirrors the packages REST endpoint (more here: https://developers.partners.airalo.com/get-packages-11883036e0). Passing `flat=True` returns package objects in a single data object, example:
91
+ ```json
92
+ {
93
+ "pricing": {
94
+ "model": "net_pricing",
95
+ "discount_percentage": 0
96
+ },
97
+ "data": [
98
+ {
99
+ "package_id": "meraki-mobile-7days-1gb",
100
+ "slug": "greece",
101
+ "type": "sim",
102
+ "price": 5,
103
+ "net_price": 4,
104
+ "amount": 1024,
105
+ "day": 7,
106
+ "is_unlimited": false,
107
+ "title": "1 GB - 7 Days",
108
+ "data": "1 GB",
109
+ "short_info": "This eSIM doesn't come with a phone number.",
110
+ "voice": null,
111
+ "text": null,
112
+ "plan_type": "data",
113
+ "activation_policy": "first-usage",
114
+ "operator": {
115
+ "title": "Meraki Mobile",
116
+ "is_roaming": true,
117
+ "info": [
118
+ "LTE Data-only eSIM.",
119
+ "Rechargeable online with no expiry.",
120
+ "Operates on the Wind network in Greece."
121
+ ]
122
+ },
123
+ "countries": [
124
+ "GR"
125
+ ],
126
+ "prices": {
127
+ "net_price": {
128
+ "AUD": 6.44,
129
+ "BRL": 23.52,
130
+ "GBP": 3.2,
131
+ "AED": 14.68,
132
+ "EUR": 3.84,
133
+ "ILS": 14.32,
134
+ "JPY": 616.67,
135
+ "MXN": 82.72,
136
+ "USD": 4.0,
137
+ "VND": 100330.0
138
+ },
139
+ "recommended_retail_price": {
140
+ "AUD": 10.07,
141
+ "BRL": 36.75,
142
+ "GBP": 5.0,
143
+ "AED": 22.93,
144
+ "EUR": 6.01,
145
+ "ILS": 22.38,
146
+ "JPY": 963.54,
147
+ "MXN": 129.25,
148
+ "USD": 6.25,
149
+ "VND": 156765.62
150
+ }
151
+ }
152
+ },
153
+ {
154
+ "package_id": "meraki-mobile-7days-1gb-topup",
155
+ "slug": "greece",
156
+ "type": "topup",
157
+ "price": 5,
158
+ "net_price": 4,
159
+ "amount": 1024,
160
+ "day": 7,
161
+ "is_unlimited": false,
162
+ "title": "1 GB - 7 Days",
163
+ "data": "1 GB",
164
+ "short_info": null,
165
+ "voice": null,
166
+ "text": null,
167
+ "plan_type": "data",
168
+ "activation_policy": "first-usage",
169
+ "operator": {
170
+ "title": "Meraki Mobile",
171
+ "is_roaming": true,
172
+ "info": [
173
+ "LTE Data-only eSIM.",
174
+ "Rechargeable online with no expiry.",
175
+ "Operates on the Wind network in Greece."
176
+ ]
177
+ },
178
+ "countries": [
179
+ "GR"
180
+ ],
181
+ "prices": {
182
+ "net_price": {
183
+ "AUD": 6.44,
184
+ "BRL": 23.52,
185
+ "GBP": 3.2,
186
+ "AED": 14.68,
187
+ "EUR": 3.84,
188
+ "ILS": 14.32,
189
+ "JPY": 616.67,
190
+ "MXN": 82.72,
191
+ "USD": 4.0,
192
+ "VND": 100330.0
193
+ },
194
+ "recommended_retail_price": {
195
+ "AUD": 10.07,
196
+ "BRL": 36.75,
197
+ "GBP": 5.0,
198
+ "AED": 22.93,
199
+ "EUR": 6.01,
200
+ "ILS": 22.38,
201
+ "JPY": 963.54,
202
+ "MXN": 129.25,
203
+ "USD": 6.25,
204
+ "VND": 156765.62
205
+ }
206
+ }
207
+ }
208
+ ]
209
+ }
210
+ ```
211
+ By default no limit is applied if `limit` is empty.
212
+ By default it auto‑paginates all pages (multiple calls) or if `page` is provided it will be the starting index.
213
+
214
+ `def get_local_packages(flat: bool = False, limit: int | None = None, page: int | None = None) -> dict | None`
215
+ Fetching local packages. Same behavior as above.
216
+
217
+ `def get_global_packages(flat: bool = False, limit: int | None = None, page: int | None = None) -> dict | None`
218
+ Fetching global packages. Same behavior as above.
219
+
220
+ `def get_country_packages(country_code: str, flat: bool = False, limit: int | None = None) -> dict | None`
221
+ Fetching country‑specific packages. Same behavior as above.
222
+
223
+ `def get_sim_packages(flat: bool = False, limit: int | None = None, page: int | None = None) -> dict | None`
224
+ Fetching SIM‑only packages without top‑ups. Same behavior as above.
225
+
226
+ <h2> Orders </h2>
227
+
228
+ `def order(package_id: str, quantity: int, description: str | None = None) -> dict | None`
229
+ Places an order for a given package id and calls the `order` endpoint.
230
+ Full response example: https://developers.partners.airalo.com/submit-order-11883024e0
231
+ ```python
232
+ order = alo.order(package_id, 1)
233
+ ```
234
+
235
+ `def order_async(package_id: str, quantity: int, webhook_url: str | None = None, description: str | None = None) -> dict | None`
236
+ Places an async order for a given package id and calls the `order-async` endpoint.
237
+ Docs: https://developers.partners.airalo.com/submit-order-async-11883025e0
238
+ ```python
239
+ order_async = alo.order_async(package_id, 1, "https://your-webhook.com")
240
+ ```
241
+
242
+ `def order_with_email_sim_share(package_id: str, quantity: int, esim_cloud: dict, description: str | None = None) -> dict | None`
243
+ Places an order and emails the end user with an eSIMs Cloud sharing link (and optional PDF). `esim_cloud` must include `to_email` and `sharing_option` of `["link"]`, `["pdf"]`, or both. Optional `copy_address` list.
244
+ ```python
245
+ order = alo.order_with_email_sim_share(
246
+ package_id, 1,
247
+ {
248
+ "to_email": "end.user.email@domain.com", # mandatory
249
+ "sharing_option": ["link", "pdf"], # mandatory
250
+ "copy_address": ["other.user.email@domain.com"] # optional
251
+ }
252
+ )
253
+ ```
254
+
255
+ `def order_bulk(packages: dict[str, int], description: str | None = None) -> dict | None`
256
+ Parameters: `packages` mapping where the key is the package id and the value is the desired quantity.
257
+ Parallel ordering for multiple packages (up to 50 different package ids) within the same call. Example:
258
+ ```python
259
+ all_packages = alo.get_all_packages(True)
260
+ first_package = all_packages["data"][0]["package_id"]
261
+ second_package = all_packages["data"][1]["package_id"]
262
+
263
+ orders = alo.order_bulk({
264
+ first_package: 2,
265
+ second_package: 1,
266
+ })
267
+ ```
268
+ Example response:
269
+ ```json
270
+ {
271
+ "change-7days-1gb": {
272
+ "data": {
273
+ "id": 77670,
274
+ "code": "20240514-077670",
275
+ "currency": "USD",
276
+ "package_id": "change-7days-1gb",
277
+ "quantity": 1,
278
+ "type": "sim",
279
+ "description": "Bulk order placed via Airalo Python SDK",
280
+ "esim_type": "Prepaid",
281
+ "validity": 7,
282
+ "package": "Change-1 GB - 7 Days",
283
+ "data": "1 GB",
284
+ "price": 4.5,
285
+ "pricing_model": "net_pricing",
286
+ "created_at": "2024-05-14 11:48:47",
287
+ "manual_installation": "<p><b>eSIM name:</b> Change</p><p><b>Coverage: </b>United States</p><p><b>To manually activate the eSIM on your eSIM capable device:</b></p><ol><li>Settings > Cellular/Mobile > Add Cellular/Mobile Plan.</li><li>Manually enter the SM-DP+ Address and activation code.</li><li>Confirm eSIM plan details.</li><li>Label the eSIM.</li></ol><p><b>To access Data:</b></p><ol><li>Enable data roaming.</li></ol>",
288
+ "qrcode_installation": "<p><b>eSIM name:</b> Change</p><p><b>Coverage: </b>United States</p><p><b>To activate the eSIM by scanning the QR code on your eSIM capable device you need to print or display this QR code on other device:</b></p><ol><li>Settings > Cellular/Mobile > Add Cellular/Mobile Plan.</li><li>Scan QR code.</li><li>Confirm eSIM plan details.</li><li>Label the eSIM.</li></ol><p><b>To access Data:</b></p><ol><li>Enable data roaming.</li></ol>",
289
+ "installation_guides": {
290
+ "en": "https://www.airalo.com/help/getting-started-with-airalo"
291
+ },
292
+ "text": null,
293
+ "voice": null,
294
+ "net_price": 3.6,
295
+ "sims": [
296
+ {
297
+ "id": 102795,
298
+ "created_at": "2024-05-14 11:48:47",
299
+ "iccid": "893000000000034143",
300
+ "lpa": "lpa.airalo.com",
301
+ "imsis": null,
302
+ "matching_id": "TEST",
303
+ "qrcode": "LPA:1$lpa.airalo.com$TEST",
304
+ "qrcode_url": "https://airalo.com/qr?expires=1802000927&id=137975&signature=b4e731d218fdc707b677c89d54d41773d250a38c160cf7d97f6e9493b5fec0ee",
305
+ "airalo_code": null,
306
+ "apn_type": "automatic",
307
+ "apn_value": null,
308
+ "is_roaming": true,
309
+ "confirmation_code": null,
310
+ "apn": {
311
+ "ios": {
312
+ "apn_type": "automatic",
313
+ "apn_value": null
314
+ },
315
+ "android": {
316
+ "apn_type": "automatic",
317
+ "apn_value": null
318
+ }
319
+ },
320
+ "msisdn": null
321
+ },
322
+ {
323
+ "id": 102795,
324
+ "created_at": "2024-05-14 11:48:47",
325
+ "iccid": "893000000000034143",
326
+ "lpa": "lpa.airalo.com",
327
+ "imsis": null,
328
+ "matching_id": "TEST",
329
+ "qrcode": "LPA:1$lpa.airalo.com$TEST",
330
+ "qrcode_url": "https://airalo.com/qr?expires=1802000927&id=137975&signature=b4e731d218fdc707b677c89d54d41773d250a38c160cf7d97f6e9493b5fec0ee",
331
+ "airalo_code": null,
332
+ "apn_type": "automatic",
333
+ "apn_value": null,
334
+ "is_roaming": true,
335
+ "confirmation_code": null,
336
+ "apn": {
337
+ "ios": {
338
+ "apn_type": "automatic",
339
+ "apn_value": null
340
+ },
341
+ "android": {
342
+ "apn_type": "automatic",
343
+ "apn_value": null
344
+ }
345
+ },
346
+ "msisdn": null
347
+ }
348
+ ]
349
+ },
350
+ "meta": {
351
+ "message": "success"
352
+ }
353
+ },
354
+ "change-7days-1gb-topup": {
355
+ "data": {
356
+ "id": 77671,
357
+ "code": "20240514-077671",
358
+ "currency": "USD",
359
+ "package_id": "change-7days-1gb-topup",
360
+ "quantity": 1,
361
+ "type": "sim",
362
+ "description": "Bulk order placed via Airalo Python SDK",
363
+ "esim_type": "Prepaid",
364
+ "validity": 7,
365
+ "package": "Change-1 GB - 7 Days",
366
+ "data": "1 GB",
367
+ "price": 4.5,
368
+ "pricing_model": "net_pricing",
369
+ "created_at": "2024-05-14 11:48:47",
370
+ "manual_installation": "<p><b>eSIM name:</b> Change</p><p><b>Coverage: </b>United States</p><p><b>To manually activate the eSIM on your eSIM capable device:</b></p><ol><li>Settings > Cellular/Mobile > Add Cellular/Mobile Plan.</li><li>Manually enter the SM-DP+ Address and activation code.</li><li>Confirm eSIM plan details.</li><li>Label the eSIM.</li></ol><p><b>To access Data:</b></p><ol><li>Enable data roaming.</li></ol>",
371
+ "qrcode_installation": "<p><b>eSIM name:</b> Change</p><p><b>Coverage: </b>United States</p><p><b>To activate the eSIM by scanning the QR code on your eSIM capable device you need to print or display this QR code on other device:</b></p><ol><li>Settings > Cellular/Mobile > Add Cellular/Mobile Plan.</li><li>Scan QR code.</li><li>Confirm eSIM plan details.</li><li>Label the eSIM.</li></ol><p><b>To access Data:</b></p><ol><li>Enable data roaming.</li></ol>",
372
+ "installation_guides": {
373
+ "en": "https://www.airalo.com/help/getting-started-with-airalo"
374
+ },
375
+ "text": null,
376
+ "voice": null,
377
+ "net_price": 3.6,
378
+ "sims": [
379
+ {
380
+ "id": 102796,
381
+ "created_at": "2024-05-14 11:48:47",
382
+ "iccid": "893000000000034144",
383
+ "lpa": "lpa.airalo.com",
384
+ "imsis": null,
385
+ "matching_id": "TEST",
386
+ "qrcode": "LPA:1$lpa.airalo.com$TEST",
387
+ "qrcode_url": "https://airalo.com/qr?expires=1802000927&id=137976&signature=978adede2174b6de7d2502841d6d901d417d643570dd6172c71733cde5f72503",
388
+ "airalo_code": null,
389
+ "apn_type": "automatic",
390
+ "apn_value": null,
391
+ "is_roaming": true,
392
+ "confirmation_code": null,
393
+ "apn": {
394
+ "ios": {
395
+ "apn_type": "automatic",
396
+ "apn_value": null
397
+ },
398
+ "android": {
399
+ "apn_type": "automatic",
400
+ "apn_value": null
401
+ }
402
+ },
403
+ "msisdn": null
404
+ }
405
+ ]
406
+ },
407
+ "meta": {
408
+ "message": "success"
409
+ }
410
+ }
411
+ }
412
+ ```
413
+ >**_NOTE:_**
414
+ >Each package id is a key in the returned response. The quantity of `sims` represents the ordered quantity.
415
+ ><b>If an error occurs in a parallel order, the error response is assigned to that package id key. Validate each item.</b>
416
+
417
+ Example error:
418
+ ```json
419
+ {
420
+ "change-7days-1gb": {"data":{"quantity":"The quantity may not be greater than 50."},"meta":{"message":"the parameter is invalid"}},
421
+ "change-7days-1gb-topup": {
422
+ "data": {
423
+ "id": 77671,
424
+ "code": "20240514-077671",
425
+ "currency": "USD",
426
+ "package_id": "change-7days-1gb-topup",
427
+ "quantity": 1,
428
+ "type": "sim",
429
+ "description": "Bulk order placed via Airalo Python SDK",
430
+ "esim_type": "Prepaid",
431
+ "validity": 7,
432
+ "package": "Change-1 GB - 7 Days",
433
+ "data": "1 GB",
434
+ "price": 4.5,
435
+ "pricing_model": "net_pricing",
436
+ "created_at": "2024-05-14 11:48:47",
437
+ "manual_installation": "<p><b>eSIM name:</b> Change</p><p><b>Coverage: </b>United States</p><p><b>To manually activate the eSIM on your eSIM capable device:</b></p><ol><li>Settings > Cellular/Mobile > Add Cellular/Mobile Plan.</li><li>Manually enter the SM-DP+ Address and activation code.</li><li>Confirm eSIM plan details.</li><li>Label the eSIM.</li></ol><p><b>To access Data:</b></p><ol><li>Enable data roaming.</li></ol>",
438
+ "qrcode_installation": "<p><b>eSIM name:</b> Change</p><p><b>Coverage: </b>United States</p><p><b>To activate the eSIM by scanning the QR code on your eSIM capable device you need to print or display this QR code on other device:</b></p><ol><li>Settings > Cellular/Mobile > Add Cellular/Mobile Plan.</li><li>Scan QR code.</li><li>Confirm eSIM plan details.</li><li>Label the eSIM.</li></ol><p><b>To access Data:</b></p><ol><li>Enable data roaming.</li></ol>",
439
+ "installation_guides": {
440
+ "en": "https://www.airalo.com/help/getting-started-with-airalo"
441
+ },
442
+ "text": null,
443
+ "voice": null,
444
+ "net_price": 3.6,
445
+ "sims": [
446
+ {
447
+ "id": 102796,
448
+ "created_at": "2024-05-14 11:48:47",
449
+ "iccid": "893000000000034144",
450
+ "lpa": "lpa.airalo.com",
451
+ "imsis": null,
452
+ "matching_id": "TEST",
453
+ "qrcode": "LPA:1$lpa.airalo.com$TEST",
454
+ "qrcode_url": "https://airalo.com/qr?expires=1802000927&id=137976&signature=978adede2174b6de7d2502841d6d901d417d643570dd6172c71733cde5f72503",
455
+ "airalo_code": null,
456
+ "apn_type": "automatic",
457
+ "apn_value": null,
458
+ "is_roaming": true,
459
+ "confirmation_code": null,
460
+ "apn": {
461
+ "ios": {
462
+ "apn_type": "automatic",
463
+ "apn_value": null
464
+ },
465
+ "android": {
466
+ "apn_type": "automatic",
467
+ "apn_value": null
468
+ }
469
+ },
470
+ "msisdn": null
471
+ }
472
+ ]
473
+ },
474
+ "meta": {
475
+ "message": "success"
476
+ }
477
+ }
478
+ }
479
+ ```
480
+
481
+ `def order_async_bulk(packages: dict[str, int], webhook_url: str | None = None, description: str | None = None) -> dict | None`
482
+ Parallel async ordering for multiple packages (up to 50 different ids) within the same call.
483
+ ```python
484
+ orders = alo.order_async_bulk({ first_package: 2, second_package: 1 }, "https://your-webhook.com")
485
+ ```
486
+ Example response:
487
+ ```json
488
+ {
489
+ "change-7days-1gb": {
490
+ "data": {
491
+ "request_id": "PWhB8cr-QXPssdA2O2RRvzaeT",
492
+ "accepted_at": "2024-07-17 10:10:31"
493
+ },
494
+ "meta": {
495
+ "message": "success"
496
+ }
497
+ },
498
+ "change-30days-10gb": {
499
+ "data": {
500
+ "request_id": "nYcMsdlgtCsE_sXFAE0vdikSd",
501
+ "accepted_at": "2024-07-17 10:10:31"
502
+ },
503
+ "meta": {
504
+ "message": "success"
505
+ }
506
+ }
507
+ }
508
+ ```
509
+
510
+ `def order_bulk_with_email_sim_share(packages: dict[str, int], esim_cloud: dict, description: str | None = None) -> dict | None`
511
+ Parallel ordering for multiple packages with eSIMs Cloud email share.
512
+ ```python
513
+ orders = alo.order_bulk_with_email_sim_share(
514
+ { first_package: 2, second_package: 1 },
515
+ {
516
+ "to_email": "end.user.email@domain.com", # mandatory
517
+ "sharing_option": ["link", "pdf"], # mandatory
518
+ "copy_address": ["another.user.email@domain.com"], # optional
519
+ }
520
+ )
521
+ ```
522
+
523
+ <h2> Vouchers </h2>
524
+
525
+ `def voucher(usage_limit: int, amount: int, quantity: int, is_paid: bool | None = False, voucher_code: str | None = None) -> dict | None`
526
+ Calls the `voucher` endpoint.
527
+ ```python
528
+ vouchers = alo.voucher(40, 22, 1, False, "ABC111")
529
+ ```
530
+ Example response:
531
+ ```json
532
+ {
533
+ "data": {
534
+ "id": 8,
535
+ "code": "ABC111",
536
+ "usage_limit": 40,
537
+ "amount": 22,
538
+ "is_paid": false,
539
+ "created_at": "2024-06-10 07:23:24"
540
+ },
541
+ "meta": { "message": "success" }
542
+ }
543
+ ```
544
+
545
+ <h2> Esim Vouchers </h2>
546
+
547
+ `def esim_vouchers(vouchers: list[dict]) -> dict | None`
548
+ Calls `voucher/esim`. Full response: https://developers.partners.airalo.com/esim-voucher-11883065e0
549
+ ```python
550
+ vouchers = alo.esim_vouchers([{ "package_id": "package_slug", "quantity": 2 }])
551
+ ```
552
+ Example response:
553
+ ```json
554
+ {
555
+ "data": [
556
+ {
557
+ "package_id": "package_slug",
558
+ "codes": [
559
+ "BIXLAAAA",
560
+ "BSXLAAAA"
561
+ ]
562
+ }
563
+ ],
564
+ "meta": {
565
+ "message": "success"
566
+ }
567
+ }
568
+ ```
569
+
570
+ <h2> Topups </h2>
571
+
572
+ `def topup(package_id: str, iccid: str, description: str | None = None) -> dict | None`
573
+ Places a top‑up for a given `package_id` and `iccid`. Full response: https://developers.partners.airalo.com/submit-top-up-order-11883026e0
574
+ ```python
575
+ order = alo.order(package_id, 1)
576
+ iccid = order["data"]["sims"][0]["iccid"]
577
+ topup = alo.topup(package_id, iccid)
578
+ ```
579
+
580
+ <h2> Sim Usage </h2>
581
+
582
+ `def sim_usage(iccid: str) -> dict | None`
583
+ Calls `simUsage`. Full response: https://developers.partners.airalo.com/get-usage-data-text-voice-11883030e0
584
+ ```python
585
+ usage = alo.sim_usage(iccid)
586
+ ```
587
+
588
+ `def sim_usage_bulk(iccids: list[str]) -> dict | None`
589
+ Parallel usage calls for multiple ICCIDs.
590
+ ```python
591
+ usage = alo.sim_usage_bulk(["870000000001", "870000000002", "870000000003", "870000000004"])
592
+ ```
593
+ >**_NOTE:_**
594
+ >Each ICCID is a key in the returned response.
595
+ ><b>If an error occurs in a parallel usage call, the error response is assigned to that ICCID key.</b>
596
+
597
+ <h2> Sim Topups </h2>
598
+
599
+ `def get_sim_topups(iccid: str) -> dict | None`
600
+ Fetches available top‑ups for an `iccid`. Full response: https://developers.partners.airalo.com/get-top-up-package-list-11883031e0
601
+ ```python
602
+ available_topups = alo.get_sim_topups(iccid)
603
+ ```
604
+
605
+ <h2> Sim Package History </h2>
606
+
607
+ `def get_sim_package_history(iccid: str) -> dict | None`
608
+ Fetches package history for an `iccid`. Full response: https://developers.partners.airalo.com/get-esim-package-history-11883032e0
609
+ ```python
610
+ sim_package_history = alo.get_sim_package_history(iccid)
611
+ ```
612
+
613
+ <h2> Exchange Rates </h2>
614
+
615
+ `def get_exchange_rates(date: str | None = None, source: str | None = None, from_currency: str | None = None, to: str | None = None) -> dict | None`
616
+ Fetches exchange rates.
617
+ `date` - `YYYY-MM-DD` format. If not provided, current date is used.
618
+ `source` - keep `None`.
619
+ `from_currency` - usually `USD`.
620
+ `to` - comma‑separated list of currency codes, e.g. `"AUD,GBP,EUR"`.
621
+ ```python
622
+ exchange_rates = alo.get_exchange_rates()
623
+ ```
624
+ Example:
625
+ ```python
626
+ exchange_rates = alo.get_exchange_rates("2025-01-30", None, None, "AUD,GBP,EUR")
627
+ ```
628
+ ```json
629
+ {
630
+ "data": {
631
+ "date": "2025-01-30",
632
+ "rates": [
633
+ {
634
+ "from": "USD",
635
+ "mid": "1.6059162",
636
+ "to": "AUD"
637
+ },
638
+ {
639
+ "from": "USD",
640
+ "mid": "0.80433592",
641
+ "to": "GBP"
642
+ },
643
+ {
644
+ "from": "USD",
645
+ "mid": "0.96191527",
646
+ "to": "EUR"
647
+ }
648
+ ]
649
+ },
650
+ "meta": {
651
+ "message": "success"
652
+ }
653
+ }
654
+ ```
655
+
656
+ <h2> Sim Instructions </h2>
657
+
658
+ `def get_installation_instructions(params: dict) -> dict | None`
659
+ Provide `{"iccid": "<ICCID>", "language": "en"}`. Full response: https://developers.partners.airalo.com/get-installation-instructions-11883029e0
660
+ ```python
661
+ instructions = alo.get_installation_instructions({"iccid": "893000000000002115", "language": "en"})
662
+ ```
663
+ Example response:
664
+ ```json
665
+ {
666
+ "data": {
667
+ "instructions": {
668
+ "language": "EN",
669
+ "ios": [
670
+ {
671
+ "model": null,
672
+ "version": "15.0,14.0.,13.0,12.0",
673
+ "installation_via_qr_code": {
674
+ "steps": {
675
+ "1": "Go to Settings > Cellular/Mobile > Add Cellular/Mobile Plan.",
676
+ "2": "Scan the QR Code.",
677
+ "3": "Tap on 'Add Cellular Plan'.",
678
+ "4": "Label the eSIM.",
679
+ "5": "Choose preferred default line to call or send messages.",
680
+ "6": "Choose the preferred line to use with iMessage, FaceTime, and Apple ID.",
681
+ "7": "Choose the eSIM plan as your default line for Cellular Data and do not turn on 'Allow Cellular Data Switching' to prevent charges on your other line.",
682
+ "8": "Your eSIM has been installed successfully, please scroll down to see the settings for accessing data."
683
+ },
684
+ "qr_code_data": "5a30d830-cfa9-4353-8d76-f103351d53b6",
685
+ "qr_code_url": "https://www.conroy.biz/earum-dolor-qui-molestiae-at"
686
+ },
687
+ "installation_manual": {
688
+ "steps": {
689
+ "1": "Go to Settings > Cellular/Mobile > Add Cellular/Mobile Plan.",
690
+ "2": "Tap on 'Enter Details Manually'.",
691
+ "3": "Enter your SM-DP+ Address and Activation Code.",
692
+ "4": "Tap on 'Add Cellular Plan'.",
693
+ "5": "Label the eSIM.",
694
+ "6": "Choose preferred default line to call or send messages.",
695
+ "7": "Choose the preferred line to use with iMessage, FaceTime, and Apple ID.",
696
+ "8": "Choose the eSIM plan as your default line for Cellular Data and do not turn on 'Allow Cellular Data Switching' to prevent charges on your other line.",
697
+ "9": "Your eSIM has been installed successfully, please scroll down to see the settings for accessing data."
698
+ },
699
+ "smdp_address_and_activation_code": "6a7f7ab6-6469-461d-8b17-2ee5c0207d22"
700
+ },
701
+ "network_setup": {
702
+ "steps": {
703
+ "1": "Select your eSIM under 'Cellular Plans'.",
704
+ "2": "Ensure that 'Turn On This Line' is toggled on.",
705
+ "3": "Go to 'Network Selection' and select the supported network.",
706
+ "4": "Need help? Chat with us."
707
+ },
708
+ "apn_type": "manual",
709
+ "apn_value": "globaldata",
710
+ "is_roaming": null
711
+ }
712
+ },
713
+ {
714
+ "model": null,
715
+ "version": null,
716
+ "installation_via_qr_code": {
717
+ "steps": {
718
+ "1": "Go to Settings > Cellular/Mobile Data > Add eSIM or Set up Cellular/Mobile Service > Use QR Code on your device. ",
719
+ "2": "Scan the QR code available on the app, then tap “Continue” twice and wait for a while. Your eSIM will connect to the network, this may take a few minutes, then tap “Done”.",
720
+ "3": "Choose a label for your new eSIM plan.",
721
+ "4": "Choose “Primary” for your default line, then tap “Continue”.",
722
+ "5": "Choose “Primary” you want to use with iMessage and FaceTime for your Apple ID, then tap “Continue”.",
723
+ "6": "Choose your new eSIM plan for cellular/mobile data, then tap “Continue”."
724
+ },
725
+ "qr_code_data": "5a30d830-cfa9-4353-8d76-f103351d53b6",
726
+ "qr_code_url": "https://www.conroy.biz/earum-dolor-qui-molestiae-at"
727
+ },
728
+ "installation_manual": {
729
+ "steps": {
730
+ "1": "Go to Settings > Cellular/Mobile Data > Add eSIM or Set up Cellular/Mobile Service > Use QR Code on your device.",
731
+ "2": "Tap “Enter Details Manually” and enter the SM-DP+ Address and Activation Code available on the app by copying them, tap “Next”, then tap “Continue” twice and wait for a while. Your eSIM will connect to the network, this may take a few minutes, then tap “Done”.",
732
+ "3": "Choose a label for your new eSIM plan.",
733
+ "4": "Choose “Primary” for your default line, then tap “Continue”.",
734
+ "5": "Choose “Primary” you want to use with iMessage and FaceTime for your Apple ID, then tap “Continue”.",
735
+ "6": "Choose your new eSIM plan for cellular/mobile data, then tap “Continue”."
736
+ },
737
+ "smdp_address_and_activation_code": "6a7f7ab6-6469-461d-8b17-2ee5c0207d22"
738
+ },
739
+ "network_setup": {
740
+ "steps": {
741
+ "1": "Go to “Cellular/Mobile Data”, then select the recently downloaded eSIM on your device. Enable the “Turn On This Line” toggle, then select your new eSIM plan for cellular/mobile data. ",
742
+ "2": "Tap “Network Selection”, disable the “Automatic” toggle, then select the supported network available on the app manually if your eSIM has connected to the wrong network."
743
+ },
744
+ "apn_type": "manual",
745
+ "apn_value": "globaldata",
746
+ "is_roaming": null
747
+ }
748
+ }
749
+ ],
750
+ "android": [
751
+ {
752
+ "model": null,
753
+ "version": null,
754
+ "installation_via_qr_code": {
755
+ "steps": {
756
+ "1": "Go to Settings > Connections > SIM Card Manager.",
757
+ "2": "Tap on 'Add Mobile Plan'.",
758
+ "3": "Tap on 'Scan Carrier QR Code' and tap on 'Add'.",
759
+ "4": "When the plan has been registered, tap 'Ok' to turn on a new mobile plan.",
760
+ "5": "Your eSIM has been installed successfully, please scroll down to see the settings for accessing data."
761
+ },
762
+ "qr_code_data": "5a30d830-cfa9-4353-8d76-f103351d53b6",
763
+ "qr_code_url": "https://www.conroy.biz/earum-dolor-qui-molestiae-at"
764
+ },
765
+ "installation_manual": {
766
+ "steps": {
767
+ "1": "Go to Settings > Connections > SIM Card Manager.",
768
+ "2": "Tap on 'Add Mobile Plan'.",
769
+ "3": "Tap on 'Scan Carrier QR Code' and tap on 'Enter code instead'.",
770
+ "4": "Enter the Activation Code (SM-DP+ Address & Activation Code).",
771
+ "5": "When the plan has been registered, tap 'Ok' to turn on a new mobile plan.",
772
+ "6": "Your eSIM has been installed successfully, please scroll down to see the settings for accessing data."
773
+ },
774
+ "smdp_address_and_activation_code": "6a7f7ab6-6469-461d-8b17-2ee5c0207d22"
775
+ },
776
+ "network_setup": {
777
+ "steps": {
778
+ "1": "In the 'SIM Card Manager' select your eSIM.",
779
+ "2": "Ensure that your eSIM is turned on under 'Mobile Networks'.",
780
+ "3": "Enable the Mobile Data.",
781
+ "4": "Go to Settings > Connections > Mobile networks > Network Operators.",
782
+ "5": "Ensure that the supported network is selected.",
783
+ "6": "Need help? Chat with us."
784
+ },
785
+ "apn_type": "automatic",
786
+ "apn_value": "globaldata",
787
+ "is_roaming": null
788
+ }
789
+ },
790
+ {
791
+ "model": null,
792
+ "version": null,
793
+ "installation_via_qr_code": {
794
+ "steps": {
795
+ "1": "Go to Settings > Network & internet.",
796
+ "2": "Tap on the '+' (Add) icon next to the Mobile network.",
797
+ "3": "Tap 'Next' when asked, “Don’t have a SIM card?”.",
798
+ "4": "Scan the QR Code.",
799
+ "5": "Your eSIM has been installed successfully, please scroll down to see the settings for accessing data."
800
+ },
801
+ "qr_code_data": "5a30d830-cfa9-4353-8d76-f103351d53b6",
802
+ "qr_code_url": "https://www.conroy.biz/earum-dolor-qui-molestiae-at"
803
+ },
804
+ "installation_manual": {
805
+ "steps": {
806
+ "1": "Go to Settings > Network & internet.",
807
+ "2": "Tap on the '+' (Add) icon next to the Mobile network.",
808
+ "3": "Tap on 'Next' when asked, “Don’t have a SIM card?”.",
809
+ "4": "Tap 'Enter Code Manually'. You will be asked to enter your Activation Code (SM-DP+ Adress & Activation Code).",
810
+ "5": "Your eSIM has been installed successfully, please scroll down to see the settings for accessing data."
811
+ },
812
+ "smdp_address_and_activation_code": "6a7f7ab6-6469-461d-8b17-2ee5c0207d22"
813
+ },
814
+ "network_setup": {
815
+ "steps": {
816
+ "1": "Go to Network & internet and tap on 'Mobile network'.",
817
+ "2": "Connect manually to the supported network.",
818
+ "3": "Turn on eSIM under 'Mobile network'.",
819
+ "4": "Enable the Mobile Data.",
820
+ "5": "Need help? Chat with us."
821
+ },
822
+ "apn_type": "automatic",
823
+ "apn_value": "globaldata",
824
+ "is_roaming": null
825
+ }
826
+ },
827
+ {
828
+ "model": "Galaxy",
829
+ "version": "1",
830
+ "installation_via_qr_code": {
831
+ "steps": {
832
+ "1": "Go to “Settings”, tap “Connections”, then tap “SIM card manager” on your device.",
833
+ "2": "Tap “Add mobile plan”, then tap “Scan carrier QR code”.",
834
+ "3": "Tap “Enter activation code”.",
835
+ "4": "Enter the SM-DP+ Address & Activation Code by copying it, tap “Connect”, then tap “Confirm”."
836
+ },
837
+ "qr_code_data": "5a30d830-cfa9-4353-8d76-f103351d53b6",
838
+ "qr_code_url": "https://www.conroy.biz/earum-dolor-qui-molestiae-at"
839
+ },
840
+ "installation_manual": {
841
+ "steps": {
842
+ "1": "Go to “Settings”, tap “Connections”, then tap “SIM card manager” on your device.",
843
+ "2": "Tap “Add mobile plan”, then tap “Scan carrier QR code”.",
844
+ "3": "Tap “Enter activation code”.",
845
+ "4": "Enter the SM-DP+ Address & Activation Code by copying it, tap “Connect”, then tap “Confirm”."
846
+ },
847
+ "smdp_address_and_activation_code": "6a7f7ab6-6469-461d-8b17-2ee5c0207d22"
848
+ },
849
+ "network_setup": {
850
+ "steps": {
851
+ "1": "Go to “Settings”, tap “Connections”, then tap “SIM card manager” on your device.",
852
+ "2": "Tap “Add mobile plan”, then tap “Scan carrier QR code”.",
853
+ "3": "Tap “Enter activation code”.",
854
+ "4": "Enter the SM-DP+ Address & Activation Code by copying it, tap “Connect”, then tap “Confirm”."
855
+ },
856
+ "apn_type": "automatic",
857
+ "apn_value": "globaldata",
858
+ "is_roaming": null
859
+ }
860
+ }
861
+ ]
862
+ }
863
+ },
864
+ "meta": {
865
+ "message": "success"
866
+ }
867
+ }
868
+ ```
869
+
870
+ <h2> Future Orders </h2>
871
+
872
+ `def create_future_order(package_id: str, quantity: int, due_date: str, webhook_url: str | None = None, description: str | None = None, brand_settings_name: str | None = None, to_email: str | None = None, sharing_option: list[str] | None = None, copy_address: list[str] | None = None) -> dict | None`
873
+ Places a future order via `future-orders`.
874
+ >**_NOTE:_**
875
+ >`due_date` must be in UTC and format `YYYY-MM-DD HH:MM`.
876
+ ```python
877
+ future_order = alo.create_future_order(
878
+ "package_id", 1, "2025-03-10 10:00",
879
+ "https://your-webhook.com",
880
+ "Test description from Python SDK",
881
+ None,
882
+ "end.user.email@domain.com",
883
+ ["link", "pdf"],
884
+ ["other.user.email@domain.com"]
885
+ )
886
+ ```
887
+ Example response:
888
+ ```json
889
+ {
890
+ "data": {
891
+ "request_id": "bUKdUc0sVB_nXJvlz0l8rTqYR",
892
+ "due_date": "2025-03-10 10:00",
893
+ "latest_cancellation_date": "2025-03-09 10:00"
894
+ },
895
+ "meta": { "message": "success" }
896
+ }
897
+ ```
898
+
899
+ <h2> Cancel Future Orders </h2>
900
+
901
+ `def cancel_future_order(request_ids: list[str]) -> dict | None`
902
+ Cancels future orders via `cancel-future-orders`.
903
+ ```python
904
+ cancel_future = alo.cancel_future_order(["request_id_1", "request_id_2", "request_id_3"])
905
+ ```
906
+ Example response:
907
+ ```json
908
+ { "data": {}, "meta": { "message": "Future orders cancelled successfully" } }
909
+ ```
910
+
911
+ <h2> Get Compatible Devices </h2>
912
+
913
+ `def get_compatible_devices() -> dict | None`
914
+ Calls the compatible eSIM devices endpoint.
915
+ ```python
916
+ devices = alo.get_compatible_devices()
917
+ ```
918
+ Example response:
919
+ ```json
920
+ {
921
+ "data": [
922
+ {
923
+ "os": "android",
924
+ "brand": "ABCTECH",
925
+ "name": "X20"
926
+ },
927
+ {
928
+ "os": "android",
929
+ "brand": "Asus",
930
+ "name": "ZenFone Max Pro M1 (ZB602KL) (WW) / Max Pro M1 (ZB601KL) (IN)"
931
+ },
932
+ {
933
+ "os": "android",
934
+ "brand": "Asus",
935
+ "name": "ZenFone Max Pro M1 (ZB602KL) (WW) / Max Pro M1 (ZB601KL) (IN)"
936
+ },
937
+ ...
938
+ ...
939
+ ...
940
+ ]
941
+ }
942
+ ```
943
+
944
+ # Technical notes
945
+ - Auth tokens are cached by the SDK for performance.
946
+ - Package responses are cached for a 1h period.
947
+ - The SDK raises exceptions on non‑2xx responses.
948
+ - Validate each item when using bulk or parallel calls.