speedy-bg 0.1.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.
Files changed (148) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +3 -0
  3. data/CODE_OF_CONDUCT.md +134 -0
  4. data/CONTRIBUTING.md +67 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +150 -0
  7. data/SECURITY.md +29 -0
  8. data/docs/API.md +740 -0
  9. data/docs/RESPONSE_CONTRACTS.md +55 -0
  10. data/docs/VCR.md +161 -0
  11. data/docs/schema-notes.md +38 -0
  12. data/lib/speedy/camel_case_middleware.rb +71 -0
  13. data/lib/speedy/client.rb +100 -0
  14. data/lib/speedy/client_resources.rb +776 -0
  15. data/lib/speedy/collection.rb +58 -0
  16. data/lib/speedy/error.rb +29 -0
  17. data/lib/speedy/model.rb +92 -0
  18. data/lib/speedy/models/calculation/address_location.rb +16 -0
  19. data/lib/speedy/models/calculation/calculation_content.rb +15 -0
  20. data/lib/speedy/models/calculation/calculation_recipient.rb +15 -0
  21. data/lib/speedy/models/calculation/calculation_result.rb +19 -0
  22. data/lib/speedy/models/calculation/calculation_sender.rb +16 -0
  23. data/lib/speedy/models/calculation/calculation_service.rb +16 -0
  24. data/lib/speedy/models/clients/client.rb +21 -0
  25. data/lib/speedy/models/clients/cod_contract_info.rb +16 -0
  26. data/lib/speedy/models/clients/cod_international_annex.rb +12 -0
  27. data/lib/speedy/models/clients/contract_info.rb +16 -0
  28. data/lib/speedy/models/clients/requirement.rb +12 -0
  29. data/lib/speedy/models/clients/special_delivery_requirements.rb +12 -0
  30. data/lib/speedy/models/common/address.rb +36 -0
  31. data/lib/speedy/models/error.rb +37 -0
  32. data/lib/speedy/models/location/address_nomenclature_type.rb +12 -0
  33. data/lib/speedy/models/location/block.rb +15 -0
  34. data/lib/speedy/models/location/complex.rb +23 -0
  35. data/lib/speedy/models/location/country.rb +25 -0
  36. data/lib/speedy/models/location/find_office_response.rb +12 -0
  37. data/lib/speedy/models/location/find_site_response.rb +12 -0
  38. data/lib/speedy/models/location/get_office_response.rb +12 -0
  39. data/lib/speedy/models/location/get_site_response.rb +12 -0
  40. data/lib/speedy/models/location/office.rb +41 -0
  41. data/lib/speedy/models/location/office_result.rb +13 -0
  42. data/lib/speedy/models/location/office_working_time_schedule.rb +15 -0
  43. data/lib/speedy/models/location/point_of_interest.rb +22 -0
  44. data/lib/speedy/models/location/postcode.rb +12 -0
  45. data/lib/speedy/models/location/routing_information.rb +14 -0
  46. data/lib/speedy/models/location/site.rb +30 -0
  47. data/lib/speedy/models/location/state.rb +17 -0
  48. data/lib/speedy/models/location/street.rb +23 -0
  49. data/lib/speedy/models/location/tour.rb +14 -0
  50. data/lib/speedy/models/payments/payout.rb +20 -0
  51. data/lib/speedy/models/payments/payout_details.rb +23 -0
  52. data/lib/speedy/models/pickup/pickup_order.rb +16 -0
  53. data/lib/speedy/models/pickup/terms_response.rb +12 -0
  54. data/lib/speedy/models/print/extended_print_response.rb +13 -0
  55. data/lib/speedy/models/print/label_info.rb +19 -0
  56. data/lib/speedy/models/print/label_info_response.rb +12 -0
  57. data/lib/speedy/models/print/parcel_to_print_additional_barcode.rb +14 -0
  58. data/lib/speedy/models/print/print_response.rb +12 -0
  59. data/lib/speedy/models/response.rb +13 -0
  60. data/lib/speedy/models/services/additional_courier_service.rb +11 -0
  61. data/lib/speedy/models/services/additional_courier_services.rb +21 -0
  62. data/lib/speedy/models/services/courier_service.rb +19 -0
  63. data/lib/speedy/models/services/extended_courier_service.rb +13 -0
  64. data/lib/speedy/models/shipments/bank_account.rb +12 -0
  65. data/lib/speedy/models/shipments/barcode_information.rb +20 -0
  66. data/lib/speedy/models/shipments/cod_payment.rb +12 -0
  67. data/lib/speedy/models/shipments/content.rb +20 -0
  68. data/lib/speedy/models/shipments/create_shipment_response.rb +16 -0
  69. data/lib/speedy/models/shipments/created_shipment_parcel.rb +14 -0
  70. data/lib/speedy/models/shipments/external_carrier_parcel_number.rb +12 -0
  71. data/lib/speedy/models/shipments/goods_item.rb +16 -0
  72. data/lib/speedy/models/shipments/money_transfer_premium.rb +13 -0
  73. data/lib/speedy/models/shipments/parcel.rb +22 -0
  74. data/lib/speedy/models/shipments/payment.rb +16 -0
  75. data/lib/speedy/models/shipments/primary_shipment.rb +12 -0
  76. data/lib/speedy/models/shipments/recipient.rb +21 -0
  77. data/lib/speedy/models/shipments/return_amounts.rb +11 -0
  78. data/lib/speedy/models/shipments/secondary_shipment.rb +18 -0
  79. data/lib/speedy/models/shipments/sender.rb +21 -0
  80. data/lib/speedy/models/shipments/shipment.rb +28 -0
  81. data/lib/speedy/models/shipments/shipment_additional_services.rb +17 -0
  82. data/lib/speedy/models/shipments/shipment_address.rb +10 -0
  83. data/lib/speedy/models/shipments/shipment_cod_additional_service.rb +20 -0
  84. data/lib/speedy/models/shipments/shipment_cod_fiscal_receipt_item.rb +14 -0
  85. data/lib/speedy/models/shipments/shipment_content.rb +24 -0
  86. data/lib/speedy/models/shipments/shipment_declared_value_additional_service.rb +13 -0
  87. data/lib/speedy/models/shipments/shipment_delivery.rb +14 -0
  88. data/lib/speedy/models/shipments/shipment_discount_card_id.rb +12 -0
  89. data/lib/speedy/models/shipments/shipment_electronic_return_receipt_additional_service.rb +14 -0
  90. data/lib/speedy/models/shipments/shipment_obpd.rb +13 -0
  91. data/lib/speedy/models/shipments/shipment_parcel.rb +23 -0
  92. data/lib/speedy/models/shipments/shipment_parcel_number.rb +12 -0
  93. data/lib/speedy/models/shipments/shipment_parcel_ref.rb +13 -0
  94. data/lib/speedy/models/shipments/shipment_parcel_size.rb +13 -0
  95. data/lib/speedy/models/shipments/shipment_payment.rb +17 -0
  96. data/lib/speedy/models/shipments/shipment_phone_number.rb +12 -0
  97. data/lib/speedy/models/shipments/shipment_price.rb +23 -0
  98. data/lib/speedy/models/shipments/shipment_price_amount.rb +13 -0
  99. data/lib/speedy/models/shipments/shipment_recipient.rb +14 -0
  100. data/lib/speedy/models/shipments/shipment_return_additional_services.rb +20 -0
  101. data/lib/speedy/models/shipments/shipment_return_receipt_additional_service.rb +14 -0
  102. data/lib/speedy/models/shipments/shipment_return_voucher_additional_service.rb +14 -0
  103. data/lib/speedy/models/shipments/shipment_rod_additional_service.rb +15 -0
  104. data/lib/speedy/models/shipments/shipment_rop_additional_service.rb +12 -0
  105. data/lib/speedy/models/shipments/shipment_rop_additional_service_line.rb +12 -0
  106. data/lib/speedy/models/shipments/shipment_sender.rb +23 -0
  107. data/lib/speedy/models/shipments/shipment_service.rb +17 -0
  108. data/lib/speedy/models/shipments/shipment_swap_additional_service.rb +17 -0
  109. data/lib/speedy/models/shipments/update_shipment_response.rb +10 -0
  110. data/lib/speedy/models/tracking/bulk_tracking_data_file.rb +14 -0
  111. data/lib/speedy/models/tracking/external_carrier_parcel_number_details.rb +13 -0
  112. data/lib/speedy/models/tracking/tracked_parcel.rb +21 -0
  113. data/lib/speedy/models/tracking/tracked_parcel_operation.rb +22 -0
  114. data/lib/speedy/models/tracking/tracked_parcel_operation_additional_info.rb +17 -0
  115. data/lib/speedy/models/tracking/tracked_parcel_operation_additional_info_predict.rb +14 -0
  116. data/lib/speedy/models/tracking/tracked_parcel_operation_additional_info_recipient.rb +14 -0
  117. data/lib/speedy/models/validation/validation_response.rb +14 -0
  118. data/lib/speedy/resource_attributes.rb +87 -0
  119. data/lib/speedy/service_resource.rb +94 -0
  120. data/lib/speedy/services/calculation.rb +22 -0
  121. data/lib/speedy/services/clients.rb +40 -0
  122. data/lib/speedy/services/courier_services.rb +25 -0
  123. data/lib/speedy/services/location/block.rb +32 -0
  124. data/lib/speedy/services/location/complex.rb +39 -0
  125. data/lib/speedy/services/location/country.rb +70 -0
  126. data/lib/speedy/services/location/office.rb +50 -0
  127. data/lib/speedy/services/location/point_of_interest.rb +39 -0
  128. data/lib/speedy/services/location/postcode.rb +25 -0
  129. data/lib/speedy/services/location/site.rb +77 -0
  130. data/lib/speedy/services/location/state.rb +46 -0
  131. data/lib/speedy/services/location/street.rb +39 -0
  132. data/lib/speedy/services/location.rb +11 -0
  133. data/lib/speedy/services/payments.rb +19 -0
  134. data/lib/speedy/services/pickup.rb +38 -0
  135. data/lib/speedy/services/print.rb +58 -0
  136. data/lib/speedy/services/shipments/shipment.rb +120 -0
  137. data/lib/speedy/services/shipments.rb +11 -0
  138. data/lib/speedy/services/tracking.rb +26 -0
  139. data/lib/speedy/services/validation/address.rb +26 -0
  140. data/lib/speedy/services/validation/general.rb +37 -0
  141. data/lib/speedy/services/validation.rb +11 -0
  142. data/lib/speedy/transport_error.rb +17 -0
  143. data/lib/speedy/util.rb +67 -0
  144. data/lib/speedy/version.rb +5 -0
  145. data/lib/speedy-bg.rb +6 -0
  146. data/lib/speedy.rb +203 -0
  147. data/sig/speedy.rbs +374 -0
  148. metadata +227 -0
