Skip to main content

Building Integrations

GGNomad is designed to plug into the systems a travel business already runs — property management systems, channel managers, and ticketing platforms — and to let partners build their own apps on top of GGNomad inventory and bookings. This guide walks through the building blocks of an integration: querying inventory, writing bookings, keeping availability in sync, and reacting to domain events.

Roadmap items

The SDKs and the CLI referenced below are roadmap and not yet published; the GraphQL API is the available surface.

Integration building blocks

The pieces of an integration A typical GGNomad integration is built from:

  • A workspace-scoped credential (OAuth client or API key)
  • Read queries against inventory (listings, providers, availability)
  • Write mutations for bookings and listings
  • An event subscription to react to changes (for example booking.created)
  • Idempotent sync logic so re-runs are safe

What you can integrate GGNomad commonly connects with:

  • Property and channel management systems (availability and rates)
  • Ticketing and event platforms (events and ticket inventory)
  • Payment and finance systems (settlement and reconciliation)
  • Notification and CRM tools (traveler and host communications)

Getting set up

Create credentials Issue a workspace-scoped credential from the developer portal, then confirm connectivity with a read query:

query Ping {
ggnomadProperties(pagination: { skip: 0, take: 1 }) { id name }
}

If this returns results, your token carries the ggnomad:read permission and is scoped to the right workspace.

Reading inventory

Pull listings to mirror or display them in your own system. Request only the fields you need:

query Inventory {
ggnomadProperties(pagination: { skip: 0, take: 50 }) {
id
name
location
pricePerNight
provider { id name type }
}
}

The same pattern applies to tours, activities, events, and transport trips.

Writing bookings

Confirm a reservation from your own checkout or back office. GGNomad generates a reference code, validates workspace ownership of the target, and emits a booking.created event:

mutation Book($input: CreateGgnomadBookingInput!) {
createGgnomadBooking(input: $input) {
id
referenceCode
status
paymentStatus
}
}

Cancellation Cancellations move a booking to the cancelled state, with the transition recorded on both the trip timeline and the host's booking queue:

mutation Cancel($id: ID!) {
cancelGgnomadBooking(id: $id) { id status }
}

Reacting to events

Rather than polling, subscribe to GGNomad's domain events. A common pattern is to keep an external system in sync as bookings are confirmed — register a webhook endpoint for the events you care about and handle the delivery:

// Your webhook endpoint, subscribed to ggnomad.booking.created
app.post('/webhooks/ggnomad', async (req, res) => {
const event = req.body;

if (event.type === 'ggnomad.booking.created') {
// Mirror the confirmed booking into your PMS / channel manager
await syncBookingToExternalSystem(event.payload);
}

res.sendStatus(200);
});

Build your handler to be idempotent — events may be redelivered, so applying the same booking.created twice must be a no-op.

Keeping availability in sync

When inventory changes in an external system, push the change into GGNomad so discovery and checkout price against current availability. A robust sync:

  1. Reads the current GGNomad state for the affected listing
  2. Computes the delta against the source of truth
  3. Applies updates through the appropriate mutation
  4. Records the sync so re-runs are safe

Error handling

Handle the typed GraphQL error codes rather than parsing messages:

  • UNAUTHENTICATED / FORBIDDEN — token or permission issue
  • WORKSPACE_REQUIRED — missing workspace context
  • NOT_FOUND — the target does not exist in this workspace
  • VALIDATION_ERROR — input failed validation
const { data, errors } = await client.request(CREATE_BOOKING, variables);
if (errors?.length) {
const code = errors[0].extensions?.code;
if (code === 'VALIDATION_ERROR') {
// surface field-level details to the caller
}
throw new IntegrationError(code, errors[0].message);
}

Best practices

  • Send every call to the public API endpoint with a valid credential
  • Let roles scope every action — request the minimum permissions
  • Make writes and event handlers idempotent
  • Paginate every list query and request only needed fields
  • Treat the published GraphQL schema as the contract — watch for deprecations

Getting started

Begin building an integration:

  • Issue a credential and confirm a read query works
  • Wire booking create/cancel into your flow
  • Subscribe to booking.created and keep an external system in sync
  • Verify cross-workspace isolation and RBAC behavior

For integration support, see the API Reference or contact the GGNomad developer team.