Client API

The Client API enables third-party applications to integrate with MatchEngine for booking management. This API uses a dedicated authentication token and supports mapping your external IDs to MatchEngine entities.

Overview

The Client API provides endpoints for:

  • User Management: Register and map users between your system and MatchEngine

  • Resource Management: Map your external resource IDs to MatchEngine resources

  • Venue Management: Map your external venue IDs to MatchEngine venues

  • Availability: Check resource availability using your external IDs

  • Bookings: Create and manage bookings on behalf of users

Authentication

All Client API requests require a Client API token:

Authorization: Token YOUR_CLIENT_API_TOKEN

Contact MatchEngine to obtain your Client API credentials.

User Identification

When making requests on behalf of a user, include one of these headers:

# Using your external ID (recommended)
X-User-External-ID: your-user-123

# Using MatchEngine's user ID
X-User-ID: 550e8400-e29b-41d4-a716-446655440000

User Endpoints

Register User

Register a new user or retrieve existing user mapping.

Request:

POST /api/v1/client/users/register/
Authorization: Token CLIENT_API_TOKEN
Content-Type: application/json

{
    "external_id": "your-user-123",
    "email": "user@example.com",
    "first_name": "John",
    "last_name": "Doe"
}

Response (201 Created):

{
    "user_id": "550e8400-e29b-41d4-a716-446655440000",
    "external_id": "your-user-123",
    "email": "user@example.com",
    "created": true,
    "mapping_created": true
}
Field Description
user_id MatchEngine's UUID for this user
external_id Your ID for this user
created true if a new user was created
mapping_created true if a new mapping was created

Notes:

  • If external_id already exists for your client, returns the existing mapping

  • If email matches an existing user, creates a mapping to that user

  • Idempotent: calling multiple times with same data is safe

Lookup User

Find a user by your external ID.

Request:

GET /api/v1/client/users/lookup/?external_id=your-user-123
Authorization: Token CLIENT_API_TOKEN

Response (200 OK):

{
    "id": "mapping-uuid",
    "external_id": "your-user-123",
    "user_id": "550e8400-e29b-41d4-a716-446655440000",
    "user_email": "user@example.com",
    "is_active": true,
    "created_at": "2025-01-01T00:00:00Z"
}

Response (404 Not Found):

{
    "error": "No user found with external_id: your-user-123"
}

List User Mappings

List all users mapped for your client.

Request:

GET /api/v1/client/users/mappings/
Authorization: Token CLIENT_API_TOKEN

# Optional query parameters:
# ?is_active=true - Filter by active status
# ?limit=100 - Results per page (max 1000)
# ?offset=0 - Pagination offset

Response (200 OK):

[
    {
        "id": "mapping-uuid",
        "external_id": "your-user-123",
        "user_id": "550e8400-e29b-41d4-a716-446655440000",
        "user_email": "user@example.com",
        "is_active": true,
        "created_at": "2025-01-01T00:00:00Z"
    }
]

Resource Endpoints

Register Resource

Map one of your external resource IDs to a MatchEngine resource.

Request:

POST /api/v1/client/resources/register/
Authorization: Token CLIENT_API_TOKEN
Content-Type: application/json

{
    "external_id": "pitch-123",
    "resource_id": 1,
    "external_data": {
        "custom_field": "value"
    }
}

Response (201 Created):

{
    "external_id": "pitch-123",
    "resource_id": 1,
    "resource_name": "Court 1",
    "venue_name": "Sports Center Munich",
    "created": true
}

Lookup Resource

Find a resource by your external ID.

Request:

GET /api/v1/client/resources/lookup/?external_id=pitch-123
Authorization: Token CLIENT_API_TOKEN

Response (200 OK):

{
    "id": "mapping-uuid",
    "external_id": "pitch-123",
    "resource_id": 1,
    "resource_name": "Court 1",
    "venue_name": "Sports Center Munich",
    "is_active": true,
    "created_at": "2025-01-01T00:00:00Z"
}

List Resource Mappings

GET /api/v1/client/resources/mappings/
Authorization: Token CLIENT_API_TOKEN

Venue Endpoints

Register Venue

Map one of your external venue IDs to a MatchEngine venue.

Request:

POST /api/v1/client/venues/register/
Authorization: Token CLIENT_API_TOKEN
Content-Type: application/json

{
    "external_id": "venue-456",
    "venue_id": 1,
    "external_data": {
        "custom_field": "value"
    }
}

Response (201 Created):

