openapi: 3.1.0 info: title: API partenaire BeeHive version: 1.0.0 summary: Publier, modifier et supprimer automatiquement les événements d'un établissement sur BeeHive. description: | L'API partenaire permet à un établissement de synchroniser ses événements avec BeeHive depuis son propre outil : le plugin WordPress BeeHive, un site sur mesure, ou une automatisation (n8n, Make, Zapier…). ## Authentification Chaque requête porte une clé d'API dans l'en-tête `Authorization` : ``` Authorization: Bearer bh_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ``` Les clés se créent dans l'espace établissement de BeeHive, page **Intégrations**. Une clé n'est affichée qu'une fois, à sa création : BeeHive n'en garde qu'une empreinte et ne peut pas la réafficher. Une clé perdue se régénère ; une clé exposée se révoque. Les clés appartiennent à une **connexion** (par exemple « Site WordPress »). Un établissement peut avoir plusieurs connexions, une par outil ou par site. Une clé ne voit et ne modifie **que les événements créés par sa propre connexion**. Les événements saisis dans l'espace établissement, détectés sur Instagram ou envoyés par une autre connexion lui sont invisibles. Régénérer une clé garde la connexion : les événements déjà envoyés restent rattachés à la nouvelle clé. Révoquer une connexion la coupe définitivement. Une connexion est de l'un de ces deux types, choisi à sa création : | Type | Usage | Routes | |---|---|---| | Synchronisation | Envoyer, modifier, supprimer les événements de votre outil | toutes | | Affichage seul | Afficher sur votre site les événements publics de l'établissement | `GET /me`, `GET /categories`, `GET /public-events` | Une clé d'affichage ne peut rien écrire : sur une autre route, la réponse est `403 insufficient_scope`. Si votre site ne fait qu'afficher, choisissez ce type : un site piraté ne pourra rien publier avec sa clé. Envoyez un `User-Agent` qui identifie votre outil et sa version, par exemple `BeeHive-WordPress/1.0.0`. Il sert au support en cas de problème. ## Modes test et production Chaque connexion a deux clés. **Le mode dépend de la clé utilisée**, pas d'un paramètre de la requête : | Clé | Mode | Effet | |---|---|---| | `bh_test_…` | Test | **Rien n'est enregistré.** L'API valide la requête et renvoie ce que la production aurait répondu : mêmes contrôles, mêmes codes d'erreur, même statut. | | `bh_live_…` | Production | Les événements sont enregistrés, vérifiés par la modération, puis publiés sur BeeHive. | Utilisez la clé de test pour mettre au point votre intégration, puis passez à la clé de production. Toutes les réponses portent le champ `test`. En mode test : - `PUT /events/{externalId}` répond toujours `200`, avec l'événement tel qu'il serait enregistré, `id: null` et le statut qu'il aurait en production. Le quota est simulé à partir de l'état réel de l'établissement : une création qui dépasserait le quota renvoie `403 quota_exceeded`, comme en production. Les coordonnées ne sont pas calculées et les traductions ne sont pas produites. - `PUT /events/{externalId}/cover` vérifie le fichier (type, taille, lisibilité) sans l'héberger. - `DELETE` répond toujours `deleted`. - `GET /events` renvoie une liste vide et `GET /events/{externalId}` une `404`, puisque rien n'est enregistré. - Les limites de débit sont les mêmes qu'en production ; le plafond quotidien de créations et la suspension automatique ne s'appliquent pas. ## Identifiant externe Chaque événement est désigné par **votre** identifiant, `externalId` (l'identifiant du post pour WordPress), unique au sein de votre connexion. Vous n'avez pas besoin de connaître l'identifiant BeeHive pour créer, modifier ou supprimer un événement. Il est renvoyé dans le champ `id` si vous souhaitez le conserver. `PUT /events/{externalId}` crée l'événement s'il n'existe pas et le remplace sinon. Rejouer la même requête (après un délai d'attente dépassé, par exemple) ne crée jamais de doublon. ## Statut d'un événement et modération En production, tout événement créé est vérifié avant d'être mis en ligne. Les modifications d'un événement en ligne sont appliquées immédiatement : il reste en ligne, sans interruption de sa page publique. Celles qui touchent un texte ou une image sont revues après coup. | `status` | Signification | |---|---| | `pending` | En modération. Pas visible sur BeeHive tant qu'il n'est pas validé. | | `published` | Visible sur l'application et le site BeeHive. | | `unpublished` | Validé, hors ligne : vous avez envoyé `published: false`. | | `quota_full` | Validé et `published: true`, mais hors ligne : votre quota est atteint (voir « Quota »). | | `rejected` | Refusé par la modération. `reason` en donne le motif quand il est connu. | Règles : - Un événement créé part en modération (`pending`). - Une modification d'un événement validé est appliquée immédiatement, sans changer son statut. Si elle touche un texte ou une image (`name`, `description`, `location`, `tags`, `ticketingUrl`, couverture), elle est revue après coup ; un contenu jugé non conforme fait passer l'événement en `rejected` et peut entraîner la suspension de la connexion. - Un événement `pending` reste en modération, avec le contenu à jour. - Modifier le contenu d'un événement `rejected` le renvoie en modération. Renvoyer exactement le même contenu le laisse `rejected`. - Une valeur de `status` inconnue de votre outil doit être traitée comme `pending` : de nouveaux statuts pourront apparaître. ## Quota Le nombre d'événements à venir publiés en même temps dépend de l'abonnement de l'établissement (`quota.limit` dans `GET /me`, `null` = illimité). Occupe une place un événement **à venir** (sa date de fin, ou sa date s'il n'en a pas, est aujourd'hui ou plus tard) qui est : - en ligne, quelle que soit son origine (espace établissement, Instagram, API) ; - ou en modération, envoyé par l'API avec `published: true`. Un événement passé libère sa place automatiquement. - **Création** : avec `published: true`, s'il ne reste aucune place, la requête est refusée (`403 quota_exceeded`) et rien n'est créé. Réessayez plus tard. - **Modification** : jamais refusée pour cause de quota. Si l'événement ne peut pas être mis en ligne faute de place, il prend le statut `quota_full`. Renvoyez-le (`PUT`) quand une place s'est libérée. C'est aussi le cas d'un événement passé redaté dans le futur : il reprend une place, s'il en reste. - Un événement envoyé avec `published: false` n'occupe pas de place. ## Sécurité Une clé de production permet d'agir sur les événements de votre établissement : protégez-la comme un mot de passe. - Gardez-la côté serveur. Ne la mettez jamais dans du code exécuté par le navigateur, dans un dépôt de code ou dans un message. - Réservez l'accès aux réglages de votre outil aux administrateurs. - Au moindre doute, régénérez-la depuis l'espace établissement : l'ancienne cesse de fonctionner immédiatement. BeeHive limite les dégâts d'une clé volée : - **Modération** : toute création est vérifiée avant publication ; toute modification d'un texte ou d'une image est revue après coup. Un contenu non conforme est retiré et la connexion suspendue (voir « Statut d'un événement et modération »). - **Plafond quotidien** : une connexion crée au plus 500 événements par période de 24 heures, quel que soit l'abonnement. Au-delà, les créations sont refusées (`429 daily_limit_reached`, avec `Retry-After`) ; les modifications et suppressions restent possibles. - **Suspension automatique** : en cas d'activité anormale (par exemple une vague de suppressions d'événements en ligne, ou des modifications en boucle), la connexion est suspendue (`403 connection_suspended`) et l'établissement est prévenu par email. Elle se réactive depuis l'espace établissement, après régénération des clés. - **Suppressions réversibles** : un événement supprimé par l'API reste restaurable pendant 30 jours depuis l'espace établissement. - **Journal d'activité** : chaque création, modification et suppression faite par une connexion est visible dans l'espace établissement. - **Alertes** : l'établissement est prévenu par email quand une clé est créée ou régénérée, quand une connexion est révoquée ou suspendue, et quand un grand nombre d'événements à venir est retiré en 24 heures (sans suspension : vérifiez que c'est bien vous). ## Bonnes pratiques de synchronisation - Envoyez un `PUT` à chaque création ou modification, sans chercher à savoir si l'événement existe déjà. - N'envoyez rien si le contenu n'a pas changé depuis le dernier envoi réussi (comparez une empreinte locale). - N'envoyez la couverture que si l'image a changé. - Les dates et les heures sont en **heure locale du lieu de l'événement**, sans fuseau (`2026-10-12`, `21:00`). - Suivez les décisions de modération avec `GET /events?updatedSince=`, par exemple toutes les heures. - Pour détecter les suppressions manquées (outil désactivé pendant une suppression), comparez de temps en temps `GET /events` avec votre liste. | Réponse | Que faire | |---|---| | `2xx` | Succès. | | `400` | Corrigez les données. Ne réessayez pas tant que le contenu n'a pas changé. | | `401` | Clé invalide ou révoquée. Arrêtez les envois et demandez une nouvelle clé. | | `403 quota_exceeded` | Réessayez plus tard (par exemple une fois par jour). | | `403 account_inactive` | Établissement désactivé. Arrêtez les envois. | | `403 connection_suspended` | Connexion suspendue. Arrêtez les envois et prévenez l'administrateur du site. | | `404` sur un `DELETE` | Déjà supprimé : à traiter comme un succès. | | `429` | Attendez la durée indiquée par `Retry-After`, puis réessayez. | | `5xx` ou réseau | Réessayez avec un délai croissant (1 min, 5 min, 30 min…). | ## Limites de débit Par clé : 120 requêtes par minute, dont 30 envois de couverture. Au-delà, la réponse est `429 rate_limited` avec un en-tête `Retry-After` (en secondes). Les requêtes avec une clé invalide sont aussi limitées, par adresse IP. ## Erreurs Toutes les erreurs ont la même forme : ```json { "error": "validation_failed", "message": "…", "details": { "fields": [ … ] } } ``` `error` est un code stable sur lequel votre outil peut s'appuyer. `message` est un texte indicatif qui peut changer. Un champ inconnu dans le corps de la requête est refusé (`400 validation_failed`), de même qu'un corps JSON illisible ou trop imbriqué (`field: "(body)"`, `invalid_format`) ou de plus de 2 Mo (`too_long`). ## Évolutions Sans changer de version, l'API peut ajouter des routes, des champs facultatifs en entrée, des champs en sortie et de nouvelles valeurs de `status`. Votre outil doit ignorer les champs qu'il ne connaît pas. Toute modification incompatible passera par une nouvelle version, l'ancienne restant servie pendant une période annoncée. servers: - url: https://api.beehiveevents.app/v1/partner-api description: Production security: - ApiKey: [] tags: - name: Connexion description: Vérification de la clé, établissement connecté et quota. - name: Catégories description: Catégories d'événement acceptées par BeeHive. - name: Événements description: Création, modification, lecture et suppression des événements de la connexion. - name: Couverture description: Image de couverture d'un événement. - name: Affichage description: Événements publics de l'établissement, pour les afficher sur un site. paths: /me: get: tags: [Connexion] operationId: getMe summary: Vérifier la clé et lire l'état de la connexion description: | À appeler à l'enregistrement de la clé dans votre outil, puis pour afficher l'établissement connecté, le mode de la clé et le quota. responses: '200': description: Clé valide. content: application/json: schema: $ref: '#/components/schemas/Me' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/AccessDenied' '429': $ref: '#/components/responses/RateLimited' /categories: get: tags: [Catégories] operationId: listCategories summary: Lister les catégories d'événement description: | Liste complète (quelques dizaines d'entrées, non paginée). Le `slug` est la valeur à envoyer dans le champ `category` d'un événement. parameters: - name: lang in: query description: Langue des noms de catégorie. schema: type: string enum: [fr, en, es] default: fr responses: '200': description: Catégories. content: application/json: schema: $ref: '#/components/schemas/CategoryList' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/AccessDenied' '429': $ref: '#/components/responses/RateLimited' /public-events: get: tags: [Affichage] operationId: listPublicEvents summary: Lister les événements publics de l'établissement description: | Événements à venir de l'établissement, visibles sur BeeHive, quelle que soit leur origine (saisis dans l'espace établissement, détectés sur Instagram, envoyés par une connexion). Un événement récurrent apparaît une fois, à sa prochaine date. Triés par date puis heure. Données publiques : la clé de test lit les vraies données. Admis pour les connexions de synchronisation et d'affichage. Seul un extrait de la description est renvoyé ; la fiche complète est sur BeeHive (`publicUrl`). Mettez la réponse en cache (15 minutes conseillées) : n'appelez pas l'API à chaque affichage d'une page. security: - ApiKey: [] parameters: - name: limit in: query description: Nombre d'événements au plus. schema: type: integer minimum: 1 maximum: 100 default: 20 - name: lang in: query description: Langue des titres, extraits et catégories. schema: type: string enum: [fr, en, es] default: fr - name: excludeConnection in: query description: | `true` : écarte les événements envoyés par la connexion de la clé (ils sont déjà sur votre site si vous synchronisez et affichez). schema: type: string enum: ['true', 'false'] default: 'false' responses: '200': description: Événements publics à venir. headers: Cache-Control: description: '`private, max-age=300`' schema: type: string content: application/json: schema: $ref: '#/components/schemas/PublicEventList' '400': $ref: '#/components/responses/ValidationFailed' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/AccessDenied' '429': $ref: '#/components/responses/RateLimited' /events: get: tags: [Événements] operationId: listEvents summary: Lister les événements de la connexion description: | Événements créés par cette connexion, paginés par curseur. Sans `updatedSince`, triés par identifiant croissant ; avec `updatedSince`, triés par date de modification croissante. Une décision de modération compte comme une modification. Les événements supprimés n'y figurent pas. En mode test, la liste est toujours vide. parameters: - name: status in: query description: Ne garder que les événements de ce statut. schema: $ref: '#/components/schemas/EventStatus' - name: updatedSince in: query description: Ne garder que les événements modifiés strictement après cet instant. schema: type: string format: date-time example: '2026-10-06T08:00:00Z' - name: cursor in: query description: Valeur `nextCursor` de la page précédente. Opaque, à renvoyer telle quelle. schema: type: string maxLength: 512 - name: limit in: query description: Nombre d'événements par page. schema: type: integer minimum: 1 maximum: 100 default: 50 responses: '200': description: Une page d'événements. content: application/json: schema: $ref: '#/components/schemas/EventList' '400': $ref: '#/components/responses/ValidationFailed' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/AccessDenied' '429': $ref: '#/components/responses/RateLimited' /events/{externalId}: parameters: - $ref: '#/components/parameters/ExternalId' get: tags: [Événements] operationId: getEvent summary: Lire un événement responses: '200': description: L'événement. content: application/json: schema: $ref: '#/components/schemas/Event' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/AccessDenied' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' put: tags: [Événements] operationId: upsertEvent summary: Créer ou remplacer un événement description: | Crée l'événement s'il n'existe pas pour cette connexion, sinon le remplace entièrement : un champ facultatif absent est vidé. Rejouer la même requête est sans effet supplémentaire. En production, un événement créé part en modération (`pending`). Les modifications d'un événement validé sont appliquées immédiatement. Voir « Statut d'un événement et modération » et « Quota ». En mode test, rien n'est enregistré : voir « Modes test et production ». Si `externalId` désigne un événement supprimé il y a moins de 30 jours, il est restauré, puis les règles de modification s'appliquent. La création d'un événement entièrement passé est refusée (`event_in_past`). La modification d'un événement passé est acceptée. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/EventInput' examples: concert: summary: Concert ponctuel, payant value: name: Concert jazz – Trio Mareas description:

