{
  "info": {
    "name": "Wohno API (v1.0.0)",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
    "description": "Public, GA-only Postman collection for the Wohno REST API. Generated from the sanitised OpenAPI spec — no internal endpoints. Set the \"api_key\" variable to your sk_live_/pk_live_ key."
  },
  "item": [
    {
      "name": "Organizations",
      "item": [
        {
          "name": "List organizations",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/organizations",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "organizations"
              ]
            },
            "description": "Returns a paginated list of organizations accessible to the API key."
          }
        },
        {
          "name": "Create organization",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/organizations",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "organizations"
              ]
            },
            "description": "Creates a new organization. Requires `organizations:write` scope.",
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Get organization by ID",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/organizations/:id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "organizations",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Returns details of a specific organization. Requires read access to the organization."
          }
        },
        {
          "name": "Update organization",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/organizations/:id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "organizations",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Updates an organization. Requires `organizations:write` scope and admin/owner role.",
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Delete organization",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/organizations/:id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "organizations",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Deletes an organization. Requires `organizations:write` scope and owner role. This action is irreversible."
          }
        }
      ]
    },
    {
      "name": "Listings",
      "item": [
        {
          "name": "List the org's public listings",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/listings",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "listings"
              ]
            },
            "description": "Returns a cursor-paginated, filtered list of the API key's organization listings using the `ListingPublicDto` whitelist."
          }
        },
        {
          "name": "Create or upsert a listing",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/listings",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "listings"
              ]
            },
            "description": "Creates a listing (`201`) or, when an org-scoped `external_ref` already exists, updates it (`200` upsert). Runs the same moderation pipeline as the wizard (no DB bypass) and geocodes server-side. Requires scope `listings:write` (secret key only).",
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Get a single public listing",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/listings/:id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "listings",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Returns a single listing belonging to the API key's organization. Cross-org, unpublished, archived and unknown IDs all resolve to 404 so listing existence is never leaked."
          }
        },
        {
          "name": "Update a listing",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/listings/:id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "listings",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Partially updates a listing of the API key's org. `external_ref` cannot be changed; `status` may transition to `rented`/`archived`. Address changes re-geocode; identical addresses skip geocoding. Foreign/unknown IDs resolve to 404. Requires scope `listings:write` (secret key only).",
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Delete a listing",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/listings/:id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "listings",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Deletes the listing → 204. Foreign/unknown (or already-deleted) IDs resolve to 404 (idempotent from the client's perspective). Requires scope `listings:delete` (secret key only)."
          }
        },
        {
          "name": "Request a signed image-upload URL",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/listings/:id/images",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "listings",
                ":id",
                "images"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Returns a short-lived signed upload URL + `image_id`; the client uploads the binary directly to storage (no large binary through the API). MIME whitelist JPEG/PNG/WebP, 5 MB bucket limit. Requires scope `listings:write` (secret key only).",
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Delete a listing image",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/listings/:id/images",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "listings",
                ":id",
                "images"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Deletes an image of the listing → 204. `image_id` is supplied via `?image_id=…` query or JSON body. Foreign/unknown IDs resolve to 404. Requires scope `listings:write` (secret key only)."
          }
        }
      ]
    },
    {
      "name": "Appointments",
      "item": [
        {
          "name": "List appointments",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/appointments",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "appointments"
              ]
            },
            "description": "Returns appointments belonging to the API key's organization. Filterable by listing, time window, status. With a publishable (pk) key the list is restricted to free future viewing slots of publicly visible listings (active, published, not discrete, not moderation-blocked); `notes` and `location` are omitted, a `status` other than `free` is rejected with `400 VALIDATION_ERROR` and a past `from` is clamped to now."
          }
        },
        {
          "name": "Create an appointment",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/appointments",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "appointments"
              ]
            },
            "description": "Creates a new appointment in the API key's organization. Requires `appointments:write`. Owner is the user who created the API key.",
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Get a single appointment",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/appointments/:id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "appointments",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Returns a single appointment of the API key's organization. With a publishable (pk) key only free future viewing slots of publicly visible listings (active, published, not discrete, not moderation-blocked) are visible — any other id answers `404` (indistinguishable from cross-org) — and the response omits `notes` and `location`."
          }
        },
        {
          "name": "Update an appointment",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/appointments/:id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "appointments",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Update an appointment",
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Cancel an appointment",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/appointments/:id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "appointments",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Soft-cancels the appointment; `.ics`-Storno wird per E-Mail-Pfad ausgelöst."
          }
        },
        {
          "name": "Book a free slot",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/appointments/:id/book",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "appointments",
                ":id",
                "book"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Book an appointment slot. Two authorization paths by key type (Plan 267): **publishable (pk) keys** MUST send a WOHNO-issued signed `booking_intent` (first-party only — issued to the logged-in seeker session, bound to exactly this appointment, 10 min TTL, single-use on a best-effort basis; the security invariants are signature, TTL and appointment binding); body `user_id` is rejected with `403 BOOKING_INTENT_REQUIRED`. **Secret (sk) keys** may keep sending `user_id` (server-to-server booking for the org's own applicants; applicant-gate and audit-log apply) or a `booking_intent`. If both fields are present the `booking_intent` wins. Invalid/expired/replayed intents return `403 BOOKING_INTENT_INVALID`; if intent verification is not configured the endpoint returns `503 BOOKING_INTENT_UNAVAILABLE` (fail-closed).",
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        }
      ]
    },
    {
      "name": "Webhooks",
      "item": [
        {
          "name": "List webhooks",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/webhooks",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "webhooks"
              ]
            },
            "description": "Returns the API key org's webhooks **without** the HMAC secret. Requires scope `webhooks:read` (secret key only)."
          }
        },
        {
          "name": "Create a webhook",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/webhooks",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "webhooks"
              ]
            },
            "description": "Creates a webhook subscription. The HMAC `secret` is returned **once** in this response and never again. Requires scope `webhooks:write` (secret key only). URLs run through an SSRF/HTTPS check server-side.",
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Get a single webhook",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/webhooks/:id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "webhooks",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Returns one webhook of the API key org (no secret). Foreign/unknown IDs resolve to 404. Requires scope `webhooks:read` (secret key only)."
          }
        },
        {
          "name": "Update a webhook",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/webhooks/:id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "webhooks",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Updates url/events/active/description. Never returns the secret. Changed URLs re-run the SSRF/HTTPS check; events are validated against the `EVENT_TYPES` whitelist. Requires scope `webhooks:write` (secret key only).",
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Delete a webhook",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/webhooks/:id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "webhooks",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Deletes the webhook → 204. Foreign/unknown IDs resolve to 404 (idempotent). Requires scope `webhooks:delete` (secret key only)."
          }
        },
        {
          "name": "List webhook deliveries",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/webhooks/:id/deliveries",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "webhooks",
                ":id",
                "deliveries"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Offset-paginated delivery attempts for a webhook. The DTO omits `response_body`/`response_headers`/`payload` (may contain third-party data/secrets). Requires scope `webhooks:read` (secret key only)."
          }
        },
        {
          "name": "Re-deliver a webhook delivery",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/webhooks/:id/deliveries/:deliveryId/redeliver",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "webhooks",
                ":id",
                "deliveries",
                ":deliveryId",
                "redeliver"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                },
                {
                  "key": "deliveryId",
                  "value": "<deliveryId>"
                }
              ]
            },
            "description": "Re-queues an existing delivery → 202 `{ redelivery_id, status: \"pending\" }`. A delivery not belonging to the webhook resolves to 404; an inactive webhook returns 409 `WEBHOOK_INACTIVE`. Requires scope `webhooks:write` (secret key only)."
          }
        }
      ]
    },
    {
      "name": "API Keys",
      "item": [
        {
          "name": "List API keys",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api-keys",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api-keys"
              ]
            },
            "description": "Returns the caller org's active (non-revoked) API keys — never the cleartext secret or hash. Requires scope `api-keys:read` (secret key only)."
          }
        },
        {
          "name": "Create an API key",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api-keys",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api-keys"
              ]
            },
            "description": "Creates a key for the caller org. The cleartext key is returned **once** in the `key` field and never again. Requires scope `api-keys:write` (secret key only). The new key may never carry the global `*` scope or scopes the caller key itself lacks.",
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Get a single API key",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api-keys/:id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api-keys",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Returns one key of the caller org (no secret/hash). Foreign/unknown IDs resolve to 404. Requires scope `api-keys:read` (secret key only)."
          }
        },
        {
          "name": "Revoke an API key",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api-keys/:id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api-keys",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Revokes a key of the caller org → 204. Foreign/unknown IDs resolve to 404. The calling key may not revoke itself → 409 `CANNOT_DELETE_SELF` (self-lockout guard). Requires scope `api-keys:delete` (secret key only)."
          }
        }
      ]
    },
    {
      "name": "Members",
      "item": [
        {
          "name": "List organization members",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/organizations/:id/members",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "organizations",
                ":id",
                "members"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Returns the org's members without PII (no email/phone). Requires scope `members:read` (secret key only). Foreign org IDs resolve to 404."
          }
        },
        {
          "name": "Invite a member",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/organizations/:id/members",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "organizations",
                ":id",
                "members"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Creates an e-mail invitation (no direct add). Requires scope `members:write` (secret key only). A user who is already a member returns 409 `ALREADY_EXISTS`.",
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Update a member's role",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/organizations/:id/members/:userId",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "organizations",
                ":id",
                "members",
                ":userId"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                },
                {
                  "key": "userId",
                  "value": "<userId>"
                }
              ]
            },
            "description": "Changes a member's role. Requires scope `members:write` (secret key only). Owner-related transitions are forbidden (403); unknown members resolve to 404.",
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Remove a member",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/organizations/:id/members/:userId",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "organizations",
                ":id",
                "members",
                ":userId"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                },
                {
                  "key": "userId",
                  "value": "<userId>"
                }
              ]
            },
            "description": "Removes a member from the org → 204. Requires scope `members:delete` (secret key only). Removing an owner is forbidden (403); unknown members resolve to 404."
          }
        }
      ]
    },
    {
      "name": "Applications",
      "item": [
        {
          "name": "List a listing's applications",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/listings/:id/applications",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "listings",
                ":id",
                "applications"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Returns the offset-paginated applications of one listing (incl. the coarse matching score) via the strict `ApplicationPublicDto` whitelist — never raw applicant PII or the full score snapshot. **Consent gate:** per-org consent (missing → `403 CONSENT_REQUIRED`) must pass; the scope `applications:read` is **secret-key only** (publishable keys → `403 INSUFFICIENT_SCOPE`). Hard org-isolation: a foreign listing yields an empty result (existence is never leaked). Every read is audited."
          }
        },
        {
          "name": "Get a single application",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/applications/:id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "applications",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Returns one application via the strict `ApplicationPublicDto` whitelist — never raw applicant PII or internal score weights. **Consent gate:** per-org consent (missing → `403 CONSENT_REQUIRED`) must pass; scope `applications:read` is **secret-key only**. Foreign / unknown IDs resolve to `404` (hard org-isolation, existence is never leaked). Every read is audited."
          }
        },
        {
          "name": "Update an application's status / tags",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/applications/:id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "applications",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Sets a status decision (`shortlisted`/`accepted`/`rejected`) and/or replaces the tag set. The write runs through the application state machine (events + notifications, no DB bypass). **Consent gate:** per-org consent (missing → `403 CONSENT_REQUIRED`) must pass; scope `applications:write` is **secret-key only** (publishable keys → `403 INSUFFICIENT_SCOPE`). Org-isolation is checked before any mutation — foreign / unknown IDs resolve to `404`. An illegal transition (e.g. `accepted`→`new`) or a read-only (`withdrawn`) application returns `409 INVALID_STATUS_TRANSITION`. Every write is audited.",
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        }
      ]
    },
    {
      "name": "Utility",
      "item": [
        {
          "name": "WBS eligibility quick-check",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/wbs/check",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "wbs",
                "check"
              ]
            },
            "description": "Returns a NON-BINDING WBS (Wohnberechtigungsschein) eligibility estimate (`eligible`, `income_limit`, `headroom`, `basis`) for a household. **Stateless:** inputs are neither persisted nor logged in clear text (data minimisation). The scope `wbs:check` is **publishable-key allowed** (browser embeds; publishable keys require an `Origin` header). An unknown `bundesland` is rejected with `400`; at the exact income boundary `headroom` is `0` with `eligible: true`. The `basis` string includes the legal basis plus the disclaimer that the binding decision is made by the responsible housing authority.",
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        }
      ]
    },
    {
      "name": "Discovery",
      "item": [
        {
          "name": "Search public listings (cross-org discovery)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/discovery/listings",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "discovery",
                "listings"
              ]
            },
            "description": "Returns a cursor-paginated, discrete-respecting list of public listings via the strict `DiscoveryListingDto` whitelist. 🔴 Diskret/PII boundary: discrete, inactive, unpublished or blocked listings are structurally excluded (they do not exist in the underlying view); geo is rounded to ≈110 m and never carries street/house number. The scope `discovery:read` is **publishable-key allowed** (browser aggregators; publishable keys require an `Origin` header). Zero matches → an empty list (no error). Supports ETag + `If-None-Match` (`304`) and public `Cache-Control`."
          }
        }
      ]
    },
    {
      "name": "Matching",
      "item": [
        {
          "name": "Compute an applicant matching score (Premium)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/matching/score",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "matching",
                "score"
              ]
            },
            "description": "Computes the WOHNO matching score for an anonymous applicant/listing pair and returns ONLY aggregated values (`total`, boolean `knockout`, coarse per-category scores) — never internal weights, thresholds, formulas or the reasoned K.O. list (score-IP protection). 🔴 **sk-only:** `matching:score` is NOT publishable-allowed (a `pk_` key → `403 INSUFFICIENT_SCOPE`). **Premium-plan gate:** only `premium` orgs may compute; Free/Plus → `403 PLAN_REQUIRED`. Input is anonymous and strict — any accidental PII field (e.g. `name`/`email`) → `400`. **Stateless:** nothing is persisted.",
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        }
      ]
    },
    {
      "name": "Analytics",
      "item": [
        {
          "name": "Get aggregated analytics for a listing (sk-only)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/analytics/listings/:id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "analytics",
                "listings",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "<id>"
                }
              ]
            },
            "description": "Returns anonymous, aggregated analytics for a single listing via the strict `ListingAnalyticsDto` whitelist: totals (views, unique visitors, contact clicks, applications), a conversion funnel and a day/week time series — 🔒 never raw events, raw IPs or visitor PII (`unique_visitors` is derived from hashed identifiers; consent-anonymous counting per Plan 56). 🔒 **sk-only:** `analytics:read` is NOT publishable-allowed (a `pk_` key → `403 INSUFFICIENT_SCOPE`). Org-isolation is hard: a foreign/unknown listing → `404`. The window is capped at 90 days (`from`/`to` spanning > 90 days → `400 VALIDATION_ERROR`). A listing with no data returns all-zero counts and an empty `series`. Supports ETag + `If-None-Match` (`304`) with `Cache-Control: private, max-age=300`."
          }
        }
      ]
    },
    {
      "name": "Usage",
      "item": [
        {
          "name": "Get your organization's quota usage (sk-only)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "X-API-Key",
                "value": "{{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/usage",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "usage"
              ]
            },
            "description": "Returns the calling key's organization quota/usage for one month via the strict `UsageSummaryDto` whitelist: `api_requests`, `webhook_deliveries` and `embed_impressions`, each as `{ used, limit, reset_at }`, plus the effective `plan`. 🔒 **sk-only:** `usage:read` is NOT publishable-allowed (a `pk_` key → `403 INSUFFICIENT_SCOPE`). The plan-dependent `limit` values are derived from the entitlements matrix (`-1` = unlimited / Premium). Source of truth is the `quotaService` (live month from Redis, prior months from the `api_usage_periods` snapshot). In the first month (no prior period) only the live month is returned. On a Redis outage the response falls back to the snapshot and sets `stale: true` — never a `500`."
          }
        }
      ]
    }
  ],
  "auth": {
    "type": "apikey",
    "apikey": [
      {
        "key": "key",
        "value": "X-API-Key"
      },
      {
        "key": "value",
        "value": "{{api_key}}"
      },
      {
        "key": "in",
        "value": "header"
      }
    ]
  },
  "variable": [
    {
      "key": "base_url",
      "value": "https://wohno.de/api/v1",
      "type": "string"
    },
    {
      "key": "api_key",
      "value": "sk_live_your_api_key_here",
      "type": "string"
    }
  ]
}