Skip to content
TOBENKEY
All projects
06GitHub ProjectAPI Integration · Booking Workflow

SkyWings

Flight Booking Platform

SkyWings is a flight booking web application built with Django and integrated with the Duffel API for flight-related services and Paystack for payment processing. The project demonstrates my ability to combine a server-side web framework, external travel APIs, and payment infrastructure into an end-to-end booking workflow.

SEARCHduffelITINERARYCONFIRMPAYpaystackSERVER-VERIFIED FAREthird-party inventory

Technology

HTMLCSSBootstrapDjangoPaystackDuffel API
01

The problem

Flight availability and pricing are not data you own. They come from an external travel provider, they are quoted with an expiry, and they are not a reservation until the booking is actually confirmed. Building a booking flow means handling third-party authentication, translating an unfamiliar response model into something usable, and making sure a payment is only ever requested against a price the backend has verified and held.

02

Approach

  1. 01

    Kept the Duffel integration server-side. API credentials never reach the browser, and search and pricing logic live in Django where they can be tested and versioned independently of the interface.

  2. 02

    Treated search and booking as separate concerns. Search returns candidates; booking is a distinct, validated step against a specific itinerary — the separation matters because search is cheap and idempotent while booking is neither.

  3. 03

    Made the price authoritative on the server. The amount submitted to the payment gateway is the amount the backend holds, not a figure forwarded from the client, so a tampered request cannot change what is charged.

  4. 04

    Verified the booking before taking payment, so a confirmed seat exists before funds are requested rather than after.

  5. 05

    Built the interface with HTML, CSS and Bootstrap so the booking flow stays readable and usable on the devices travellers actually use, while Django handles the external calls.

03

Architecture

  1. 01

    Search request

    The user submits origin, destination and dates. The Django backend queries the Duffel API and translates the response into a normalised result model.

  2. 02

    Itinerary selection

    A chosen result becomes a server-held itinerary with a verified fare, rather than a set of values the client is trusted to carry forward.

  3. 03

    Booking confirmation

    The booking is confirmed against the Duffel API before any payment is requested, so a failed reservation never reaches the payment step.

  4. 04

    Payment

    The verified amount is sent to Paystack from the backend. The client initiates the payment but cannot influence the amount charged.

  5. 05

    Confirmation

    The result of the transaction is recorded against the itinerary so booking state and payment state remain consistent.

The verified fare lives on the server. The client can start a payment; it cannot decide what the payment is for.

04

Key features

Flight search powered by the Duffel API
Server-side integration layer keeping credentials and pricing logic off the client
Itinerary selection with server-held, verified fares
Booking confirmation before payment is requested
Paystack payment integration
Bootstrap-based responsive interface for search, results and checkout
Django backend handling integration, business logic and payment flow
05

Challenges

Integrating a third-party API you do not control

Travel API responses are deeply nested, token-authenticated, and they change. Isolating the integration behind a service layer meant the rest of the application worked with a normalised model, and a change in the external contract stayed a small, contained edit.

Payment against a price that can expire

A fare quoted at search time is not guaranteed at checkout. Holding the verified amount server-side and confirming the booking before requesting payment is what stops a payment from being attempted against a price that no longer exists.

06

What I learned

Any third-party integration eventually breaks. The design decision that matters is not how well it works on the day it is built, but whether the failure is contained to one module with a clear shape when the external API changes.