Last updated

High Conversion OTA Integration Tutorial

This tutorial walks you through implementing a high-conversion integration between your Outbound Travel Business (OTA) platform and Hubby eSIM. This approach maximizes conversion by automatically assigning appropriate eSIM packages based on your predefined strategy.

Integration Flow

High Conversion Flow

What You'll Build

  • Automatic eSIM booking creation when travel is booked
  • Strategy-based package assignment
  • Automated email delivery system
  • Booking reference storage

Prerequisites

Before starting this tutorial, ensure you have:

  • A Hubby Partner account with API access
  • Your API credentials (public key and secret)
  • A configured package strategy (contact support to set this up)
  • Node.js installed (v14 or later)
  • Basic knowledge of async/await and REST APIs

API Endpoints

Hubby provides two API endpoints for different environments:

  • Production: https://api.hubbyesim.com/api - Use this for live applications
  • Staging: https://api-staging.hubby.dev/api - Use this for testing and development

Always test thoroughly in staging before using production.

Step 1: Project Setup

Create a new directory and initialize your project:

mkdir ota-hubby-integration
cd ota-hubby-integration
npm init -y
npm install node-fetch crypto dotenv express

Create a .env file:

HUBBY_API_KEY=your_api_key
HUBBY_API_SECRET=your_api_secret
# Use staging for development, production for live
HUBBY_API_URL=https://api-staging.hubby.dev/api
# HUBBY_API_URL=https://api.hubbyesim.com/api  # Uncomment for production

Step 2: Authentication Setup

Create auth.js:

require('dotenv').config();
const crypto = require('crypto');

function generateHeaders(method, path, timestamp) {
  const payload = timestamp + method + path;
  const signature = crypto
    .createHmac('sha256', process.env.HUBBY_API_SECRET)
    .update(payload)
    .digest('hex');

  return {
    'x-api-key': process.env.HUBBY_API_KEY,
    'x-timestamp': timestamp,
    'x-signature': signature,
    'Content-Type': 'application/json'
  };
}

module.exports = { generateHeaders };

Step 3: Booking Service

Create booking-service.js:

const fetch = require('node-fetch');
const { generateHeaders } = require('./auth');

class BookingService {
  constructor() {
    this.apiUrl = process.env.HUBBY_API_URL;
  }

  async createEsimBooking(bookingData) {
    const timestamp = Math.floor(Date.now()).toString();
    const path = '/api/bookings';
    
    try {
      const response = await fetch(`${this.apiUrl}${path}`, {
        method: 'POST',
        headers: generateHeaders('POST', path, timestamp),
        body: JSON.stringify({
          booking_id: bookingData.bookingId,
          departure_date: bookingData.departureDate,
          email: bookingData.customerEmail,
          first_name: bookingData.firstName,
          last_name: bookingData.lastName,
          package_specifications: [{
            destination: bookingData.countryCode
          }],
          communication_options: {
            should_send_message: true,
            channels: ["EMAIL"]
          }
        })
      });

      const data = await response.json();
      
      if (!data.success) {
        throw new Error(data.error?.message || 'Failed to create eSIM booking');
      }

      return data;
    } catch (error) {
      console.error('eSIM booking creation failed:', error);
      throw error;
    }
  }

  async updateBookingRecord(bookingId, hubbyData) {
    // Implement your booking record update logic here
    console.log(`Updating booking ${bookingId} with Hubby data:`, hubbyData);
  }
}

module.exports = new BookingService();

Step 4: Express Server Setup

Create server.js:

require('dotenv').config();
const express = require('express');
const bookingService = require('./booking-service');

const app = express();
app.use(express.json());

app.post('/bookings', async (req, res) => {
  try {
    // 1. Create your travel booking
    const travelBooking = await createTravelBooking(req.body);

    // 2. Create Hubby eSIM booking
    const esimBooking = await bookingService.createEsimBooking({
      bookingId: travelBooking.id,
      departureDate: travelBooking.departureDate,
      customerEmail: travelBooking.customerEmail,
      firstName: travelBooking.firstName,
      lastName: travelBooking.lastName,
      countryCode: travelBooking.destination
    });

    // 3. Update booking record with Hubby reference
    await bookingService.updateBookingRecord(travelBooking.id, {
      hubbyBookingId: esimBooking.data.id,
      promocodes: esimBooking.data.promo_codes
    });

    // 4. Return success to customer
    res.json({
      success: true,
      message: 'Booking confirmed! Check your email for eSIM details.',
      bookingId: travelBooking.id
    });
  } catch (error) {
    console.error('Booking failed:', error);
    res.status(500).json({
      success: false,
      error: 'Booking failed. Please try again.'
    });
  }
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

// Mock function - replace with your actual booking creation
async function createTravelBooking(data) {
  return {
    id: 'TB' + Date.now(),
    departureDate: data.departureDate,
    customerEmail: data.email,
    firstName: data.firstName,
    lastName: data.lastName,
    destination: data.destination
  };
}

Step 5: Error Handling

Add error handling middleware in server.js:

app.use((err, req, res, next) => {
  console.error('Error:', err);
  res.status(500).json({
    success: false,
    error: 'An unexpected error occurred'
  });
});

Step 6: Testing

Create test.js:

const fetch = require('node-fetch');

async function testBooking() {
  try {
    const response = await fetch('http://localhost:3000/bookings', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        departureDate: '2024-12-01T00:00:00Z',
        email: 'test@example.com',
        firstName: 'John',
        lastName: 'Doe',
        destination: 'US'
      })
    });

    const data = await response.json();
    console.log('Test result:', data);
  } catch (error) {
    console.error('Test failed:', error);
  }
}

testBooking();

Running the Integration

  1. Start the server:

    node server.js
  2. In a new terminal, run the test:

    node test.js

Best Practices

  1. Early Integration: Create the eSIM booking as soon as the travel booking is confirmed
  2. Error Handling: Implement robust error handling and retry mechanisms
  3. Logging: Add detailed logging for troubleshooting
  4. Monitoring: Track booking success rates and API response times

Next Steps

  1. Add retry logic for failed API calls
  2. Implement webhook handling for booking updates
  3. Add monitoring and alerting
  4. Set up a staging environment for testing

Support

If you need help: