PADEL LABDevelopers
v1.0.0-beta.1OpenAPIIm Club verwalten
GuidesAPI ReferenceSDKsOpenAPI JSONIm Club verwalten
Dokumentation öffnen
POST/oauth/installation-exchange

Exchange a one-time partner installation authorization code

Server-side exchange for an authorization code issued by the Club Portal. The exact redirect_uri and PKCE S256 verifier must match the owner-approved request. A successful exchange provisions one environment- and club-bound ZITADEL M2M principal; it never returns a private key or browser token.

Öffentlicher Code-Exchange

Request

curl · Sandboxbash
curl --request POST \
  'https://sandbox-api.padel-lab.crewio.co/v1/club/oauth/installation-exchange' \
  --header 'Idempotency-Key: 018f-unique-request-key' \
  --header 'Content-Type: application/json' \
  --data '{
  "grant_type": "authorization_code",
  "code": "plc_auth_code_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",
  "code_verifier": "plc-verifier-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdef",
  "redirect_uri": "https://partner.example/callback"
}'

Parameter

Idempotency-Keyheaderstringrequired

Unique key retained for 24 hours on authenticated mutation endpoints. The installation-exchange binding is retained permanently with its consumed authorization code. Reuse with different request content returns IDEMPOTENCY_CONFLICT.

Request Body

PartnerInstallationExchangeInputrequired
Examplejson
{
  "grant_type": "authorization_code",
  "code": "plc_auth_code_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",
  "code_verifier": "plc-verifier-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdef",
  "redirect_uri": "https://partner.example/callback"
}
JSON Schema anzeigen
{
  "type": "object",
  "additionalProperties": false,
  "required": [
    "grant_type",
    "code",
    "code_verifier",
    "redirect_uri"
  ],
  "properties": {
    "grant_type": {
      "const": "authorization_code"
    },
    "code": {
      "type": "string",
      "pattern": "^[A-Za-z0-9_-]{40,200}$"
    },
    "code_verifier": {
      "type": "string",
      "minLength": 43,
      "maxLength": 128,
      "pattern": "^[A-Za-z0-9._~-]+$"
    },
    "redirect_uri": {
      "type": "string",
      "format": "uri",
      "maxLength": 2048
    }
  }
}

Responses

200Installation principal provisionedPartnerInstallationExchangeResponse
400Malformed JSON or a syntactically valid request that violates a path, query, header or JSON-body constraint.ErrorResponse
403Installation lacks the required scope or is inactiveErrorResponse
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

PartnerInstallationExchangeResponseStatus 200
{
  "type": "object",
  "additionalProperties": false,
  "required": [
    "data"
  ],
  "properties": {
    "data": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "installation_id",
        "organization_id",
        "application_id",
        "environment",
        "scopes",
        "oauth_subject",
        "credential_key_id",
        "nonce",
        "api_base_url",
        "oauth_issuer",
        "oauth_token_url",
        "oauth_audience",
        "oauth_audience_scope"
      ],
      "properties": {
        "installation_id": {
          "type": "string",
          "minLength": 1,
          "maxLength": 200,
          "description": "Opaque stable identifier"
        },
        "organization_id": {
          "type": "string",
          "minLength": 1,
          "maxLength": 200,
          "description": "Opaque stable identifier"
        },
        "application_id": {
          "type": "string",
          "minLength": 1,
          "maxLength": 200,
          "description": "Opaque stable identifier"
        },
        "environment": {
          "type": "string",
          "enum": [
            "SANDBOX",
            "PRODUCTION"
          ]
        },
        "scopes": {
          "type": "array",
          "items": {
            "type": "string",
            "enum": [
              "club:read",
              "locations:read",
              "courts:read",
              "bookings:read",
              "bookings:write",
              "participants:read",
              "participants:write",
              "sessions:read",
              "scores:read",
              "events:read",
              "webhooks:manage"
            ]
          }
        },
        "oauth_subject": {
          "type": "string"
        },
        "credential_key_id": {
          "type": "string",
          "minLength": 1
        },
        "nonce": {
          "type": "string"
        },
        "api_base_url": {
          "type": "string",
          "format": "uri",
          "description": "Environment-specific Club API base URL. This exchange response is authoritative."
        },
        "oauth_issuer": {
          "type": "string",
          "format": "uri",
          "description": "Environment-specific ZITADEL issuer used as the JWT assertion audience."
        },
        "oauth_token_url": {
          "type": "string",
          "format": "uri",
          "description": "Environment-specific ZITADEL token endpoint."
        },
        "oauth_audience": {
          "type": "string",
          "minLength": 1,
          "description": "Audience required on Club API access tokens."
        },
        "oauth_audience_scope": {
          "type": "string",
          "pattern": "^urn:zitadel:iam:org:project:id:[A-Za-z0-9_-]+:aud$",
          "description": "ZITADEL project audience scope sent alongside openid in the token request."
        }
      }
    }
  }
}
ErrorResponseStatus 400, 403, 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": {}
      }
    }
  }
}