PADEL LABDevelopers
v1.0.0-beta.1OpenAPIIm Club verwalten
GuidesAPI ReferenceSDKsOpenAPI JSONIm Club verwalten
Dokumentation öffnen
PUT/booking-sources/{sourceId}/bookings/{externalBookingId}

Create or update the complete source-owned booking snapshot

source_version must increase monotonically. The same version and same content is an idempotent replay; the same version with different content or an older version returns VERSION_CONFLICT. Cancellation uses status=CANCELLED. If an operational match can no longer be changed, the booking snapshot is accepted and a reconciliation conflict is created without overwriting Padel Lab match state. Supplying participants requires participants:write; response participants additionally require participants:read and explicit source-bound consent.

Bearer Tokenbookings:write
participants:writeThe request body contains the participants property.
participants:readInclude consented, source-bound participant objects in the response; without it participants is an empty array.

Request

curl · Sandboxbash
curl --request PUT \
  'https://sandbox-api.padel-lab.crewio.co/v1/club/booking-sources/src_01JABC/bookings/booking-1001' \
  --header 'Authorization: Bearer $PADEL_LAB_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
  "source_version": 42,
  "status": "CONFIRMED",
  "external_court_id": "court-1",
  "scheduled_start": "2030-01-15T18:00:00.000Z",
  "scheduled_end": "2030-01-15T19:30:00.000Z",
  "participants": [
    {
      "external_id": "player-17",
      "display_name": "Alex",
      "consent_to_share": true,
      "consent_reference": "consent-2030-001"
    }
  ]
}'

Parameter

sourceIdpathIdrequired
externalBookingIdpathstringrequired

Request Body

BookingSnapshotInputrequired
Examplejson
{
  "source_version": 42,
  "status": "CONFIRMED",
  "external_court_id": "court-1",
  "scheduled_start": "2030-01-15T18:00:00.000Z",
  "scheduled_end": "2030-01-15T19:30:00.000Z",
  "participants": [
    {
      "external_id": "player-17",
      "display_name": "Alex",
      "consent_to_share": true,
      "consent_reference": "consent-2030-001"
    }
  ]
}
JSON Schema anzeigen
{
  "type": "object",
  "additionalProperties": false,
  "description": "A complete source-owned snapshot. scheduled_end must be after scheduled_start and the duration must not exceed 24 hours.",
  "required": [
    "source_version",
    "external_court_id",
    "scheduled_start",
    "scheduled_end",
    "status"
  ],
  "properties": {
    "source_version": {
      "type": "integer",
      "minimum": 0,
      "maximum": 2147483647
    },
    "external_court_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 200,
      "x-runtime-normalization": "trim-before-length-validation"
    },
    "scheduled_start": {
      "type": "string",
      "format": "date-time",
      "description": "UTC RFC 3339 timestamp"
    },
    "scheduled_end": {
      "type": "string",
      "format": "date-time",
      "description": "UTC RFC 3339 timestamp"
    },
    "status": {
      "type": "string",
      "enum": [
        "CONFIRMED",
        "CANCELLED",
        "COMPLETED"
      ]
    },
    "participants": {
      "type": "array",
      "maxItems": 4,
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "external_id",
          "display_name"
        ],
        "properties": {
          "external_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "x-runtime-normalization": "trim-before-length-validation"
          },
          "display_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 80,
            "x-runtime-normalization": "trim-before-length-validation"
          },
          "team": {
            "type": "string",
            "enum": [
              "BLUE",
              "ORANGE",
              "UNASSIGNED"
            ]
          },
          "consent_to_share": {
            "type": "boolean",
            "default": false,
            "description": "Explicit consent to expose the data-minimized participant through the Club API. Omission is treated as false."
          },
          "consent_reference": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "Optional source-side consent receipt or policy reference.",
            "x-runtime-normalization": "trim-before-length-validation"
          }
        },
        "allOf": [
          {
            "if": {
              "required": [
                "consent_reference"
              ]
            },
            "then": {
              "required": [
                "consent_to_share"
              ],
              "properties": {
                "consent_to_share": {
                  "const": true
                }
              }
            }
          }
        ]
      },
      "description": "Requires participants:write in addition to bookings:write."
    }
  }
}

Responses