data/docs/API.md ADDED
@@ -0,0 +1,740 @@
1
+ # Method reference
2
+
3
+ All calls below use a configured `Speedy::Client`:
4
+
5
+ ```ruby
6
+ require "speedy"
7
+ client = Speedy::Client.instance # Configure first; see the README.
8
+ ```
9
+
10
+ Methods use snake_case keywords and readers; the client converts API camelCase.
11
+ A keyword ending in `:` is required; `: nil` is optional and usually omitted
12
+ from the outgoing payload. Signatures below expand the facade's `**args` to
13
+ show the keywords accepted by its service. `**options` and `**attributes`
14
+ forward additional endpoint fields, not arbitrary Ruby configuration.
15
+
16
+ Examples are independent illustrations, **not a script to execute in sequence**.
17
+ Replace resource IDs, dates, contacts and addresses with your account's fixtures.
18
+ Calls marked **mutation** change the selected remote environment; they are not
19
+ safe merely because their arguments are synthetic. Printing is download-only
20
+ unless `printer_name` is supplied. Account permissions may restrict any endpoint.
21
+
22
+ ## Finding a method
23
+
24
+ - [Calculation](#calculation) — `calculate_delivery`.
25
+ - [Shipments](#shipments) — `create_shipment`, `shipment_info`, `update_shipment`, `update_shipment_properties`, `cancel_shipment`, `finalize_shipment`, `add_shipment_parcel`, `secondary_shipments`, `find_parcels_by_reference`, `hand_over_to_courier`, `hand_over_to_midway_carrier`, `barcode_information`.
26
+ - [Tracking](#tracking) — `track_shipments`, `bulk_tracking_files`.
27
+ - [Services and pickup](#services-and-pickup) — `courier_services`, `destination_services`, `request_pickup`, `pickup_terms`.
28
+ - [Printing](#printing) — `print_labels`, `print_labels_pdf`, `label_info`, `print_voucher`.
29
+ - [Clients and payments](#clients-and-payments) — `own_client_id`, `get_client`, `contract_clients`, `create_contact`, `contact_by_external_id`, `contract_info`, `payouts`.
30
+ - [Locations](#locations) — `find_sites`, `get_site`, `get_state`, `find_states`, `all_states`, `all_countries`, `all_sites`, `all_streets`, `all_complexes`, `all_blocks`, `all_points_of_interest`, `all_postcodes`, `find_countries`, `get_country`, `find_streets`, `get_street`, `find_complexes`, `get_complex`, `find_blocks`, `find_points_of_interest`, `get_point_of_interest`, `find_offices`, `get_office`, `nearest_offices`.
31
+ - [Validation](#validation) — `validate_address`, `validate_phone`, `validate_post_code`, `validate_shipment`.
32
+
33
+ `calculate_delivery_fee` is an alias of `calculate_delivery`.
34
+
35
+ ## Payloads and results
36
+
37
+ Lookups provide country, site, office and service identifiers; don't guess them.
38
+ Use the [carrier payload reference](https://api.speedy.bg/api/docs/) for nested
39
+ required fields, enums, units and account-specific constraints. This reference
40
+ documents the Ruby interface; it does not promise that every payload will be
41
+ accepted by every account.
42
+
43
+ The following setup supplies the shared variables in the examples:
44
+
45
+ ```ruby
46
+ country_id = 100
47
+ site_id = 68_134
48
+ office_id = 1 # Replace with a currently available office.
49
+ state_id = 1
50
+ street_id = 1
51
+ complex_id = 1
52
+ point_of_interest_id = 1
53
+ client_id = 123 # Use own_client_id or contract_clients.
54
+ shipment_id = "EXISTING_SHIPMENT_ID"
55
+ parcel_id = "EXISTING_PARCEL_ID"
56
+ external_contact_id = "EXISTING_EXTERNAL_CONTACT_ID"
57
+ external_contact_secret = ENV.fetch("SPEEDY_EXTERNAL_CONTACT_SECRET")
58
+ pickup_date_time = "2026-10-12T10:00:00" # Replace with a permitted future date.
59
+ address = { country_id: country_id, site_id: site_id, street_name: "Витоша", street_no: "1" }
60
+ sender = { client_id: client_id }
61
+ recipient = {
62
+ private_person: true, client_name: "Synthetic Recipient",
63
+ phone1: { number: "+359888000000" }, pickup_office_id: office_id
64
+ }
65
+ shipment_attributes = {
66
+ sender: sender, recipient: recipient,
67
+ service: { service_id: 505, auto_adjust_pickup_date: true },
68
+ content: { parcels_count: 1, contents: "Artwork", total_weight: 0.1 },
69
+ payment: { courier_service_payer: "SENDER" }
70
+ }
71
+ quote_attributes = shipment_attributes.merge(service: { service_ids: [505] })
72
+ ```
73
+
74
+ Types below use `Collection<Model>` to mean an enumerable
75
+ `Speedy::Collection` containing typed model items. Models expose snake_case
76
+ readers and `to_h`. Collection errors and per-item errors must both be checked.
77
+ Raw document methods return bytes; extended printing returns base64 document
78
+ data in `data`, decoded with `result.data.unpack1("m0")`.
79
+
80
+ ### Errors
81
+
82
+ Unsuccessful HTTP responses raise `Speedy::Error`. Network failures are wrapped
83
+ under `Speedy::TransportError`, which also inherits from `Speedy::Error`:
84
+
85
+ | Exception | Meaning |
86
+ | --- | --- |
87
+ | `Speedy::ConnectionError` | Connection could not be established or was interrupted |
88
+ | `Speedy::TimeoutError` | Connection, read or write timeout |
89
+ | `Speedy::SSLError` | TLS negotiation or certificate verification failure |
90
+
91
+ Transport errors have fixed, credential-free messages, `status: nil` and
92
+ `error: nil`. Their original exception is preserved as `cause`; its message,
93
+ response details and chained `full_message` may contain private data. Don't log
94
+ them without review. Parsing, configuration and programming errors are not
95
+ converted into transport errors.
96
+
97
+ No automatic retry occurs. A timeout or interrupted connection does not establish
98
+ whether a mutation succeeded; reconcile its state before retrying.
99
+ For typed results, successful HTTP responses may still contain a carrier error:
100
+
101
+ ```ruby
102
+ begin
103
+ result = client.calculate_delivery(**quote_attributes)
104
+ if result.error?
105
+ warn "Calculation rejected"
106
+ else
107
+ result.each do |item|
108
+ next if item.error?
109
+ puts item.price.total
110
+ end
111
+ end
112
+ rescue Speedy::TimeoutError
113
+ warn "Request timed out; reconcile any mutation before retrying"
114
+ rescue Speedy::TransportError => error
115
+ warn error.message # Fixed transport summary, not error.cause or full_message.
116
+ rescue Speedy::Error => error
117
+ warn "Request failed: HTTP #{error.status.inspect}"
118
+ end
119
+ ```
120
+
121
+ Scalar ID and barcode-list methods return only those values; they do not offer
122
+ `error?`. A missing ID may be `nil`. Avoid logging raw payloads, credentials,
123
+ document bytes or unsanitized carrier error messages.
124
+
125
+ ## Calculation
126
+
127
+ ### `calculate_delivery`
128
+
129
+ `client.calculate_delivery(recipient:, service:, content:, payment:, sender: nil, **options)`
130
+
131
+ Calculate available delivery prices without creating a shipment. Returns `Collection<Calculation::CalculationResult>`.
132
+
133
+ ```ruby
134
+ client.calculate_delivery(**quote_attributes)
135
+ ```
136
+
137
+ ## Shipments
138
+
139
+ ### `create_shipment`
140
+
141
+ `client.create_shipment(service:, content:, payment:, recipient:, sender: nil, **options)`
142
+
143
+ Create a shipment; retain its identifier for subsequent reads and cleanup. **Mutation.** Returns `Shipments::CreateShipmentResponse`.
144
+
145
+ ```ruby
146
+ client.create_shipment(**shipment_attributes)
147
+ ```
148
+
149
+ ### `shipment_info`
150
+
151
+ `client.shipment_info(*shipment_ids)`
152
+
153
+ Retrieve shipment details; accepts individual IDs or an array. Returns `Collection<Shipments::Shipment>`.
154
+
155
+ ```ruby
156
+ client.shipment_info(shipment_id)
157
+ ```
158
+
159
+ ### `update_shipment`
160
+
161
+ `client.update_shipment(id:, **attributes)`
162
+
163
+ Replace/update full shipment data using fields accepted by the shipment update endpoint. **Mutation.** Returns `Shipments::UpdateShipmentResponse`.
164
+
165
+ ```ruby
166
+ client.update_shipment(id: shipment_id, **shipment_attributes)
167
+ ```
168
+
169
+ ### `update_shipment_properties`
170
+
171
+ `client.update_shipment_properties(id:, **properties)`
172
+
173
+ Update selected shipment properties; keywords are nested inside properties automatically. **Mutation.** Returns `Shipments::UpdateShipmentResponse`.
174
+
175
+ ```ruby
176
+ client.update_shipment_properties(id: shipment_id, contents: "Artwork")
177
+ ```
178
+
179
+ ### `cancel_shipment`
180
+
181
+ `client.cancel_shipment(id:, comment: nil)`
182
+
183
+ Cancel an eligible shipment; inspect success? and error before treating cleanup as complete. **Mutation.** Returns `Response`.
184
+
185
+ ```ruby
186
+ client.cancel_shipment(id: shipment_id, comment: "Synthetic test cleanup")
187
+ ```
188
+
189
+ ### `finalize_shipment`
190
+
191
+ `client.finalize_shipment(id:)`
192
+
193
+ Finalize a shipment that is awaiting parcel completion; requires applicable account permissions. **Mutation.** Returns `Shipments::CreateShipmentResponse`.
194
+
195
+ ```ruby
196
+ client.finalize_shipment(id: shipment_id)
197
+ ```
198
+
199
+ ### `add_shipment_parcel`
200
+
201
+ `client.add_shipment_parcel(shipment_id:, parcel:, declared_value_amount: nil, cod_amount: nil, cod_fiscal_receipt_items: nil)`
202
+
203
+ Add a parcel to an eligible pending shipment; standard demo accounts may lack permission. **Mutation.** Returns `Shipments::CreatedShipmentParcel`.
204
+
205
+ ```ruby
206
+ client.add_shipment_parcel(shipment_id: shipment_id, parcel: { weight: 0.1 })
207
+ ```
208
+
209
+ ### `secondary_shipments`
210
+
211
+ `client.secondary_shipments(shipment_id:, types: nil)`
212
+
213
+ List secondary shipments associated with a shipment. Returns `Collection<Shipments::SecondaryShipment>`.
214
+
215
+ ```ruby
216
+ client.secondary_shipments(shipment_id: shipment_id)
217
+ ```
218
+
219
+ ### `find_parcels_by_reference`
220
+
221
+ `client.find_parcels_by_reference(ref:, search_in_ref:, shipments_only: nil, include_returns: nil, from_date_time: nil, to_date_time: nil)`
222
+
223
+ Find barcode strings by a shipment reference; search_in_ref selects reference fields. Returns `Array<String>`.
224
+
225
+ ```ruby
226
+ client.find_parcels_by_reference(ref: "order-123", search_in_ref: 1)
227
+ ```
228
+
229
+ ### `hand_over_to_courier`
230
+
231
+ `client.hand_over_to_courier(parcels:)`
232
+
233
+ Register parcel handover to a courier; not a dry-run operation. **Mutation.** Returns `Response`.
234
+
235
+ ```ruby
236
+ client.hand_over_to_courier(parcels: [{ id: parcel_id }])
237
+ ```
238
+
239
+ ### `hand_over_to_midway_carrier`
240
+
241
+ `client.hand_over_to_midway_carrier(parcels:)`
242
+
243
+ Register parcel handover to a midway carrier. **Mutation.** Returns `Response`.
244
+
245
+ ```ruby
246
+ client.hand_over_to_midway_carrier(parcels: [{ id: parcel_id }])
247
+ ```
248
+
249
+ ### `barcode_information`
250
+
251
+ `client.barcode_information(parcel:)`
252
+
253
+ Retrieve barcode information for a parcel reference. Returns `Shipments::BarcodeInformation`.
254
+
255
+ ```ruby
256
+ client.barcode_information(parcel: { id: parcel_id })
257
+ ```
258
+
259
+ ## Tracking
260
+
261
+ ### `track_shipments`
262
+
263
+ `client.track_shipments(parcels:, last_operation_only: nil)`
264
+
265
+ Retrieve parcel tracking operations; true requests only the latest operation. Returns `Collection<Tracking::TrackedParcel>`.
266
+
267
+ ```ruby
268
+ client.track_shipments(parcels: [{ id: parcel_id }], last_operation_only: true)
269
+ ```
270
+
271
+ ### `bulk_tracking_files`
272
+
273
+ `client.bulk_tracking_files(last_processed_file_id:)`
274
+
275
+ List available tracking files after a cursor; URLs are returned, not downloaded. Returns `Collection<Tracking::BulkTrackingDataFile>`.
276
+
277
+ ```ruby
278
+ client.bulk_tracking_files(last_processed_file_id: 0)
279
+ ```
280
+
281
+ ## Services and pickup
282
+
283
+ ### `courier_services`
284
+
285
+ `client.courier_services(date: nil)`
286
+
287
+ List courier services, optionally for an ISO date. Returns `Collection<Services::CourierService>`.
288
+
289
+ ```ruby
290
+ client.courier_services
291
+ ```
292
+
293
+ ### `destination_services`
294
+
295
+ `client.destination_services(sender:, recipient:, date: nil)`
296
+
297
+ List services available for the supplied shipment parties. Returns `Collection<Services::ExtendedCourierService>`.
298
+
299
+ ```ruby
300
+ client.destination_services(sender: sender, recipient: recipient)
301
+ ```
302
+
303
+ ### `request_pickup`
304
+
305
+ `client.request_pickup(pickup_date_time:, pickup_scope: nil, explicit_shipment_id_list: nil, visit_end_time: nil, contact_name: nil, phone_number: nil, auto_adjust_pickup_date: nil)`
306
+
307
+ Request a courier visit; auto_adjust_pickup_date allows server adjustment when supported. **Mutation.** Returns `Collection<Pickup::PickupOrder>`.
308
+
309
+ ```ruby
310
+ client.request_pickup(pickup_date_time: pickup_date_time, explicit_shipment_id_list: [shipment_id])
311
+ ```
312
+
313
+ ### `pickup_terms`
314
+
315
+ `client.pickup_terms(service_id:, starting_date: nil, sender: nil, sender_has_payment: nil)`
316
+
317
+ Retrieve available pickup terms for a service and sender. Returns `Pickup::TermsResponse`.
318
+
319
+ ```ruby
320
+ client.pickup_terms(service_id: 505)
321
+ ```
322
+
323
+ ## Printing
324
+
325
+ ### `print_labels`
326
+
327
+ `client.print_labels(parcels:, format: nil, paper_size: nil, printer_name: nil, dpi: nil, additional_waybill_sender_copy: nil)`
328
+
329
+ Get extended labels with encoded document data and label metadata. **Physical printing possible when `printer_name` is provided.** Returns `Print::ExtendedPrintResponse`.
330
+
331
+ ```ruby
332
+ client.print_labels(parcels: [{ parcel: { id: parcel_id } }], format: "pdf")
333
+ ```
334
+
335
+ ### `print_labels_pdf`
336
+
337
+ `client.print_labels_pdf(parcels:, format: nil, paper_size: nil, printer_name: nil, dpi: nil, additional_waybill_sender_copy: nil)`
338
+
339
+ Get raw label document bytes; despite its name, format may request ZPL. **Physical printing possible when `printer_name` is provided.** Returns `String`.
340
+
341
+ ```ruby
342
+ client.print_labels_pdf(parcels: [{ parcel: { id: parcel_id } }], format: "pdf")
343
+ ```
344
+
345
+ ### `label_info`
346
+
347
+ `client.label_info(parcel: nil, parcels: nil)`
348
+
349
+ Retrieve label metadata. Returns `Print::LabelInfoResponse`.
350
+ Prefer `parcels:` with an array; it takes precedence over `parcel:`.
351
+ The `parcel:` shorthand accepts a single reference hash or an array of references.
352
+
353
+ ```ruby
354
+ client.label_info(parcels: [{ id: parcel_id }])
355
+ ```
356
+
357
+ ### `print_voucher`
358
+
359
+ `client.print_voucher(shipment_ids:, printer_name: nil, format: nil, dpi: nil)`
360
+
361
+ Get raw voucher PDF/ZPL bytes for shipment IDs. **Physical printing possible when `printer_name` is provided.** Returns `String`.
362
+
363
+ ```ruby
364
+ client.print_voucher(shipment_ids: [shipment_id], format: "pdf")
365
+ ```
366
+
367
+ ## Clients and payments
368
+
369
+ ### `own_client_id`
370
+
371
+ `client.own_client_id`
372
+
373
+ Retrieve the authenticated client identifier. Returns `Integer, nil`.
374
+
375
+ ```ruby
376
+ client.own_client_id
377
+ ```
378
+
379
+ ### `get_client`
380
+
381
+ `client.get_client(id)`
382
+
383
+ Retrieve a client by identifier. Returns `Clients::Client`.
384
+
385
+ ```ruby
386
+ client.get_client(client_id)
387
+ ```
388
+
389
+ ### `contract_clients`
390
+
391
+ `client.contract_clients`
392
+
393
+ List clients available under the authenticated contract. Returns `Collection<Clients::Client>`.
394
+
395
+ ```ruby
396
+ client.contract_clients
397
+ ```
398
+
399
+ ### `create_contact`
400
+
401
+ `client.create_contact(**attributes)`
402
+
403
+ Create a contact; forwards compacted contact attributes accepted by the API. **Mutation.** Returns `Integer, nil`.
404
+
405
+ ```ruby
406
+ client.create_contact(client_name: "Synthetic Contact", private_person: true, phone1: { number: "+359888000000" }, address: address)
407
+ ```
408
+
409
+ ### `contact_by_external_id`
410
+
411
+ `client.contact_by_external_id(id:, secret_key:)`
412
+
413
+ Retrieve a contact using its external ID and secret; do not log the secret. Returns `Clients::Client`.
414
+
415
+ ```ruby
416
+ client.contact_by_external_id(id: external_contact_id, secret_key: external_contact_secret)
417
+ ```
418
+
419
+ ### `contract_info`
420
+
421
+ `client.contract_info`
422
+
423
+ Retrieve contract information for the authenticated account. Returns `Clients::ContractInfo`.
424
+
425
+ ```ruby
426
+ client.contract_info
427
+ ```
428
+
429
+ ### `payouts`
430
+
431
+ `client.payouts(from_date:, to_date:, include_details: nil)`
432
+
433
+ Retrieve payouts within an ISO-date interval; dates are cast to Ruby Date values where supported. Returns `Collection<Payments::Payout>`.
434
+
435
+ ```ruby
436
+ client.payouts(from_date: "2026-10-01", to_date: "2026-10-10", include_details: true)
437
+ ```
438
+
439
+ ## Locations
440
+
441
+ ### `find_sites`
442
+
443
+ `client.find_sites(country_id: nil, name: nil, post_code: nil, type: nil, municipality: nil, region: nil)`
444
+
445
+ Search cities/localities with optional filters. Returns `Collection<Location::Site>`.
446
+
447
+ ```ruby
448
+ client.find_sites(country_id: 100, name: "София")
449
+ ```
450
+
451
+ ### `get_site`
452
+
453
+ `client.get_site(id)`
454
+
455
+ Get a site response envelope; the site is available through result.site. Returns `Location::GetSiteResponse`.
456
+
457
+ ```ruby
458
+ client.get_site(site_id)
459
+ ```
460
+
461
+ ### `get_state`
462
+
463
+ `client.get_state(id)`
464
+
465
+ Retrieve a state by its identifier. Returns `Location::State`.
466
+
467
+ ```ruby
468
+ client.get_state(state_id)
469
+ ```
470
+
471
+ ### `find_states`
472
+
473
+ `client.find_states(country_id: nil, name: nil)`
474
+
475
+ Search states with optional country and name filters. Returns `Collection<Location::State>`.
476
+
477
+ ```ruby
478
+ client.find_states(country_id: country_id)
479
+ ```
480
+
481
+ ### `all_states`
482
+
483
+ `client.all_states(country_id:)`
484
+
485
+ Download and parse the state CSV dataset for a country. Returns `Collection<Location::State>`.
486
+
487
+ ```ruby
488
+ client.all_states(country_id: country_id)
489
+ ```
490
+
491
+ ### `all_countries`
492
+
493
+ `client.all_countries`
494
+
495
+ Download and parse the country CSV dataset. Returns `Collection<Location::Country>`.
496
+
497
+ ```ruby
498
+ client.all_countries
499
+ ```
500
+
501
+ ### `all_sites`
502
+
503
+ `client.all_sites(country_id:)`
504
+
505
+ Download and parse the sites CSV dataset for a country. Returns `Collection<Location::Site>`.
506
+
507
+ ```ruby
508
+ client.all_sites(country_id: 100)
509
+ ```
510
+
511
+ ### `all_streets`
512
+
513
+ `client.all_streets(country_id:)`
514
+
515
+ Download and parse the streets CSV dataset for a country. Returns `Collection<Location::Street>`.
516
+
517
+ ```ruby
518
+ client.all_streets(country_id: 100)
519
+ ```
520
+
521
+ ### `all_complexes`
522
+
523
+ `client.all_complexes(country_id:)`
524
+
525
+ Download and parse the complexes CSV dataset for a country. Returns `Collection<Location::Complex>`.
526
+
527
+ ```ruby
528
+ client.all_complexes(country_id: 100)
529
+ ```
530
+
531
+ ### `all_blocks`
532
+
533
+ `client.all_blocks(country_id:)`
534
+
535
+ Download and parse the blocks CSV dataset for a country. Returns `Collection<Location::Block>`.
536
+
537
+ ```ruby
538
+ client.all_blocks(country_id: 100)
539
+ ```
540
+
541
+ ### `all_points_of_interest`
542
+
543
+ `client.all_points_of_interest(country_id:)`
544
+
545
+ Download and parse the points of interest CSV dataset for a country. Returns `Collection<Location::PointOfInterest>`.
546
+
547
+ ```ruby
548
+ client.all_points_of_interest(country_id: 100)
549
+ ```
550
+
551
+ ### `all_postcodes`
552
+
553
+ `client.all_postcodes(country_id:)`
554
+
555
+ Download and parse the postcodes CSV dataset for a country. Returns `Collection<Location::Postcode>`.
556
+
557
+ ```ruby
558
+ client.all_postcodes(country_id: 100)
559
+ ```
560
+
561
+ ### `find_countries`
562
+
563
+ `client.find_countries(name: nil, iso_alpha2: nil, iso_alpha3: nil)`
564
+
565
+ Search countries by name or ISO code. Returns `Collection<Location::Country>`.
566
+
567
+ ```ruby
568
+ client.find_countries(iso_alpha2: "BG")
569
+ ```
570
+
571
+ ### `get_country`
572
+
573
+ `client.get_country(id)`
574
+
575
+ Retrieve a country by identifier. Returns `Location::Country`.
576
+
577
+ ```ruby
578
+ client.get_country(100)
579
+ ```
580
+
581
+ ### `find_streets`
582
+
583
+ `client.find_streets(site_id:, name: nil, type: nil)`
584
+
585
+ Search streets within a site. Returns `Collection<Location::Street>`.
586
+
587
+ ```ruby
588
+ client.find_streets(site_id: site_id, name: "Витоша")
589
+ ```
590
+
591
+ ### `get_street`
592
+
593
+ `client.get_street(id)`
594
+
595
+ Retrieve a street by identifier. Returns `Location::Street`.
596
+
597
+ ```ruby
598
+ client.get_street(street_id)
599
+ ```
600
+
601
+ ### `find_complexes`
602
+
603
+ `client.find_complexes(site_id:, name: nil, type: nil)`
604
+
605
+ Search complexes within a site. Returns `Collection<Location::Complex>`.
606
+
607
+ ```ruby
608
+ client.find_complexes(site_id: site_id, name: "Витоша")
609
+ ```
610
+
611
+ ### `get_complex`
612
+
613
+ `client.get_complex(id)`
614
+
615
+ Retrieve a complex by identifier. Returns `Location::Complex`.
616
+
617
+ ```ruby
618
+ client.get_complex(complex_id)
619
+ ```
620
+
621
+ ### `find_blocks`
622
+
623
+ `client.find_blocks(site_id:, name: nil)`
624
+
625
+ Search block/building numbers within a site. Returns `Collection<Location::Block>`.
626
+
627
+ ```ruby
628
+ client.find_blocks(site_id: site_id, name: "1")
629
+ ```
630
+
631
+ ### `find_points_of_interest`
632
+
633
+ `client.find_points_of_interest(site_id:, name: nil)`
634
+
635
+ Search points of interest within a site. Returns `Collection<Location::PointOfInterest>`.
636
+
637
+ ```ruby
638
+ client.find_points_of_interest(site_id: site_id)
639
+ ```
640
+
641
+ ### `get_point_of_interest`
642
+
643
+ `client.get_point_of_interest(id)`
644
+
645
+ Retrieve a point of interest by identifier. Returns `Location::PointOfInterest`.
646
+
647
+ ```ruby
648
+ client.get_point_of_interest(point_of_interest_id)
649
+ ```
650
+
651
+ ### `find_offices`
652
+
653
+ `client.find_offices(country_id: nil, site_id: nil, site_name: nil, name: nil, limit: nil)`
654
+
655
+ Search offices and lockers with optional locality/name filters. Returns `Collection<Location::Office>`.
656
+
657
+ ```ruby
658
+ client.find_offices(site_id: site_id, limit: 10)
659
+ ```
660
+
661
+ ### `get_office`
662
+
663
+ `client.get_office(id)`
664
+
665
+ Retrieve an office response envelope; the office is available through result.office. Returns `Location::GetOfficeResponse`.
666
+
667
+ ```ruby
668
+ client.get_office(office_id)
669
+ ```
670
+
671
+ ### `nearest_offices`
672
+
673
+ `client.nearest_offices(address:, distance: nil, limit: nil, office_type: nil, office_features: nil)`
674
+
675
+ Find offices near an address; items contain office and distance metadata. Returns `Collection<Location::OfficeResult>`.
676
+
677
+ ```ruby
678
+ client.nearest_offices(address: address, limit: 5)
679
+ ```
680
+
681
+ ## Validation
682
+
683
+ ### `validate_address`
684
+
685
+ `client.validate_address(address)`
686
+
687
+ Validate a shipment address supplied as a hash or ShipmentAddress model. Returns `Validation::ValidationResponse`.
688
+
689
+ ```ruby
690
+ client.validate_address(address)
691
+ ```
692
+
693
+ ### `validate_phone`
694
+
695
+ `client.validate_phone(number:, extension: nil)`
696
+
697
+ Validate a phone number, optionally including an extension. Returns `Validation::ValidationResponse`.
698
+
699
+ ```ruby
700
+ client.validate_phone(number: "+359888000000")
701
+ ```
702
+
703
+ ### `validate_post_code`
704
+
705
+ `client.validate_post_code(country_id:, post_code:, site_id: nil)`
706
+
707
+ Validate a postcode against a country and optional site. Returns `Validation::ValidationResponse`.
708
+
709
+ ```ruby
710
+ client.validate_post_code(country_id: 100, post_code: "1000")
711
+ ```
712
+
713
+ ### `validate_shipment`
714
+
715
+ `client.validate_shipment(service:, content:, payment:, recipient:, sender: nil, **options)`
716
+
717
+ Validate shipment attributes without creating a shipment. Returns `Validation::ValidationResponse`.
718
+
719
+ ```ruby
720
+ client.validate_shipment(**shipment_attributes)
721
+ ```
722
+
723
+ ## Generated documentation
724
+
725
+ The source documents every endpoint shortcut with YARD signatures, parameter
726
+ notes, result types and examples. From a repository checkout, generate browsable
727
+ HTML without making API requests:
728
+
729
+ ```bash
730
+ bundle exec rake yard
731
+ ```
732
+
733
+ Open `doc/index.html`; generated `doc/` and `.yardoc` are ignored.
734
+ The Markdown reference is committed and packaged with the gem. A GitHub wiki is
735
+ not required. A hosted documentation site can be added separately without
736
+ changing where the source documentation lives.
737
+
738
+ For offline/live verification and mutation cleanup limits, see
739
+ [VCR policy](VCR.md). For response-shape exceptions, see
740
+ [response contracts](RESPONSE_CONTRACTS.md) and [schema notes](schema-notes.md).