{
    "external_id": "venue-456",
    "venue_id": 1,
    "venue_name": "Sports Center Munich",
    "venue_slug": "sports-center-munich",
    "venue_city": "Munich",
    "approval_status": "pending",
    "created": true
}

Note: Venue mappings require approval before use. The approval_status will be:

  • pending - Awaiting approval

  • approved - Ready to use

  • rejected - Request denied

Lookup Venue

GET /api/v1/client/venues/lookup/?external_id=venue-456
Authorization: Token CLIENT_API_TOKEN

Response (200 OK):

{
    "id": "mapping-uuid",
    "external_id": "venue-456",
    "venue_id": 1,
    "venue_name": "Sports Center Munich",
    "venue_slug": "sports-center-munich",
    "venue_city": "Munich",
    "is_active": true,
    "approval_status": "approved",
    "created_at": "2025-01-01T00:00:00Z"
}

List Venue Mappings

GET /api/v1/client/venues/mappings/
Authorization: Token CLIENT_API_TOKEN

# Optional query parameters:
# ?approval_status=approved - Filter by approval status

Get Venue with Resources

Get complete venue details including all resources by your external ID.

Request:

GET /api/v1/client/venues/resources/?venue_external_id=venue-456
Authorization: Token CLIENT_API_TOKEN

Response (200 OK):

{
    "id": 1,
    "external_id": "venue-456",
    "name": "Sports Center Munich",
    "slug": "sports-center-munich",
    "description": "Premier sports facility...",
    "short_description": "Modern sports center",
    "venue_type": "sports_center",
    "street_address": "Example Street 123",
    "city": "Munich",
    "postal_code": "80331",
    "country": "Germany",
    "latitude": "48.137154",
    "longitude": "11.576124",
    "timezone": "Europe/Berlin",
    "is_active": true,
    "is_published": true,
    "resources": [
        {
            "id": 1,
            "name": "Court 1",
            "description": "Indoor tennis court",
            "external_id": "pitch-123",
            "capacity": 4,
            "base_price": "25.00",
            "currency": "EUR",
            "price_unit": "hour",
            "booking_interval_minutes": 30,
            "min_booking_duration_minutes": 60,
            "max_booking_duration_minutes": 180,
            "is_active": true,
            "is_bookable": true
        }
    ]
}

Note: Resources include their external_id if you have mapped them.


Availability Endpoint

Get availability using your external resource ID.

Request:

GET /api/v1/resources/availability/?resource_external_id=pitch-123&start_date=2025-01-15&end_date=2025-01-16
Authorization: Token CLIENT_API_TOKEN

Response:

{
    "resource_id": 1,
    "resource_name": "Court 1",
    "start_date": "2025-01-15",
    "end_date": "2025-01-16",
    "timezone": "Europe/Berlin",
    "booking_interval_minutes": 30,
    "min_duration_minutes": 60,
    "max_duration_minutes": 180,
    "prevent_unbookable_gaps": true,
    "min_advance_booking_minutes": 60,
    "max_advance_booking_days": 30,
    "available_ranges": [
        {
            "date": "2025-01-15",
            "start_time": "08:00:00",
            "end_time": "14:00:00",
            "price_per_hour": "25.00",
            "currency": "EUR",
            "label": "",
            "slot_prices": null
        },
        {
            "date": "2025-01-15",
            "start_time": "15:30:00",
            "end_time": "22:00:00",
            "price_per_hour": "30.00",
            "currency": "EUR",
            "label": "Peak Hours",
            "slot_prices": null
        }
    ]
}

Booking Endpoints

Create Booking

Create a booking on behalf of a user using your external IDs.

Request:

POST /api/v1/bookings/
Authorization: Token CLIENT_API_TOKEN
X-User-External-ID: your-user-123
Content-Type: application/json

{
    "resource_external_id": "pitch-123",
    "start_datetime": "2025-01-15T10:00:00+01:00",
    "end_datetime": "2025-01-15T11:30:00+01:00",
    "participant_count": 2,
    "notes": "Optional booking notes"
}

Response (201 Created):

{
    "id": 123,
    "reference_code": "BK-250115-A7F3",
    "status": "pending",
    "resource_id": 1,
    "resource_name": "Court 1",
    "venue_name": "Sports Center Munich",
    "start_datetime": "2025-01-15T10:00:00+01:00",
    "end_datetime": "2025-01-15T11:30:00+01:00",
    "total_price": "37.50",
    "currency": "EUR",
    "participant_count": 2,
    "created_at": "2025-01-14T15:30:00Z"
}

Important: The start_datetime and end_datetime must include the timezone offset (e.g., +01:00 for CET).

List Bookings

List all bookings made through your client.