Le trio revient pour une soirée autour de leur nouvel album.

date: '2026-10-12' time: '21:00' endDate: null endTime: '23:30' recurrence: null location: Le Bar X, 12 rue des Pins, 40130 Capbreton latitude: 43.6431 longitude: -1.4283 category: musique tags: [jazz, live] price: amount: 12 currency: EUR ticketingUrl: https://billetterie.example.com/e/123 sourceUrl: https://bar-x.fr/evenement/concert-jazz-trio-mareas language: fr published: true hebdo: summary: Rendez-vous hebdomadaire au lieu de l'établissement value: name: Afterwork du jeudi date: '2026-10-08' time: '18:30' endDate: '2026-12-17' endTime: '21:00' recurrence: daysOfWeek: [4] closedDates: ['2026-11-12'] location: null category: apero price: amount: 0 currency: EUR published: true responses: '200': description: Événement existant remplacé, ou toute réponse réussie en mode test. content: application/json: schema: $ref: '#/components/schemas/Event' '201': description: Événement créé (production). content: application/json: schema: $ref: '#/components/schemas/Event' '400': $ref: '#/components/responses/ValidationFailed' '401': $ref: '#/components/responses/Unauthorized' '403': description: Quota atteint à la création (`quota_exceeded`), établissement désactivé (`account_inactive`) ou connexion suspendue (`connection_suspended`). content: application/json: schema: $ref: '#/components/schemas/Error' examples: quota: value: error: quota_exceeded message: Quota d'événements publiés atteint (3/3). details: limit: 3 published: 2 pending: 1 inactive: value: error: account_inactive message: Cet établissement est désactivé. suspended: value: error: connection_suspended message: Connexion suspendue après une activité inhabituelle. '429': description: Trop de requêtes (`rate_limited`) ou plafond quotidien de créations atteint (`daily_limit_reached`). headers: Retry-After: description: Délai d'attente avant de réessayer, en secondes. schema: type: integer content: application/json: schema: $ref: '#/components/schemas/Error' examples: rate: value: error: rate_limited message: Trop de requêtes, réessayez dans 30 secondes. daily: value: error: daily_limit_reached message: Plafond de 500 créations par 24 heures atteint. delete: tags: [Événements] operationId: deleteEvent summary: Supprimer un événement description: | Retire immédiatement l'événement de BeeHive et de `GET /events`. Il reste restaurable pendant 30 jours depuis l'espace établissement, pour réparer une suppression accidentelle ou malveillante. Un `PUT` sur le même `externalId` pendant ce délai le restaure aussi. Passé ce délai, la suppression est définitive et un `PUT` crée un nouvel événement. Pour retirer un événement temporairement (brouillon, corbeille), envoyez plutôt un `PUT` avec `published: false`. En mode test, la réponse est toujours `deleted`. responses: '200': description: Événement supprimé ou mis hors ligne. content: application/json: schema: $ref: '#/components/schemas/DeleteResult' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/AccessDenied' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' /events/{externalId}/cover: parameters: - $ref: '#/components/parameters/ExternalId' put: tags: [Couverture] operationId: putEventCover summary: Envoyer ou remplacer la couverture description: | Image de 10 Mo au maximum, tout format d'image courant (JPEG, PNG, WebP…) sauf SVG. Elle est convertie et redimensionnée par BeeHive. Remplace la couverture existante. Sur un événement validé, elle est appliquée immédiatement puis revue après coup. En mode test, le fichier est vérifié mais pas hébergé. requestBody: required: true content: multipart/form-data: schema: type: object required: [file] properties: file: type: string contentMediaType: application/octet-stream description: Le fichier image. alt: type: string maxLength: 500 description: Texte alternatif, sans HTML. responses: '200': description: Couverture enregistrée. content: application/json: schema: $ref: '#/components/schemas/CoverResult' '400': description: Fichier absent, illisible ou d'un type refusé (`invalid_file`). content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/AccessDenied' '404': $ref: '#/components/responses/NotFound' '413': description: Fichier de plus de 10 Mo (`file_too_large`). content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' delete: tags: [Couverture] operationId: deleteEventCover summary: Retirer la couverture responses: '200': description: Couverture retirée (ou déjà absente). content: application/json: schema: $ref: '#/components/schemas/CoverResult' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/AccessDenied' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' components: securitySchemes: ApiKey: type: http scheme: bearer bearerFormat: bh_live_ (production) ou bh_test_ (test), suivi de 43 caractères base64url description: Clé d'API de la connexion, créée dans l'espace établissement BeeHive. Le préfixe fixe le mode. parameters: ExternalId: name: externalId in: path required: true schema: type: string pattern: '^(?!\.{1,2}$)[A-Za-z0-9._:-]{1,128}$' description: Votre identifiant de l'événement, unique au sein de la connexion. `.` et `..` sont refusés. example: '42' responses: Unauthorized: description: Clé absente, invalide ou révoquée (`invalid_api_key`). content: application/json: schema: $ref: '#/components/schemas/Error' example: error: invalid_api_key message: Clé d'API invalide ou révoquée. AccessDenied: description: Établissement désactivé (`account_inactive`), connexion suspendue (`connection_suspended`) ou connexion d'affichage sur une route d'écriture (`insufficient_scope`). content: application/json: schema: $ref: '#/components/schemas/Error' examples: inactive: value: error: account_inactive message: Cet établissement est désactivé. suspended: value: error: connection_suspended message: Connexion suspendue après une activité inhabituelle. NotFound: description: Aucun événement avec cet identifiant pour cette connexion (`not_found`). content: application/json: schema: $ref: '#/components/schemas/Error' example: error: not_found message: Événement introuvable. ValidationFailed: description: Données invalides (`validation_failed`). content: application/json: schema: $ref: '#/components/schemas/Error' example: error: validation_failed message: Certains champs sont invalides. details: fields: - field: date code: event_in_past message: L'événement est déjà terminé. - field: category code: unknown_category message: Catégorie inconnue. RateLimited: description: Trop de requêtes (`rate_limited`). headers: Retry-After: description: Délai d'attente avant de réessayer, en secondes. schema: type: integer content: application/json: schema: $ref: '#/components/schemas/Error' example: error: rate_limited message: Trop de requêtes, réessayez dans 30 secondes. schemas: LocalDate: type: string format: date description: Date locale, `AAAA-MM-JJ`. example: '2026-10-12' LocalTime: type: string pattern: '^([01][0-9]|2[0-3]):[0-5][0-9]$' description: Heure locale, `HH:mm` sur 24 heures. example: '21:00' EventStatus: type: string enum: [pending, published, unpublished, quota_full, rejected] description: Voir « Statut d'un événement et modération ». Une valeur inconnue doit être traitée comme `pending`. Price: type: object additionalProperties: false required: [amount, currency] properties: amount: type: number minimum: 0 maximum: 99999999.99 description: Montant. `0` = gratuit. example: 12 currency: type: string enum: [EUR, USD, GBP, CHF, CAD, AUD, JPY, MXN] example: EUR Recurrence: type: object additionalProperties: false required: [daysOfWeek] description: | Répétition hebdomadaire entre `date` (première séance) et `endDate` (dernière séance possible), obligatoire dans ce cas. La série couvre au plus 366 jours. properties: daysOfWeek: type: array minItems: 1 maxItems: 7 uniqueItems: true items: type: integer minimum: 0 maximum: 6 description: Jours de la semaine, `0` = dimanche … `6` = samedi. example: [4] closedDates: type: array maxItems: 366 uniqueItems: true items: $ref: '#/components/schemas/LocalDate' description: Dates sans séance (fermeture exceptionnelle). EventInput: type: object additionalProperties: false required: [name, date, category] properties: name: type: string minLength: 1 maxLength: 500 description: Titre de l'événement. description: type: [string, 'null'] maxLength: 50000 description: | Description, en texte ou en HTML simple. Le HTML est nettoyé par BeeHive (scripts, styles et attributs non sûrs retirés). Au plus 5 000 caractères de texte visible. date: $ref: '#/components/schemas/LocalDate' description: Date de l'événement, ou de la première séance s'il se répète. time: oneOf: - $ref: '#/components/schemas/LocalTime' - type: 'null' description: Heure de début. endDate: oneOf: - $ref: '#/components/schemas/LocalDate' - type: 'null' description: | Dernier jour, pour un événement sur plusieurs jours ou une répétition. Égale ou postérieure à `date` (`end_before_start` sinon). endTime: oneOf: - $ref: '#/components/schemas/LocalTime' - type: 'null' description: | Heure de fin. Antérieure à `time` sans `endDate` : l'événement se termine après minuit (23:00 → 02:00). recurrence: oneOf: - $ref: '#/components/schemas/Recurrence' - type: 'null' location: type: [string, 'null'] maxLength: 2000 description: | Nom du lieu et adresse complète. `null` : l'adresse de l'établissement est utilisée. Obligatoire si l'établissement n'a pas d'adresse (`required`). latitude: type: [number, 'null'] minimum: -90 maximum: 90 description: À fournir avec `longitude`, ou pas du tout (`coordinates_incomplete`). Absentes, BeeHive les calcule depuis `location`. longitude: type: [number, 'null'] minimum: -180 maximum: 180 category: type: string minLength: 1 maxLength: 100 description: Slug d'une catégorie de `GET /categories` (`unknown_category` sinon). example: musique tags: type: array maxItems: 10 items: type: string pattern: '^[a-zA-Z0-9_-]{1,50}$' description: Mots-clés. Enregistrés en minuscules, sans doublon. price: oneOf: - $ref: '#/components/schemas/Price' - type: 'null' description: Tarif d'entrée. `null` = non renseigné. ticketingUrl: type: [string, 'null'] format: uri pattern: '^https://' maxLength: 2048 description: Lien de billetterie, en `https` uniquement. sourceUrl: type: [string, 'null'] format: uri pattern: '^https?://' maxLength: 2048 description: | Page de l'événement sur votre site (`http` ou `https`). Sert à la modération pour vérifier l'événement. Non affichée publiquement. language: type: string enum: [fr, en, es] default: fr description: Langue du titre et de la description. BeeHive traduit automatiquement dans les autres langues. published: type: boolean default: true description: | `false` met l'événement hors ligne sans le supprimer (brouillon, corbeille). Le remettre à `true` le republie. Event: type: object description: | Événement tel qu'enregistré par BeeHive, après normalisation : tags en minuscules, HTML nettoyé, lieu et coordonnées complétés si absents. required: [test, externalId, id, status, reason, publicUrl, coverUrl, createdAt, updatedAt, name, date, category, published] properties: test: type: boolean description: '`true` si la réponse vient d''une clé de test : rien n''a été enregistré.' externalId: type: string example: '42' id: type: [integer, 'null'] description: Identifiant BeeHive. `null` en mode test. example: 12345 status: $ref: '#/components/schemas/EventStatus' reason: type: [string, 'null'] description: Motif du refus quand `status` vaut `rejected` et que la modération en a donné un. publicUrl: type: [string, 'null'] format: uri description: Page publique de l'événement, quand `status` vaut `published` (toujours `null` en mode test). example: https://beehiveevents.app/fr/event/12345 coverUrl: type: [string, 'null'] format: uri description: URL de la couverture enregistrée. createdAt: type: string format: date-time description: En mode test, l'heure de la réponse. updatedAt: type: string format: date-time description: Dernière modification, y compris une décision de modération. En mode test, l'heure de la réponse. name: type: string description: type: [string, 'null'] date: $ref: '#/components/schemas/LocalDate' time: oneOf: - $ref: '#/components/schemas/LocalTime' - type: 'null' endDate: oneOf: - $ref: '#/components/schemas/LocalDate' - type: 'null' endTime: oneOf: - $ref: '#/components/schemas/LocalTime' - type: 'null' recurrence: oneOf: - $ref: '#/components/schemas/Recurrence' - type: 'null' location: type: string latitude: type: [number, 'null'] longitude: type: [number, 'null'] category: type: string tags: type: array items: type: string price: oneOf: - $ref: '#/components/schemas/Price' - type: 'null' ticketingUrl: type: [string, 'null'] sourceUrl: type: [string, 'null'] language: type: string enum: [fr, en, es] published: type: boolean EventList: type: object required: [items, nextCursor] properties: items: type: array items: $ref: '#/components/schemas/Event' nextCursor: type: [string, 'null'] description: À passer dans `cursor` pour la page suivante. `null` sur la dernière page. DeleteResult: type: object required: [test, externalId, result] properties: test: type: boolean externalId: type: string result: type: string enum: [deleted] description: Toujours `deleted`. L'événement reste restaurable 30 jours depuis l'espace établissement. Me: type: object required: [establishment, connection, quota] properties: establishment: type: object required: [id, name, address, city, publicUrl] properties: id: type: integer example: 280 name: type: string example: Le Bar X address: type: [string, 'null'] description: Adresse utilisée quand un événement est envoyé sans `location`. city: type: [string, 'null'] publicUrl: type: [string, 'null'] format: uri example: https://beehiveevents.app/fr/partner/280 connection: type: object required: [name, mode, kind, createdAt, lastUsedAt] properties: name: type: string example: Site WordPress mode: type: string enum: [test, live] description: Mode de la clé utilisée pour cette requête. kind: type: string enum: [sync, display] description: '`sync` : synchronisation ; `display` : affichage seul.' createdAt: type: string format: date-time lastUsedAt: type: [string, 'null'] format: date-time quota: type: object required: [limit, published, pending] description: Voir « Quota ». properties: limit: type: [integer, 'null'] description: Places disponibles. `null` = illimité. example: 3 published: type: integer description: Événements à venir en ligne, toutes origines confondues. example: 1 pending: type: integer description: 'Événements à venir en modération envoyés par l''API avec `published: true`.' example: 1 PublicEvent: type: object required: [id, name, excerpt, date, time, endDate, endTime, recurring, location, city, latitude, longitude, category, price, ticketingUrl, coverUrl, publicUrl] properties: id: type: integer description: Identifiant BeeHive. name: type: string excerpt: type: [string, 'null'] description: Début de la description, en texte brut (280 caractères au plus). date: $ref: '#/components/schemas/LocalDate' description: Prochaine date de l'événement. time: oneOf: - $ref: '#/components/schemas/LocalTime' - type: 'null' endDate: oneOf: - $ref: '#/components/schemas/LocalDate' - type: 'null' description: Dernier jour d'un événement continu sur plusieurs jours ; `null` pour un événement récurrent. endTime: oneOf: - $ref: '#/components/schemas/LocalTime' - type: 'null' recurring: type: boolean description: Événement qui se répète ; `date` est sa prochaine séance. location: type: string city: type: [string, 'null'] latitude: type: [number, 'null'] longitude: type: [number, 'null'] category: oneOf: - type: object required: [slug, name] properties: slug: type: string name: type: string - type: 'null' price: oneOf: - $ref: '#/components/schemas/Price' - type: 'null' ticketingUrl: type: [string, 'null'] coverUrl: type: [string, 'null'] format: uri publicUrl: type: string format: uri description: Fiche de l'événement sur BeeHive (datée pour un événement récurrent). example: https://beehiveevents.app/fr/event/12345 PublicEventList: type: object required: [test, establishment, items, generatedAt] properties: test: type: boolean establishment: type: object required: [id, name, publicUrl] properties: id: type: integer name: type: string publicUrl: type: string format: uri items: type: array items: $ref: '#/components/schemas/PublicEvent' generatedAt: type: string format: date-time CoverResult: type: object required: [test, externalId, coverUrl] properties: test: type: boolean externalId: type: string coverUrl: type: [string, 'null'] format: uri description: URL de la couverture enregistrée. `null` après un retrait, et toujours en mode test. Category: type: object required: [slug, name] properties: slug: type: string example: musique name: type: string example: Musique CategoryList: type: object required: [items] properties: items: type: array items: $ref: '#/components/schemas/Category' Error: type: object required: [error, message] properties: error: type: string description: | Code stable : `invalid_api_key`, `account_inactive`, `connection_suspended`, `insufficient_scope`, `quota_exceeded`, `validation_failed`, `not_found`, `invalid_file`, `file_too_large`, `rate_limited`, `daily_limit_reached`, `internal_error`. message: type: string description: Texte indicatif, susceptible de changer. details: type: object description: | Selon le code. `validation_failed` : `fields`, liste de `{ field, code, message }`. Codes de champ : `required`, `invalid_format`, `too_long`, `out_of_range`, `unknown_field`, `unknown_category`, `event_in_past`, `end_before_start`, `coordinates_incomplete`, `recurrence_without_end`, `recurrence_too_long`. `quota_exceeded` : `limit`, `published`, `pending`.