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 connect their own systems to GGNomad inventory and bookings through the API. 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.