API HTTP
Récupérez vos produits, leur configuration de widget et leurs contenus audio depuis une API publique en lecture seule. Toutes les réponses sont au format JSON.
- URL de base
- https://app.ekoo.co
- Authentification
- Aucune
- Format
- JSON
- Accès
- Public · lecture seule
Avant de commencer
Aucune authentification n'est requise. Le seul identifiant nécessaire est celui de votre site.
curl -s "https://app.ekoo.co/ws/websites/{websiteId}/products?limit=5" \ -H "Accept: application/json"Le websiteId est un identifiant public disponible sous Paramètres → Site dans le backoffice, ou dans l'attribut data-ekoo du widget déjà installé sur vos pages.
Cas d'usage typiques
- Rendre les données produit et les transcriptions côté serveur
- SEO
- Afficher les contenus audio dans une application mobile
- Apps
- Générer des pages statiques ou synchroniser un catalogue externe
- Batch
Récupérer un produit
Retourne un produit avec sa configuration de widget et ses contenus audio actifs.
/ws/websites/{websiteId}/products/{productRef}curl -s "https://app.ekoo.co/ws/websites/{websiteId}/products/{productRef}" \ -H "Accept: application/json"Requête
GET https://app.ekoo.co/ws/websites/{websiteId}/products/{productRef}Exemple de réponseStructure JSON complète, sans exécuter la requête
{ "id": "9b0c2f3e-8e4d-4d9b-9c8a-0f3a6b7e1d22", "external_id": "SKU-1234", "name": "Eau de parfum 50ml", "seo_name": "Eau de parfum 50ml — Acme", "seo_description": "Les avis audio de nos clients.", "audio_url": "https://cdn.ekoo.co/audios/...", "website": { "id": "f7c1...", "name": "Acme Cosmetics" }, "features": { "ctaAnalytics": true }, "config": { /* configuration du widget */ }, "experiment": { /* expérimentation A/B éventuelle */ }, "reviews": [ { "id": "5d2a...", "type": "review", "label": "Marie, 34 ans", "rating": 5, "audio_url": "https://cdn.ekoo.co/audios/abc.mp3", "is_active": true, "is_default": true, "created_at": "2026-03-14T09:12:00.000Z", "transcript": "J'ai acheté ce parfum pour ma femme...", "user": { "id": "u_8f...", "firstname": "Marie", "lastname": "D.", "image_url": "https://cdn.ekoo.co/avatars/marie.jpg" } } ]}Paramètres de chemin
websiteIdstring (UUID)- Identifiant de votre site Ekoo, identique à la valeur de data-ekoo.
productRefstring- Référence produit telle que configurée dans le backoffice. Sensible à la casse.
Paramètres de requête
localestringoptionnel- Code de locale BCP-47 (ex. « fr », « en »). Filtre strictement les avis sur cette locale. Si le paramètre est omis, toutes les locales sont retournées.
typestringoptionnel- Type de widget. Vaut « standalone » par défaut.
variantstringoptionnel- Référence stable d'une configuration widget. Le produit et ses audios restent résolus par
productRef; seul l'habillage change. Compatibilité legacy : si aucune référence ne correspond, le backend tente encore une correspondance par nom.
Choisir entre productRef et variant
variant pour réutiliser le même produit avec plusieurs habillages de widget sans dupliquer ses audios ni ses contributeurs. Le productRef continue de porter toute la donnée métier ; variant ne sélectionne que la configuration visuelle.Champs de la réponse
idstring (UUID)- Identifiant interne du produit.
external_idstring- Référence produit, identique à productRef.
namestring- Nom du produit configuré dans le backoffice.
seo_namestring- Nom optimisé pour le référencement, si renseigné dans le backoffice.
seo_descriptionstring- Description optimisée pour le référencement, si renseignée.
audio_urlstring- URL audio par défaut. Champ de commodité, généralement égal à reviews[0].audio_url.
websiteobject- Site propriétaire (id, name).
featuresobject- Options actives pour ce site, lues par le widget. Contient aujourd’hui ctaAnalytics.
configobject- Configuration du widget résolue : thème, textes du CTA, animation, etc.
experimentobject | undefined- Présent uniquement si une expérimentation A/B est en cours sur ce produit.
reviews[]array- Avis et témoignages audio actifs rattachés au produit.
reviews[].type"review" | "testimony"- Indique si l'audio est un avis produit ou un témoignage.
reviews[].ratingnumber (0–5)- Note en étoiles, le cas échéant.
reviews[].audio_urlstring- URL du fichier audio (mp3).
reviews[].transcriptstring- Transcription textuelle de l'audio.
reviews[].is_defaultboolean- True pour l'avis affiché par défaut par le widget.
reviews[].is_activeboolean- False pour les avis désactivés ou supprimés en soft-delete.
reviews[].created_atstring (ISO 8601)- Date de création de l’audio.
reviews[].userobject- Métadonnées de l'auteur : firstname, lastname, image_url, description.
Types TypeScriptDéclarations couvrant les deux endpoints
// À copier dans votre projet — typage complet des réponses export type EkooReviewType = 'review' | 'testimony' export interface EkooReviewUser { id: string firstname?: string lastname?: string image_url?: string description?: string} export interface EkooReview { id: string type: EkooReviewType label?: string rating?: number audio_url?: string is_active: boolean is_default: boolean transcript?: string created_at?: string user: EkooReviewUser} export interface EkooExperimentVariation { id: string name: string widgetEnabled: boolean widgetConfigId: string | null audioSelection: string audioId: string | null audioPosition: number | null audioIdsByLocale?: Record<string, string> allocation: number position: number config?: unknown} export interface EkooExperiment { id: string name: string variations: EkooExperimentVariation[]} export interface EkooProduct { id: string external_id: string name?: string seo_name?: string seo_description?: string audio_url?: string website: { id: string; name?: string } features?: { ctaAnalytics: boolean } config?: Record<string, unknown> experiment?: EkooExperiment reviews: EkooReview[]} export interface EkooProductList { limit: number offset: number count_item: number items: EkooProduct[]}Lister les produits
Retourne une liste paginée des produits d’un site. Les filtres sont appliqués avant la pagination et le calcul du total.
/ws/websites/{websiteId}/productscurl -s "https://app.ekoo.co/ws/websites/{websiteId}/products?limit=5&locale=fr" \ -H "Accept: application/json"Requête
GET https://app.ekoo.co/ws/websites/{websiteId}/products?limit=5&locale=frExemple de réponseStructure JSON complète, sans exécuter la requête
{ "limit": 50, "offset": 0, "count_item": 124, "items": [ { /* même format qu'un produit unique */ } ]}Paramètres de requête
limitintegeroptionnel- Taille de page. Vaut 50 par défaut. Toute valeur ≤ 0 est ramenée à 50.
offsetintegeroptionnel- Offset des résultats. Vaut 0 par défaut.
withoutstringoptionnel- Valeur spéciale « inactive » pour exclure les contenus audio inactifs de la réponse.
localestringoptionnel- Locale des contenus audio recherchés et retournés. Vaut « fr » par défaut.
withAudiobooleanoptionnel- Filtre les produits selon la présence d’au moins un fichier audio retournable dans la locale demandée : URL non vide, validé et non en attente de validation.
publishedbooleanoptionnel- Filtre les produits selon la présence d’au moins un audio publié : URL non vide, actif, validé et non en attente de validation.
Filtres audio courants
- Produits ayant au moins un audio validé dans la locale demandée, actif ou non
withAudio=true- Produits ayant au moins un audio publié et utilisable par le widget
withAudio=true&published=true- Produits ayant au moins un audio retournable, mais aucun audio publié
withAudio=true&published=false- Produits sans aucun audio retournable dans la locale demandée
withAudio=false
Filtrage et pagination
limit, offset et le calcul de count_item. Ne filtrez donc pas les résultats côté client à partir de audio_url. Utilisé seul, published=false inclut également les produits sans audio ; combinez-le avec withAudio=true pour obtenir uniquement les produits possédant un audio retournable, mais non publié.Champs de la réponse
limitinteger- Écho de la taille de page demandée.
offsetinteger- Écho de l'offset demandé.
count_iteminteger- Nombre total de produits correspondant à la requête, toutes pages confondues.
items[]array- Page de produits. Chaque élément a la même structure que la réponse produit unique.
Rendu côté serveur
Rendez les contenus Ekoo dans votre HTML, puis laissez le widget s’hydrater par-dessus.
// app/products/[ref]/page.tsx — Next.js App Router (Server Component)import { notFound } from 'next/navigation'import type { EkooProduct } from '@/lib/ekoo-types' async function fetchEkooProduct(ref: string, locale: string) { const url = `https://app.ekoo.co/ws/websites/${process.env.EKOO_WEBSITE_ID}/products/${ref}?locale=${locale}&variant=homepage` const res = await fetch(url, { next: { revalidate: 300 } }) if (!res.ok) return null return (await res.json()) as EkooProduct} export default async function ProductPage({ params}: { params: Promise<{ ref: string }> }) { const { ref } = await params const product = await fetchEkooProduct(ref, 'fr') if (!product) notFound() const primary = product.reviews.find((r) => r.is_default && r.is_active) return ( <article> {primary?.transcript && ( <section aria-label="Transcription de l'avis audio"> <h2>Ce que disent nos clients</h2> <blockquote>{primary.transcript}</blockquote> <cite>{primary.user.firstname} {primary.user.lastname}</cite> </section> )} {/* Le widget Ekoo s'hydrate côté client et prend le relais */} <ekoo-widget data-ekoo={process.env.EKOO_WEBSITE_ID} data-ekoo-product-id={ref} data-ekoo-locale="fr" data-ekoo-variant="homepage" /> </article> )}Récupérez le produit côté serveur, rendez les champs nécessaires — note, transcription, auteur, mise en page personnalisée — dans votre HTML, puis laissez le widget Ekoo s'hydrater par-dessus une fois chargé. Le pattern est identique dans Nuxt (useFetch), SvelteKit (+page.server.ts), Astro, Remix, ou tout backend capable d'émettre une requête HTTP.
CORS
Erreurs
Toutes les réponses d’erreur partagent la même structure.
{ "type": "ERR_DB_MISSING", "message": "error-message-not-found"}Testez le corps, pas seulement le statut
GET /products/{productRef}, une erreur est renvoyée avec le statut 200 : c’est un comportement historique demandé par des intégrateurs. Un produit introuvable ne se détecte donc qu’à la présence du champ type dans la réponse.Codes de statut
200OK- Ressource trouvée. Sur le produit unique, également renvoyé en cas d’erreur : vérifiez le champ type.
400Bad request- Paramètre de requête invalide, sur l’endpoint liste.
500Server error- Erreur base de données ou en amont. Réessayer avec un backoff exponentiel est sûr.
Corps de l’erreur
typestring- Code stable, lisible par machine. La logique cliente doit s’appuyer sur ce champ. Valeurs courantes : ERR_DB_MISSING (produit ou site inconnu), ERR_INPUT_VALIDATION (paramètre invalide), ERR_DB_READ (erreur base de données).
messagestring- Message destiné aux humains. Peut évoluer sans préavis.
Cache et limites
Ce sur quoi vous pouvez vous appuyer en production.
Cache
Les réponses produit individuelles peuvent être mises en cache par Ekoo et ce cache est invalidé lors des mises à jour depuis le backoffice. La réponse de liste ne doit pas être considérée comme mise en cache. Nous recommandons d'ajouter un cache court côté client — par exemple revalidate: 300 en Next.js, s-maxage sur un CDN — afin d'absorber les pics de trafic et de mitiger les incidents en amont.
Lorsqu'un contenu doit être servi avant la prochaine revalidation, purgez également la page concernée sur votre propre CDN.
Limites de débit
L'API n'utilise pas de clé d'authentification et ne publie actuellement pas de quota contractuel. Évitez le polling haute fréquence non mis en cache. Pour un volume de requêtes élevé et soutenu, contactez le support afin que la capacité soit provisionnée en conséquence.