GET /api/v1/bookings/
Authorization: Token CLIENT_API_TOKEN

Get Booking Details

GET /api/v1/bookings/123/
Authorization: Token CLIENT_API_TOKEN
X-User-External-ID: your-user-123

Cancel Booking

POST /api/v1/bookings/123/cancel/
Authorization: Token CLIENT_API_TOKEN
X-User-External-ID: your-user-123
Content-Type: application/json

{
    "reason": "user_request",
    "notes": "User changed plans"
}

Create Payment Intent

POST /api/v1/bookings/123/create-payment-intent/
Authorization: Token CLIENT_API_TOKEN
X-User-External-ID: your-user-123

Response:

{
    "client_secret": "pi_3ABC123_secret_XYZ789",
    "payment_intent_id": "pi_3ABC123",
    "amount": "37.50",
    "currency": "EUR",
    "publishable_key": "pk_live_xxx",
    "stripe_account_id": "acct_xxx"
}

Use the client_secret with Stripe.js to complete payment. If stripe_account_id is present, payments go directly to the venue operator via Stripe Connect.


SDKs

We provide official SDKs for easy integration:

TypeScript/JavaScript SDK

Install:

npm install @matchengine/sdk
# or
yarn add @matchengine/sdk

Usage:

import { MatchEngineClient } from '@matchengine/sdk';

const client = new MatchEngineClient({
  baseUrl: 'https://api.matchengine.de',
  apiToken: 'YOUR_CLIENT_API_TOKEN',
  stripePublishableKey: 'pk_live_xxx',
});

// Register user
const user = await client.registerUser({
  externalId: 'user-123',
  email: 'user@example.com',
});

// Get venue with resources
const venue = await client.getVenueWithResources('venue-456');

// Get availability
const availability = await client.getAvailability({
  resourceExternalId: 'pitch-123',
  startDate: new Date('2025-01-15'),
  endDate: new Date('2025-01-16'),
});

// Create booking
const booking = await client.createBooking({
  resourceExternalId: 'pitch-123',
  userExternalId: 'user-123',
  startDatetime: new Date('2025-01-15T10:00:00'),
  endDatetime: new Date('2025-01-15T11:30:00'),
  timezone: availability.timezone,
});

// Create payment intent
const payment = await client.createPaymentIntent({
  bookingId: booking.id,
  userExternalId: 'user-123',
});

Flutter SDK

Add to pubspec.yaml:

dependencies:
  matchengine_sdk: ^1.0.0

Usage:

import 'package:matchengine_sdk/matchengine_sdk.dart';

final client = MatchEngineClient(
  config: MatchEngineConfig(
    baseUrl: 'https://api.matchengine.de',
    apiToken: 'YOUR_CLIENT_API_TOKEN',
    stripePublishableKey: 'pk_live_xxx',
  ),
);

// Register user
final user = await client.registerUser(
  externalId: 'user-123',
  email: 'user@example.com',
);

// Get venue with resources
final venue = await client.getVenueWithResources('venue-456');

// Get availability
final availability = await client.getAvailability(
  resourceExternalId: 'pitch-123',
  startDate: DateTime(2025, 1, 15),
  endDate: DateTime(2025, 1, 16),
);

// Create booking
final booking = await client.createBooking(
  resourceExternalId: 'pitch-123',
  userExternalId: 'user-123',
  startDatetime: DateTime(2025, 1, 15, 10, 0),
  endDatetime: DateTime(2025, 1, 15, 11, 30),
  timezone: availability.timezone,
);

Error Handling

Common Error Responses

401 Unauthorized - Invalid or missing API token

{
    "detail": "Authentication credentials were not provided."
}

403 Forbidden - Not a Client API user

{
    "detail": "You do not have permission to perform this action."
}

400 Bad Request - Missing user header

{
    "error": "User identification required. Provide X-User-ID or X-User-External-ID header."
}

404 Not Found - External ID not mapped

{
    "error": "No user found with external_id: your-user-123"
}

400 Bad Request - Slot not available

{
    "error": "The requested time slot is not available"
}

Best Practices

  1. Register users before booking - Always ensure users are registered before attempting to create bookings.

  2. Use external IDs consistently - Choose a naming convention for your external IDs and stick with it.

  3. Handle approval status - Venue mappings may require approval. Check approval_status before using.

  4. Include timezone in datetime - Always include the timezone offset in booking datetime values.

  5. Store booking reference codes - The reference_code is useful for customer support and lookups.

  6. Use webhooks for payment status - Set up Stripe webhooks to receive payment confirmations instead of polling.