-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
db9139a
commit c5e3637
Showing
13 changed files
with
935 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# Accounts synchronization | ||
|
||
1. TOC | ||
{:toc} | ||
|
||
## Preface | ||
|
||
With this endpoint you can import all accounts who wants to publish their listings on your website. As a next step you can sign a contracts with these accounts if needed, create accounts on your side, etc. | ||
|
||
## Get all accounts | ||
|
||
You can find detailed specification in [Swagger documentation](https://demo.platforms.bookingsync.com/api-docs/index.html) | ||
|
||
> This endpoint does not support pagination. | ||
> Don't forget to disable accounts and their rentals if you don't see them anymore in current list | ||
> We suggest to do synchronization of accounts every 12-24 hours. | ||
~~~ruby | ||
token = "<YOUR_TOKEN>" | ||
api_url = "<API_URL>" | ||
media_type = "application/vnd.api+json" | ||
options = { | ||
headers: { | ||
"User-Agent" => "Api client", | ||
"Accept" => media_type, | ||
"Content-Type" => media_type, | ||
"Authorization" => "Bearer #{token}" | ||
} | ||
} | ||
request = Excon.new(URI.join(api_url, "/api/ota/v1/accounts").to_s, options) | ||
response = request.request({ method: :get }) | ||
|
||
response.status | ||
|
||
already_import_accounts_ids = get_imported_accounts_ids # get an array of already imported accounts, Ex result: [1,2,3] | ||
|
||
json = JSON.parse(response.body) | ||
json["data"].each do |account| | ||
# Import accounts | ||
import_account(account["id"], account["attributes"]["name"]) | ||
end | ||
|
||
accounts_for_disabling = already_import_accounts_ids - json["data"].pluck("id") | ||
disable_accounts_and_rentals(accounts_for_disabling) # Disable accounts | ||
~~~ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# Smily Channel API Overview | ||
|
||
1. TOC | ||
{:toc} | ||
|
||
## What is Smily Channel API? | ||
|
||
Channel API allows you to sync Smily properties to your own website (aka Channel). You can choose which properties or accounts to display or not, get rentals availabilities, book rentals and collect payments. | ||
|
||
## Who is Smily Channel API for? | ||
|
||
TODO | ||
|
||
## Why would I use Smily Channel API? | ||
|
||
This API was developed to make integration with our partners easier. If you want to look at all features of our system, please refer to [BookingSync Universe API ](https://developers.bookingsync.com/). | ||
|
||
## How the Smily Channel API works? | ||
|
||
In general, there are 3 steps you have to do: | ||
|
||
1. Manage accounts that are ready to publish their listings on your website - regularly refresh the list and onboard them. | ||
2. Manage rentals of onboarded accounts - regularly refresh descriptions, prices and availabilities. | ||
3. Manage bookings. This step depends on how you want to process the payments - on your side, or on our side. | ||
|
||
|
||
The API is fully [JSONAPI 1.0 compliant](http://jsonapi.org). | ||
|
||
1. Get accounts | ||
2. approve/reject them | ||
3. sign contracts/register/oboarding/etc | ||
4. get rentals of approved accounts | ||
4.1 Get rentals info (refresh once a day) | ||
4.2 Get rentals availabilities (refresh every hour) | ||
4.3 Get rentals prices (every 12 hours) | ||
4.4 Remove unpublished rentals | ||
5. Booking creation: | ||
5.1 Create quote to confirm price and availability. | ||
5.2 Create booking with price not less than in quote response | ||
5.4 Create payment to confirm booking |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
# Booking cancelation | ||
|
||
1. TOC | ||
{:toc} | ||
|
||
## Preface | ||
|
||
Bookings could be canceled according to the rental's cancelation policy. You can get cancelation policy from rental's enpoint, usually it looks like: | ||
|
||
~~~js | ||
"cancelation-policy-items": [ | ||
{ | ||
"id": "1", | ||
"penalty-percentage": 10, | ||
"eligible-days": 2, | ||
"message-translations": { | ||
"en": "Lorem ipsum", | ||
"fr": "Lorem ipsum" | ||
} | ||
} | ||
] | ||
~~~ | ||
|
||
In this case you can cancel the booking not later than 2 days before check-in. And penalty will be 10% from the booking final price. | ||
|
||
## Booking cancelation | ||
|
||
You can find detailed specification in [Swagger documentation](https://demo.platforms.bookingsync.com/api-docs/index.html) | ||
|
||
~~~ruby | ||
token = "<YOUR_TOKEN>" | ||
api_url = "<API_URL>" | ||
media_type = "application/vnd.api+json" | ||
options = { | ||
headers: { | ||
"User-Agent" => "Api client", | ||
"Accept" => media_type, | ||
"Content-Type" => media_type, | ||
"Authorization" => "Bearer #{token}" | ||
} | ||
} | ||
|
||
request = Excon.new(URI.join(api_url, "/bookings/#{booking_id}/cancel").to_s, options) | ||
payload = { | ||
data: { | ||
attributes: { | ||
"cancelation-reason": "canceled_by_traveller_other", | ||
"cancelation-description": "health concern", | ||
"channel-cancelation-cost": "80.0", | ||
"currency": "USD" | ||
}, | ||
type: "bookings", | ||
id: booking_id | ||
} | ||
} | ||
response = request.request({ | ||
method: :patch, | ||
body: payload.to_json | ||
}) | ||
|
||
json = JSON.parse(response.body) | ||
if response.status == 200 | ||
booking_canceled_at = json["data"]["attributes"]["canceled-at"] | ||
# update new booking information | ||
else | ||
handle_errors(json) | ||
end | ||
~~~ | ||
|
||
In some cases you can get a 422 error. Response will look like this: | ||
|
||
~~~js | ||
{ | ||
"errors" => [ | ||
{ | ||
"code" => "100", | ||
"detail" => "currency - provided currency for cancelation must be the same as the one from booking", | ||
"source" => { | ||
"pointer" => "/data/attributes/currency" | ||
}, | ||
"status" => "422", | ||
"title" => "provided currency for cancelation must be the same as the one from booking" | ||
} | ||
] | ||
} | ||
~~~ |
160 changes: 160 additions & 0 deletions
160
content/guides/create-a-booking-payments-on-partner-side.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
# Create a booking and handle payment on partner's side | ||
|
||
1. TOC | ||
{:toc} | ||
|
||
## Preface | ||
|
||
There are 2 ways of handling payments: using Smily payment gateway or process payment on partner side. This document explains second option - how to handle payments on partner's side. | ||
|
||
## Create a quote | ||
|
||
Before creating a booking, you have to confirm the price and availability of rental. To do that, you have to create a quote. | ||
|
||
~~~ruby | ||
token = "<YOUR_TOKEN>" | ||
api_url = "<API_URL>" | ||
media_type = "application/vnd.api+json" | ||
options = { | ||
headers: { | ||
"User-Agent" => "Api client", | ||
"Accept" => media_type, | ||
"Content-Type" => media_type, | ||
"Authorization" => "Bearer #{token}" | ||
} | ||
} | ||
|
||
request = Excon.new(URI.join(api_url, "/api/ota/v1/quotes").to_s, options) | ||
payload = { | ||
data: { | ||
attributes: { | ||
"start-at": "2023-08-04", | ||
"end-at": "2023-08-11", | ||
"adults": 20, | ||
"children": 0, | ||
"rental-id": 428 | ||
}, | ||
type: "quotes" | ||
} | ||
} | ||
response = request.request({ | ||
method: :post, | ||
body: payload.to_json | ||
}) | ||
|
||
json = JSON.parse(response.body) | ||
if response.status == 201 | ||
price = json["data"]["attributes"]["final-price"] | ||
booking_url = json["data"]["attributes"]["booking-url"] | ||
# Now you can create booking via API or redirect user to booking_url | ||
else | ||
handle_errors(json) | ||
end | ||
~~~ | ||
|
||
## Create a booking | ||
|
||
Once you have successfully created a Quote, you can make a booking request. To do that you have to provide all information about the client, dates, rental ID and price. | ||
|
||
> Price should not be less than `final-price` you got from Quote request | ||
~~~ruby | ||
token = "<YOUR_TOKEN>" | ||
api_url = "<API_URL>" | ||
media_type = "application/vnd.api+json" | ||
options = { | ||
headers: { | ||
"User-Agent" => "Api client", | ||
"Accept" => media_type, | ||
"Content-Type" => media_type, | ||
"Authorization" => "Bearer #{token}", | ||
"Idempotency-Key" => get_order_uuid # optional but useful header, read comments below | ||
} | ||
} | ||
|
||
request = Excon.new(URI.join(api_url, "/api/ota/v1/bookings").to_s, options) | ||
payload = { | ||
data: { | ||
attributes: { | ||
"start-at": "2020-09-04T16:00:00.000Z", # "2020-09-04" works too | ||
"end-at": "2020-09-11T10:00:00.000Z", # "2020-09-11" works too | ||
"adults": 2, | ||
"children": 1, | ||
"final-price": "176.0", | ||
"currency": "EUR", | ||
"rental-id": 1, | ||
"client-first-name": "Rich", | ||
"client-last-name": "Piana", | ||
"client-email": "[email protected]", | ||
"client-phone-number": "123123123", | ||
"client-country-code": "US" | ||
}, | ||
type: "quotes" | ||
} | ||
} | ||
response = request.request({ | ||
method: :post, | ||
body: payload.to_json | ||
}) | ||
|
||
json = JSON.parse(response.body) | ||
if response.status == 201 | ||
booking_id = json["data"]["id"] | ||
# save this booking id | ||
else | ||
handle_errors(json) | ||
end | ||
~~~ | ||
|
||
TODO: confirm it | ||
If created booking has field `tentative-expires-at`, it means it could be canceled automatically if you won't create any payment. So, as a next step, we have to create payments. | ||
|
||
We recommend to always set `Idempotency-Key` header. This header allow to avoid duplicates creation. For example if you tried to create a booking and because of network connection or some other error you could not get response, you can safely retry your request and get the correct response, because for a given key, every success response will be cached for 6 hours. | ||
We recommend to generate UUID for each order and use it in `Idempotency-Key` header. | ||
|
||
## Create a payment | ||
|
||
When you handled payment for the booking, you have to notify our us about that. Otherwise booking could be canceled. | ||
|
||
~~~ruby | ||
token = "<YOUR_TOKEN>" | ||
api_url = "<API_URL>" | ||
media_type = "application/vnd.api+json" | ||
options = { | ||
headers: { | ||
"User-Agent" => "Api client", | ||
"Accept" => media_type, | ||
"Content-Type" => media_type, | ||
"Authorization" => "Bearer #{token}", | ||
"Idempotency-Key" => get_payment_uuid # optional but useful header, read comments below | ||
} | ||
} | ||
|
||
request = Excon.new(URI.join(api_url, "/api/ota/v1/payments").to_s, options) | ||
payload = { | ||
data: { | ||
attributes: { | ||
"amount": "100.0", | ||
"currency": "EUR", | ||
"paid-at": "2020-09-10T05:30:18.321Z", | ||
"kind": "credit-card", | ||
"booking-id": booking_id | ||
}, | ||
type: "payments" | ||
} | ||
} | ||
response = request.request({ | ||
method: :post, | ||
body: payload.to_json | ||
}) | ||
|
||
json = JSON.parse(response.body) | ||
if response.status == 201 | ||
booking_id = json["data"]["id"] | ||
# save this booking id | ||
else | ||
handle_errors(json) | ||
end | ||
~~~ | ||
|
||
Payments endpoint also support `Idempotency-Key` header. To ensure idempotent writes and frictionless integration, it is highly recommended to provide `Idempotency-Key` header. For a given key, every success response will be cached for 6 hours. Thanks to that, you can safely retry write operation. |
55 changes: 55 additions & 0 deletions
55
content/guides/create-a-booking-with-smily-payment-gateway.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# Create a booking and handle payments with Smily payment gateway | ||
|
||
1. TOC | ||
{:toc} | ||
|
||
## Preface | ||
|
||
There are 2 ways of handling payments: using Smily payment gateway or process payment on partner side. This document explains first option - how to handle payments with Smily payment gateway. | ||
|
||
## Create a quote | ||
|
||
Before creating a booking, you have to confirm the price and availability of rental. To do that, you have to create a quote. | ||
|
||
~~~ruby | ||
token = "<YOUR_TOKEN>" | ||
api_url = "<API_URL>" | ||
media_type = "application/vnd.api+json" | ||
options = { | ||
headers: { | ||
"User-Agent" => "Api client", | ||
"Accept" => media_type, | ||
"Content-Type" => media_type, | ||
"Authorization" => "Bearer #{token}" | ||
} | ||
} | ||
|
||
request = Excon.new(URI.join(api_url, "/api/ota/v1/quotes").to_s, options) | ||
payload = { | ||
data: { | ||
attributes: { | ||
"start-at": "2023-08-04", | ||
"end-at": "2023-08-11", | ||
"adults": 20, | ||
"children": 0, | ||
"rental-id": 428 | ||
}, | ||
type: "quotes" | ||
} | ||
} | ||
response = request.request({ | ||
method: :post, | ||
body: payload.to_json | ||
}) | ||
|
||
json = JSON.parse(response.body) | ||
if response.status == 201 | ||
price = json["data"]["attributes"]["final-price"] | ||
booking_url = json["data"]["attributes"]["booking-url"] | ||
# Now you can create booking via API or redirect user to booking_url | ||
else | ||
handle_errors(json) | ||
end | ||
~~~ | ||
|
||
If you don't have own payment gateway, you can just redirect user to `booking_url`. That's it :) |
Oops, something went wrong.