openapi: 3.1.0 info: title: pressekonto Publisher API version: "1.0" description: | REST-API des Publisher-Hubs (pressekonto) für presseecho.de und businessportal24.com. Pressemitteilungen werden als Entwurf angelegt, optional mit Bildern versehen und über die Submit-Route zur Inhaltsprüfung eingereicht — eine direkte Veröffentlichung über die API ist bewusst nicht möglich. Authentifizierung über einen persönlichen API-Token (Bearer). Jeder Token trägt Berechtigungen (Abilities), die den Zugriff auf die Endpunkte steuern. Tokens werden im Publisher-Konto unter „API-Tokens" selbst erstellt und widerrufen (Voraussetzung: aktive Buchung). Rate-Limit: 60 Anfragen pro Minute je Token (Header X-RateLimit-Limit / X-RateLimit-Remaining, bei 429 zusätzlich Retry-After). Migration: Der X-ApiKey-Header der Altportale wird nicht mehr unterstützt — legacy API keys are no longer supported. servers: - url: https://pressekonto.de/api/v1 security: - bearerToken: [] tags: - name: press-releases description: "Eigene Pressemitteilungen (Ability: press-releases:read bzw. press-releases:write)" - name: images description: "Bilder einer Pressemitteilung (Ability: press-release-images:write zum Schreiben)" - name: companies description: "Eigene Firmenprofile/Newsrooms (Ability: companies:read)" - name: categories description: "Aktive Rubriken (Ability: press-releases:read)" - name: newsletter description: "Newsletter-Anmeldungen (Ability: newsletter:subscribe)" paths: /press-releases: get: tags: [press-releases] summary: Eigene Pressemitteilungen auflisten parameters: - name: status in: query description: Nach Status filtern (draft, review, published, rejected, archived) schema: { type: string } - name: per_page in: query description: Seitengröße, Standard 25, max. 100 schema: { type: integer, maximum: 100 } - name: page in: query schema: { type: integer } responses: "200": description: Paginierte Liste content: application/json: schema: type: object properties: data: type: array items: { $ref: "#/components/schemas/PressRelease" } post: tags: [press-releases] summary: Pressemitteilung anlegen (immer als Entwurf) requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/PressReleaseInput" } responses: "201": description: Entwurf angelegt content: application/json: schema: type: object properties: data: { $ref: "#/components/schemas/PressRelease" } "403": { description: "Ability fehlt oder Firma gehört nicht zum Konto" } "422": { description: "Validierungsfehler" } /press-releases/{id}: parameters: - name: id in: path required: true schema: { type: integer } get: tags: [press-releases] summary: Pressemitteilung abrufen responses: "200": description: Mitteilung inkl. Firma, Rubrik und Bildern content: application/json: schema: type: object properties: data: { $ref: "#/components/schemas/PressRelease" } "403": { description: "Nicht gefunden oder fremdes Konto" } patch: tags: [press-releases] summary: Pressemitteilung ändern (nur draft/rejected) requestBody: content: application/json: schema: { $ref: "#/components/schemas/PressReleaseInput" } responses: "200": { description: "Aktualisierte Mitteilung" } "409": { description: "Nur Entwürfe und abgelehnte Mitteilungen sind änderbar" } delete: tags: [press-releases] summary: Pressemitteilung löschen (nicht bei published) responses: "204": { description: "Gelöscht" } "409": { description: "Veröffentlichte Mitteilungen können nicht per API gelöscht werden" } /press-releases/{id}/submit: post: tags: [press-releases] summary: Zur Inhaltsprüfung einreichen description: | Der einzige API-Weg Richtung Veröffentlichung. Durchläuft denselben Funnel wie das Web-Formular (Richtlinien-Filter, Kontingent, Status-Log). parameters: - name: id in: path required: true schema: { type: integer } responses: "200": { description: "Eingereicht (Status review)" } "402": { description: "Aktive Buchung erforderlich (Tarif oder Einzel-PM)" } "409": { description: "Nur draft/rejected kann eingereicht werden" } "422": { description: "Kontingent erschöpft oder Richtlinienverstoß" } /press-releases/{id}/images: parameters: - name: id in: path required: true schema: { type: integer } get: tags: [images] summary: Bilder einer Mitteilung auflisten responses: "200": description: Bilderliste content: application/json: schema: type: object properties: data: type: array items: { $ref: "#/components/schemas/PressReleaseImage" } post: tags: [images] summary: Bild hochladen (nur bei draft/rejected) requestBody: required: true content: multipart/form-data: schema: type: object required: [image] properties: image: type: string format: binary description: JPG, PNG oder WebP, max. 8 MB title: { type: string, maxLength: 120 } description: { type: string, maxLength: 500 } copyright: { type: string, maxLength: 255 } is_preview: type: boolean description: Als Vorschaubild setzen (ersetzt ein vorhandenes) responses: "201": { description: "Bild gespeichert" } "409": { description: "Mitteilung ist nicht mehr änderbar" } "422": { description: "Ungültige Datei" } /press-release-images/{imageId}: delete: tags: [images] summary: Bild entfernen (nur bei draft/rejected) parameters: - name: imageId in: path required: true schema: { type: integer } responses: "204": { description: "Gelöscht" } "409": { description: "Mitteilung ist nicht mehr änderbar" } /companies: get: tags: [companies] summary: Eigene Firmenprofile auflisten parameters: - name: per_page in: query schema: { type: integer, maximum: 100 } responses: "200": { description: "Paginierte Liste eigener Firmen" } /companies/{id}: get: tags: [companies] summary: Firmenprofil abrufen parameters: - name: id in: path required: true schema: { type: integer } responses: "200": { description: "Firmenprofil" } "403": { description: "Nicht gefunden oder fremdes Konto" } /categories: get: tags: [categories] summary: Aktive Rubriken auflisten responses: "200": { description: "Rubriken inkl. Übersetzungen" } /newsletter/subscribe: post: tags: [newsletter] summary: Newsletter-Anmeldung anlegen (Double-Opt-in folgt per Mail) requestBody: required: true content: application/json: schema: type: object required: [portal, email] properties: portal: type: string enum: [presseecho, businessportal24] email: { type: string, format: email, maxLength: 190 } salutation_key: { type: string, maxLength: 20 } first_name: { type: string, maxLength: 80 } last_name: { type: string, maxLength: 80 } responses: "201": { description: "Anmeldung angelegt (unbestätigt)" } components: securitySchemes: bearerToken: type: http scheme: bearer description: "Persönlicher API-Token aus dem Publisher-Konto (Selfservice unter „API-Tokens")." schemas: PressReleaseInput: type: object required: [company_id, category_id, language, title, text] properties: company_id: type: integer description: ID eines eigenen Firmenprofils — bestimmt Newsroom und Portal category_id: { type: integer } language: type: string minLength: 2 maxLength: 2 description: de oder en title: { type: string, maxLength: 255 } text: type: string description: "Erlaubtes HTML: p, br, h2, h3, strong, em, ul, ol, li, blockquote, a" backlink_url: { type: string, format: uri, maxLength: 255 } keywords: { type: string, maxLength: 255 } teaser_begin: { type: integer, minimum: 0 } teaser_end: { type: integer, minimum: 0 } no_export: { type: boolean } PressRelease: type: object properties: id: { type: integer } uuid: { type: string, format: uuid } portal: { type: string } language: { type: string } title: { type: string } slug: { type: string } text: { type: string } backlink_url: { type: [string, "null"] } keywords: { type: [string, "null"] } status: type: string enum: [draft, review, published, rejected, archived] hits: { type: integer } teaser: type: object properties: begin: { type: [integer, "null"] } end: { type: [integer, "null"] } no_export: { type: boolean } published_at: { type: [string, "null"], format: date-time } company: { type: object } category: { type: object } images: type: array items: { $ref: "#/components/schemas/PressReleaseImage" } created_at: { type: string, format: date-time } updated_at: { type: string, format: date-time } PressReleaseImage: type: object properties: id: { type: integer } title: { type: [string, "null"] } description: { type: [string, "null"] } copyright: { type: [string, "null"] } is_preview: { type: boolean } width: { type: integer } height: { type: integer } mime: { type: string }