API Workflow
The diagram below illustrates the two main phases: Catalog Management (browsing categories and offers) and the Checkout Process (availability, booking, confirmation).
1. Setup your Test environment
1.1. Authentication
- Authentication uses simple HMAC based principles.
- For test queries, please use your PUBLIC key. You can find your key in your Regiondo Dashboard, under Connectivity > API configuration > Generate keys
1.2. Sandbox vs. Live Environment
- Offers created in your Regiondo Live Account will not appear in the Sandbox Environment and cannot be retrieved through the Public key.
- To test your API implementation, you will need a Regiondo account in the Sandbox Environment and publish your offers on regiondo-dev-de.de
2. Documentation
- Code examples are available on GitHub: https://github.com/regiondo-dev/api
- When using a Request URL, remove the
sandbox-prefix and ensure there are no extra spaces at the end of the URL.
3. Authentication setup
To connect to the Regiondo API, you need to follow a few critical steps to ensure secure and accurate data transmission. This guide will take you through the process and point out common issues that could lead to a 401 Unauthorized error. Follow these instructions carefully to avoid common problems.
3.1. Headers
Each request must include the following headers:
X-API-HASH: {{regiondoHmacAuthHeader}}
X-API-TIME: {{regiondoReqTime}}
X-API-ID: XXXXXXX3.2. Pre-request Script
This script generates the required timestamp and HMAC from your public and secret keys:
function getQueryString(url) {
var arrSplit = url.split('?');
return arrSplit.length 1 ? url.substring(url.indexOf('?') + 1) : '';
}
function getAuthHeader(requestUrl) {
var PUBLIC_KEY = 'XXXXXXX';
var SECRET_KEY = 'XXXXXXX';
var queryString = getQueryString(requestUrl);
var timestamp = Date.now();
pm.environment.set("regiondoReqTime", timestamp);
var requestData = timestamp + PUBLIC_KEY + queryString;
console.log("Message to be hashed with private key: " + requestData);
var hmacDigest = CryptoJS.enc.Hex.stringify(CryptoJS.HmacSHA256(requestData, SECRET_KEY));
var authHeader = hmacDigest;
return authHeader;
}
var hmac = getAuthHeader(request['url']);
console.log("HmacSHA256-Hash: " + hmac);
postman.setEnvironmentVariable('regiondoHmacAuthHeader', hmac);4. Common Issues Leading to 401 Unauthorized Errors
4.1. Bad integration of header
Ensure that your headers are correctly integrated into your requests. Double-check that the header names and values match the example provided. Any discrepancy in header names or values can result in authentication failure.
4.2. Issues with secure key integration
Make sure the secure key (SECRET_KEY) is correctly implemented in your pre-request script. Any mistake in the secure key will lead to a failed authentication process. Ensure that the script is properly copying the secure key and generating the HMAC digest.
4.3. Incorrect date format
The date format in your requests must follow the correct encoding. Instead of using commas (,), you should URL-encode them as %2C. For example, dates should be formatted as:
2024-06-01%2C2024-07-01
5. Connection scripts examples
The following examples show how to connect to the Regiondo API in different programming languages. Replace all placeholder values (e.g., XXXXXXX) with your actual credentials and a valid endpoint URL.
cURL
PUBLIC_KEY="XXXXXXX"
SECRET_KEY="XXXXXXX"
API_URL="https://api.regiondo.com/v1/..."
get_query_string() {
local url=$1
echo "${url#*\?}"
}
get_auth_header() {
local url=$1
local query_string=$(get_query_string "$url")
local timestamp=$(($(date +%s%N)/1000000))
local request_data="${timestamp}${PUBLIC_KEY}${query_string}"
local hmac_digest=$(echo -n "$request_data" | openssl dgst -sha256 -hmac "$SECRET_KEY" | sed 's/^.* //')
echo "$timestamp" "$hmac_digest"
}
read timestamp hmac <><(get_auth_header>
curl -X GET "$API_URL" \
-H "X-API-HASH: $hmac" \
-H "X-API-TIME: $timestamp" \
-H "X-API-ID: $PUBLIC_KEY"
PHP
define('PUBLIC_KEY', 'XXXXXXX');
define('SECRET_KEY', 'XXXXXXX');
define('API_URL', 'https://api.regiondo.com/v1/...');
function getQueryString($url) {
$parts = parse_url($url);
return isset($parts['query']) ? $parts['query'] : '';
}
function getAuthHeader($url) {
$queryString = getQueryString($url);
$timestamp = time() * 1000;
$requestData = $timestamp . PUBLIC_KEY . $queryString;
$hmacDigest = hash_hmac('sha256', $requestData, SECRET_KEY);
return [
'timestamp' = $timestamp,
'hmac' = $hmacDigest
];
}
$url = API_URL;
$authData = getAuthHeader($url);
$headers = [
'X-API-HASH: ' . $authData['hmac'],
'X-API-TIME: ' . $authData['timestamp'],
'X-API-ID: ' . PUBLIC_KEY
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($ch);
if (curl_errno($ch)) {
echo 'Error:' . curl_error($ch);
} else {
echo 'Response:' . $response;
}
curl_close($ch);
?
PHP (using AJAX)
define('PUBLIC_KEY', 'XXXXXXX');
define('SECRET_KEY', 'XXXXXXX');
function getQueryString($url) {
$parts = parse_url($url);
return isset($parts['query']) ? $parts['query'] : '';
}
function getAuthHeader($url) {
$queryString = getQueryString($url);
$timestamp = time() * 1000;
$requestData = $timestamp . PUBLIC_KEY . $queryString;
$hmacDigest = hash_hmac('sha256', $requestData, SECRET_KEY);
return [
'timestamp' = $timestamp,
'hmac' = $hmacDigest
];
}
$url = 'https://api.regiondo.com/v1/...';
$authData = getAuthHeader($url);
?
JavaScript/Node.ja
const crypto = require('crypto');
const axios = require('axios');
const PUBLIC_KEY = 'XXXXXXX';
const SECRET_KEY = 'XXXXXXX';
const API_URL = 'https://api.regiondo.com/v1/...';
function getQueryString(url) {
const urlObj = new URL(url);
return urlObj.search;
}
function getAuthHeader(url) {
const queryString = getQueryString(url);
const timestamp = Date.now();
const requestData = `${timestamp}${PUBLIC_KEY}${queryString}`;
const hmacDigest = crypto.createHmac('sha256', SECRET_KEY)
.update(requestData)
.digest('hex');
return {
timestamp: timestamp,
hmac: hmacDigest
};
}
const { timestamp, hmac } = getAuthHeader(API_URL);
axios.get(API_URL, {
headers: {
'X-API-HASH': hmac,
'X-API-TIME': timestamp,
'X-API-ID': PUBLIC_KEY
}
})
.then(response = console.log(response.data))
.catch(error = console.error('Error:', error));
Python
import time
import hmac
import hashlib
import requests
PUBLIC_KEY = 'XXXXXXX'
SECRET_KEY = 'XXXXXXX'
API_URL = 'https://api.regiondo.com/v1/...'
def get_query_string(url):
return url.split('?', 1)[1] if '?' in url else ''
def get_auth_header(url):
query_string = get_query_string(url)
timestamp = int(time.time() * 1000)
request_data = f"{timestamp}{PUBLIC_KEY}{query_string}"
hmac_digest = hmac.new(SECRET_KEY.encode(), request_data.encode(), hashlib.sha256).hexdigest()
return {
'timestamp': timestamp,
'hmac': hmac_digest
}
auth_data = get_auth_header(API_URL)
headers = {
'X-API-HASH': auth_data['hmac'],
'X-API-TIME': str(auth_data['timestamp']),
'X-API-ID': PUBLIC_KEY
}
response = requests.get(API_URL, headers=headers)
print(response.text)Ruby
require 'uri'
require 'net/http'
require 'openssl'
require 'time'
PUBLIC_KEY = 'XXXXXXX'
SECRET_KEY = 'XXXXXXX'
API_URL = 'https://api.regiondo.com/v1/...'
def get_query_string(url)
uri = URI(url)
uri.query
end
def get_auth_header(url)
query_string = get_query_string(url) || ''
timestamp = (Time.now.to_f * 1000).to_i
request_data = "#{timestamp}#{PUBLIC_KEY}#{query_string}"
hmac_digest = OpenSSL::HMAC.hexdigest('sha256', SECRET_KEY, request_data)
{ timestamp: timestamp, hmac: hmac_digest }
end
auth_data = get_auth_header(API_URL)
uri = URI(API_URL)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri)
request['X-API-HASH'] = auth_data[:hmac]
request['X-API-TIME'] = auth_data[:timestamp].to_s
request['X-API-ID'] = PUBLIC_KEY
response = http.request(request)
puts response.bodyC#
using System;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
class Program
{
const string PUBLIC_KEY = "XXXXXXX";
const string SECRET_KEY = "XXXXXXX";
const string API_URL = "https://api.regiondo.com/v1/...";
static string GetQueryString(string url)
{
var uri = new Uri(url);
return uri.Query;
}
static (long timestamp, string hmac) GetAuthHeader(string url)
{
var queryString = GetQueryString(url);
var timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
var requestData = $"{timestamp}{PUBLIC_KEY}{queryString}";
using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(SECRET_KEY)))
{
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(requestData));
var hmacDigest = BitConverter.ToString(hash).Replace("-", "").ToLower();
return (timestamp, hmacDigest);
}
}
static async Task Main(string[] args)
{
var (timestamp, hmac) = GetAuthHeader(API_URL);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("X-API-HASH", hmac);
client.DefaultRequestHeaders.Add("X-API-TIME", timestamp.ToString());
client.DefaultRequestHeaders.Add("X-API-ID", PUBLIC_KEY);
var response = await client.GetAsync(API_URL);
var responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseBody);
}
}
}Java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
public class Main {
private static final String PUBLIC_KEY = "XXXXXXX";
private static final String SECRET_KEY = "XXXXXXX";
private static final String API_URL = "https://api.regiondo.com/v1/...";
private static String getQueryString(String url) throws Exception {
URL uri = new URL(url);
return uri.getQuery();
}
private static String getAuthHeader(String url) throws Exception {
String queryString = getQueryString(url);
long timestamp = System.currentTimeMillis();
String requestData = timestamp + PUBLIC_KEY + (queryString != null ? queryString : "");
Mac sha256Hmac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
sha256Hmac.init(secretKey);
byte[] hashBytes = sha256Hmac.doFinal(requestData.getBytes(StandardCharsets.UTF_8));
StringBuilder hash = new StringBuilder();
for (byte b : hashBytes) {
hash.append(String.format("%02x", b));
}
return String.format("%d|%s", timestamp, hash.toString());
}
public static void main(String[] args) throws Exception {
String[] authData = getAuthHeader(API_URL).split("\\|");
long timestamp = Long.parseLong(authData[0]);
String hmac = authData[1];
URL url = new URL(API_URL);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("X-API-HASH", hmac);
conn.setRequestProperty("X-API-TIME", Long.toString(timestamp));
conn.setRequestProperty("X-API-ID", PUBLIC_KEY);
int responseCode = conn.getResponseCode();
System.out.println("Response Code: " + responseCode);
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println(response.toString());
}
}Go
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"net/http"
"net/url"
"time"
)
const (
PublicKey = "XXXXXXX"
SecretKey = "XXXXXXX"
ApiURL = "https://api.regiondo.com/v1/..."
)
func getQueryString(rawUrl string) string {
parsedUrl, _ := url.Parse(rawUrl)
return parsedUrl.RawQuery
}
func getAuthHeader(requestUrl string) (string, string) {
queryString := getQueryString(requestUrl)
timestamp := time.Now().UnixNano() / int64(time.Millisecond)
requestData := fmt.Sprintf("%d%s%s", timestamp, PublicKey, queryString)
h := hmac.New(sha256.New, []byte(SecretKey))
h.Write([]byte(requestData))
hmacDigest := hex.EncodeToString(h.Sum(nil))
return fmt.Sprintf("%d", timestamp), hmacDigest
}
func main() {
timestamp, hmacDigest := getAuthHeader(ApiURL)
client := &http.Client{}
req, _ := http.NewRequest("GET", ApiURL, nil)
req.Header.Add("X-API-HASH", hmacDigest)
req.Header.Add("X-API-TIME", timestamp)
req.Header.Add("X-API-ID", PublicKey)
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error:", err)
return
}
defer resp.Body.Close()
fmt.Println("Response Status:", resp.Status)
}Swift
import Foundation
import CommonCrypto
let publicKey = "XXXXXXX"
let secretKey = "XXXXXXX"
let apiUrl = "https://api.regiondo.com/v1/..."
func getQueryString(from url: String) - String {
if let components = URLComponents(string: url) {
return components.query ?? ""
}
return ""
}
func getAuthHeader(for url: String) - (timestamp: String, hmac: String) {
let queryString = getQueryString(from: url)
let timestamp = String(Int(Date().timeIntervalSince1970 * 1000))
let requestData = timestamp + publicKey + queryString
let key = secretKey.data(using: .utf8)!
let data = requestData.data(using: .utf8)!
var hmacData = Data(count: Int(CC_SHA256_DIGEST_LENGTH))
_ = hmacData.withUnsafeMutableBytes { hmacBytes in
data.withUnsafeBytes { dataBytes in
key.withUnsafeBytes { keyBytes in
CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA256), keyBytes, key.count, dataBytes, data.count, hmacBytes)
}
}
}
let hmac = hmacData.map { String(format: "%02hhx", $0) }.joined()
return (timestamp, hmac)
}
let authHeader = getAuthHeader(for: apiUrl)
var request = URLRequest(url: URL(string: apiUrl)!)
request.addValue(authHeader.hmac, forHTTPHeaderField: "X-API-HASH")
request.addValue(authHeader.timestamp, forHTTPHeaderField: "X-API-TIME")
request.addValue(publicKey, forHTTPHeaderField: "X-API-ID")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
print("Error:", error)
return
}
if let data = data {
print("Response Data:", String(data: data, encoding: .utf8)!)
}
}
task.resume()
Dart/Flutter
import 'dart:convert';
import 'dart:io';
import 'package:crypto/crypto.dart';
const String publicKey = 'XXXXXXX';
const String secretKey = 'XXXXXXX';
const String apiUrl = 'https://api.regiondo.com/v1/...';
String getQueryString(String url) {
Uri uri = Uri.parse(url);
return uri.query;
}
Map getAuthHeader(String url) {
String queryString = getQueryString(url);
int timestamp = DateTime.now().millisecondsSinceEpoch;
String requestData = '$timestamp$publicKey$queryString';
var key = utf8.encode(secretKey);
var bytes = utf8.encode(requestData);
var hmacSha256 = Hmac(sha256, key);
var digest = hmacSha256.convert(bytes);
return {
'timestamp': timestamp.toString(),
'hmac': digest.toString()
};
}
void main() async {
var authHeader = getAuthHeader(apiUrl);
HttpClient client = HttpClient();
HttpClientRequest request = await client.getUrl(Uri.parse(apiUrl));
request.headers.set('X-API-HASH', authHeader['hmac']);
request.headers.set('X-API-TIME', authHeader['timestamp']);
request.headers.set('X-API-ID', publicKey);
HttpClientResponse response = await request.close();
String reply = await response.transform(utf8.decoder).join();
print('Response: $reply');
}BASH
PUBLIC_KEY="XXXXXXX"
SECRET_KEY="XXXXXXX"
API_URL="https://api.regiondo.com/v1/..."
# Function to extract the query string from the URL
get_query_string() {
local url="$1"
local query_string="${url#*\?}"
if [[ "$query_string" == "$url" ]]; then
echo ""
else
echo "$query_string"
fi
}
get_auth_header() {
local url="$1"
local query_string
query_string=$(get_query_string "$url")
local timestamp
timestamp=$(($(date +%s%N)/1000000)) # Current time in milliseconds
local request_data="${timestamp}${PUBLIC_KEY}${query_string}"
local hmac_digest
hmac_digest=$(echo -n "$request_data" | openssl dgst -sha256 -hmac "$SECRET_KEY" | sed 's/^.* //')
echo "$timestamp" "$hmac_digest"
}
read -r timestamp hmac <><(get_auth_header>
curl -X GET "$API_URL" \
-H "X-API-HASH: $hmac" \
-H "X-API-TIME: $timestamp" \
-H "X-API-ID: $PUBLIC_KEY"