200Booking updated or exact version replayedBookingMutationResponse
201Booking createdBookingMutationResponse
202Snapshot accepted; reconciliation is requiredBookingMutationResponse
400Malformed JSON or a syntactically valid request that violates a path, query, header or JSON-body constraint.ErrorResponse
401Missing, invalid or expired tokenErrorResponse
403Installation lacks the required scope or is inactiveErrorResponse
404Resource is absent or outside the token-bound tenantErrorResponse
409Version, idempotency, mapping, state or resource-limit conflictErrorResponse
429Rate limit exceededErrorResponse
500An unexpected runtime error occurred; retry only when the operation is safe or idempotent.ErrorResponse
503A required authorization, tenant-safety or rate-limit dependency is unavailableErrorResponse

Response Schemas

BookingMutationResponseStatus 200, 201, 202
{
  "type": "object",
  "additionalProperties": false,
  "required": [
    "data",
    "reconciliation_status",
    "idempotent_replay"
  ],
  "properties": {
    "data": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "id",
        "booking_source_id",
        "location_id",
        "court_id",
        "provider",
        "external_booking_id",
        "external_court_id",
        "source_version",
        "scheduled_start",
        "scheduled_end",
        "status",
        "participants",
        "match_session_id",
        "imported_at",
        "created_at",
        "updated_at"
      ],
      "properties": {
        "id": {
          "type": "string",
          "minLength": 1,
          "maxLength": 200,
          "description": "Opaque stable identifier"
        },
        "booking_source_id": {
          "type": [
            "string",
            "null"
          ]
        },
        "location_id": {
          "type": "string",
          "minLength": 1,
          "maxLength": 200,
          "description": "Opaque stable identifier"
        },
        "court_id": {
          "type": "string",
          "minLength": 1,
          "maxLength": 200,
          "description": "Opaque stable identifier"
        },
        "provider": {
          "type": "string"
        },
        "external_booking_id": {
          "type": [
            "string",
            "null"
          ]
        },
        "external_court_id": {
          "type": "string"
        },
        "source_version": {
          "type": [
            "integer",
            "null"
          ]
        },
        "scheduled_start": {
          "type": "string",
          "format": "date-time",
          "description": "UTC RFC 3339 timestamp"
        },
        "scheduled_end": {
          "type": "string",
          "format": "date-time",
          "description": "UTC RFC 3339 timestamp"
        },
        "status": {
          "type": "string",
          "enum": [
            "CONFIRMED",
            "CANCELLED",
            "COMPLETED"
          ]
        },
        "participants": {
          "type": "array",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "external_id",
              "display_name"
            ],
            "description": "Data-minimized, explicitly consented participant. The response contains only source-bound external_id and display_name, and only when consent_to_share was true, the caller has participants:read and the participant belongs to the caller's source. Team, position, confirmation state, email, raw payloads, media, statistics and unrelated personal attributes are never included.",
            "properties": {
              "external_id": {
                "type": "string"
              },
              "display_name": {
                "type": "string"
              }
            }
          }
        },
        "match_session_id": {
          "type": [
            "string",
            "null"
          ]
        },
        "imported_at": {
          "type": "string",
          "format": "date-time",
          "description": "UTC RFC 3339 timestamp"
        },
        "created_at": {
          "type": "string",
          "format": "date-time",
          "description": "UTC RFC 3339 timestamp"
        },
        "updated_at": {
          "type": "string",
          "format": "date-time",
          "description": "UTC RFC 3339 timestamp"
        }
      }
    },
    "reconciliation_status": {
      "type": "string",
      "enum": [
        "none",
        "required"
      ]
    },
    "idempotent_replay": {
      "type": "boolean"
    }
  }
}
ErrorResponseStatus 400, 401, 403, 404, 409, 429, 500, 503
{
  "type": "object",
  "additionalProperties": false,
  "required": [
    "error"
  ],
  "properties": {
    "error": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "code",
        "message",
        "request_id"
      ],
      "properties": {
        "code": {
          "type": "string",
          "description": "Stable machine-readable code. Clients must tolerate unknown codes within the same HTTP class.",
          "examples": [
            "invalid_request",
            "invalid_cursor",
            "IDEMPOTENCY_KEY_REQUIRED",
            "unsafe_webhook_url",
            "authentication_required",
            "invalid_token",
            "insufficient_scope",
            "installation_inactive",
            "not_found",
            "VERSION_CONFLICT",
            "UNMAPPED_COURT",
            "IDEMPOTENCY_CONFLICT",
            "IDEMPOTENCY_IN_PROGRESS",
            "endpoint_limit_reached",
            "rate_limited",
            "internal_error",
            "idempotency_replay_failed",
            "authorization_unavailable",
            "rate_limit_unavailable"
          ]
        },
        "message": {
          "type": "string"
        },
        "request_id": {
          "type": "string"
        },
        "details": {}
      }
    }
  }
}