Annual Ads

Documentation destinée aux développeurs

Développez directement sur la plateforme Annual Ads : créez des annonceurs, publiez des annonces, déclenchez des paiements et suivez le classement, le tout via l'API.

Consultez le barème tarifaire complet

Vous conservez 70 % d’une partie des sommes versées par vos annonceurs en mode Connect pour leurs publicités — versée automatiquement sur votre portefeuille. Découvrez ci-dessous comment cela fonctionne.

URL de base

https://api.adhub365.com
OpenAPI 3

Authentification

Chaque requête est authentifiée à l'aide d'une clé secrète figurant dans l'en-tête « Authorization », selon le schéma « Bearer ».

POST https://api.adhub365.com/v1/partner/ads
Authorization: Bearer sk_sandbox_...
Content-Type: application/json

Environnement de test et production

Les clés « sandbox » et « production » sont totalement isolées les unes des autres : une clé « sandbox » ne peut en aucun cas lire ou écrire des données créées par une clé « production », et inversement.

Champs d'application

Chaque clé est limitée aux périmètres pour lesquels elle a été émise : une clé ne dispose jamais d'un accès plus étendu que le compte partenaire qui l'a créée.

Les clés API sont attribuées aux comptes des partenaires agréés par l'équipe Annual Ads.

Créer un compte partenaire

Partage des recettes publicitaires

Si vos clés API permettent de créer des comptes publicitaires pour vos propres utilisateurs (mode « Connect » — voir la section « Authentification » ci-dessus), vous percevez une part des sommes versées par ces annonceurs pour leurs publicités. La répartition indiquée ci-dessous est récupérée en temps réel à partir de ce même point de terminaison ; elle n'est jamais codée en dur et est totalement distincte de la commission de parrainage mentionnée plus bas sur cette page.

GET https://api.adhub365.com/v1/partner-program
{
  "partner_share_percentage": 0.7,
  "platform_share_percentage": 0.3
}

70%

C'est à toi

Le paiement est versé automatiquement sur le portefeuille de paiement que vous avez configuré — aucune demande de retrait n'est nécessaire.

30%

À consulter dans la rubrique « Publicités annuelles »

Couvre la modération, l'hébergement et l'infrastructure de classement sur laquelle vos publicités sont diffusées.

Comment ça marche ?

  1. L'un de vos annonceurs en mode Connect paie pour une publicité via votre intégration.
  2. L'annonce est examinée et validée, soit automatiquement, soit par notre équipe de modération.
  3. Votre part est en attente d'un versement automatique sur votre portefeuille, selon le même principe que le programme de parrainage ci-dessous.
Une part n'est jamais générée avant que l'annonce ne soit effectivement validée : si la modération la rejette, aucun montant n'est dû au titre de ce paiement. Une recharge sur une annonce déjà active ne comporte pas ce risque et est partagée immédiatement.

Conditions de paiement

  • Un portefeuille de paiement en cryptomonnaie est configuré sur votre compte partenaire.
  • Aucune vérification d’identité n’est requise de votre part : votre compte partenaire a déjà fait l’objet d’une vérification lors de sa création.

Exemple : lecture du nombre cumulé d'actions

GET https://api.adhub365.com/v1/partner/ad-revenue/earnings
Authorization: Bearer sk_sandbox_...
{
  "shares": [
    {
      "id": "share_1a2b...",
      "payment_id": "pay_9f2a...",
      "ad_id": "ad_7c31...",
      "partner_amount_usd": 140.0,
      "platform_amount_usd": 60.0,
      "status": "paid",
      "payable_after": "2026-08-03T00:00:00Z",
      "paid_at": "2026-08-05T10:12:00Z"
    }
  ],
  "total_payable_pending_usd": 0.0,
  "total_payable_usd": 0.0,
  "total_processing_usd": 0.0,
  "total_paid_usd": 140.0
}

Points de terminaison

Comptes

POST/v1/partner/advertisers

Créez un compte annonceur au nom de l'un de vos utilisateurs (mode « Connect »).

advertisers:write
GET/v1/partner/advertisers/{id}

Rechercher un compte annonceur créé par ce partenaire.

advertisers:read

Publicités

POST/v1/partner/ads

Créez une annonce. Elle apparaît d'abord en statut « brouillon ». Les champs facultatifs `advertiser_type`, `promotion_type`, `link_type` et `promoted_brand` permettent de préciser s'il s'agit d'une publicité d'affiliation, de parrainage, de créateur ou individuelle — voir la remarque ci-dessous.

ads:write
GET/v1/partner/ads/{id}

Consulter une annonce.

ads:read
PATCH/v1/partner/ads/{id}

Mettre à jour le contenu éditorial : titre, description, lien, type d'annonceur, type de promotion, type de lien et marque promue. La catégorie, la zone géographique et tout autre élément pris en compte par le moteur de classement ne peuvent en aucun cas être modifiés ici.

ads:write
POST/v1/partner/ads/{id}/image

Téléchargez directement une image pour votre annonce (JPEG/PNG/WebP, 5 Mo max.). Cette étape est obligatoire avant le premier paiement — voir la section « Paiements » ci-dessous.

ads:write
POST/v1/partner/ads/{id}/image-url

Définissez l'image d'une annonce à partir d'une URL plutôt que de télécharger un fichier : le serveur la récupère et la réhéberge lui-même. Même condition : à remplir avant le premier paiement.

ads:write
GET/v1/partner/ads/{id}/rank

Classement actuel, catégorie et zone géographique d'une annonce.

ads:read
GET/v1/partner/ads/{id}/stats

Le nombre total d'impressions et de clics pour une annonce, ainsi que le nombre de jours écoulés ou restants, proviennent des champs `activated_at` et `expires_at` déjà présents dans la requête GET /{id}, tandis que le classement provient de la requête GET /{id}/rank.

ads:read

Paiements

POST/v1/partner/payments

Lancez un paiement en cryptomonnaie pour un premier achat ou une recharge. Un premier paiement échoue avec le code d'erreur 422 à moins que l'annonce ne comporte déjà une image — voir les méthodes uploadAdImage/setAdImageUrl ci-dessus.

payments:write
GET/v1/partner/payments/{id}

Vérifier le statut d'un paiement.

payments:read

Recommandations

POST/v1/partner/referrals

Créer un lien de parrainage.

referrals:write
GET/v1/partner/referrals/{code}/earnings

Rémunérations cumulées issues du parrainage, ventilées par statut.

referrals:read

Partage des recettes publicitaires

GET/v1/partner/ad-revenue/earnings

Votre part de 70 % du montant versé par les annonceurs que vous avez créés en mode Connect pour leurs publicités, ventilée par statut.

ad-revenue:read

Journal d'accès

GET/v1/partner/access-log

Historique complet des appels pour cette clé : méthode, chemin d'accès, adresse IP, horodatage.

N'importe quel

Points de terminaison publics

GET/v1/rankings?category={id}&geo={scope}

Classement en lecture seule pour une catégorie et une zone géographique.

Public
GET/v1/tiers

Les 7 niveaux tarifaires définis (seuil, avantages débloqués).

Public
GET/v1/referral-program

Les taux de commission actuellement en vigueur pour le programme de parrainage en cascade et le « Leaders Pool ».

Public
GET/v1/partner-program

La répartition actuelle des recettes publicitaires (mode Connect) entre vous et Annual Ads.

Public
GET/v1/search?q={query}

Recherche en langage naturel : elle achemine une requête telle que « annonceurs de mobilier au Kenya » vers la catégorie et la zone géographique correspondantes, puis renvoie ce classement, dans son ordre exact tel qu'il apparaît réellement.

Public

Publicité d'affiliation et de parrainage

advertiser_type, promotion_type, link_type et promoted_brand sont des champs facultatifs pour les requêtes POST et PATCH sur /v1/partner/ads — Annual Ads ne se limite pas aux entreprises qui font leur propre publicité. Lorsque link_type vaut affiliate_link ou referral_invitation_link, ou que promotion_type vaut affiliate_offer ou referral_opportunity, affiliate_terms_accepted doit être défini sur true, sinon la requête est rejetée avec un code d'erreur 422. Le champ « title » est limité à 35 caractères et le champ « description » à 80 — ces limites sont appliquées côté serveur, et pas uniquement dans l’interface utilisateur du tableau de bord.

Outils d'IA

Chaque compte publicitaire dispose d'un ensemble d'outils d'IA intégrés — un générateur de contenu et d'éléments visuels publicitaires, un assistant conversationnel, un conseiller en budget et un outil d'audit SEO externe — financés par des crédits IA, en plus du forfait annuel.

Ces appels s'effectuent via les identifiants de connexion au tableau de bord de l'annonceur (un jeton d'accès de session), et non via une clé API partenaire ; une intégration tierce ne peut donc pas les appeler au nom de l'annonceur.
POST/v1/advertisers/{id}/ai/assistant

Ask Annual Ads — un assistant conversationnel flottant, à titre purement informatif, avec un accès en lecture seule aux données du compte.

Public
POST/v1/advertisers/{id}/ai/creative-studio

Générer un titre, une description et des mots-clés pour une annonce à partir d'une brève présentation de l'entreprise.

2 crédit(s)
POST/v1/advertisers/{id}/ai/creative-studio/image

Générer une image de présentation (PNG) à partir de cette même description d'entreprise, hébergée et prête à être jointe à une annonce.

8 crédit(s)
POST/v1/advertisers/{id}/ai/budget-advisor

Une véritable projection statistique — et en aucun cas une estimation approximative — des probabilités de conserver un rang donné à 30, 90 et 365 jours.

1 crédit(s)
POST/v1/advertisers/{id}/ai/seo-audit

Analyser le site web externe de l'annonceur et proposer des améliorations concrètes en matière de référencement naturel (SEO).

2 crédit(s)

Exemple — générer du contenu publicitaire

La même catégorie et la même description d'activité alimentent également le générateur d'images ci-dessous.

POST https://api.adhub365.com/v1/advertisers/{advertiser_id}/ai/creative-studio
Authorization: Bearer <session access token>
Content-Type: application/json

{
  "category_name": "Furniture",
  "business_description": "We sell handmade oak dining tables"
}
{
  "title": "Handmade Oak Dining Tables — Built to Last",
  "description": "Solid oak dining tables crafted by hand, built to last a lifetime.",
  "keywords": ["oak furniture", "dining table", "handmade"],
  "credits_remaining": 8
}

Créer un visuel correspondant à cette même publicité :

POST https://api.adhub365.com/v1/advertisers/{advertiser_id}/ai/creative-studio/image
Authorization: Bearer <session access token>
Content-Type: application/json

{
  "category_name": "Furniture",
  "business_description": "We sell handmade oak dining tables"
}
{
  "visual_url": "https://cdn.uploadscenter.com/file_01m1...",
  "credits_remaining": 4
}

Widget

Ajoutez un bloc publicitaire prêt à l'emploi sur votre site — sans aucune étape de création, ni iframe. Le script s'affiche directement dans la page au sein d'un Shadow DOM isolé ; ainsi, ses styles n'interfèrent jamais avec ceux de votre site, et inversement.

Ajoutez-le à votre page

<div
  class="annualads-widget"
  data-category="YOUR_CATEGORY_ID"
  data-geo="global"
  data-count="4"
  data-columns="2"
></div>
<script async src="https://adhub365.com/widget.js"></script>

Par défaut, cela affiche le classement public complet de la catégorie, c'est-à-dire tous les annonceurs de la plateforme, et pas seulement ceux que vous avez recrutés. Pour n'afficher que les publicités des annonceurs que vous avez créés via le mode Connect (ceux qui génèrent votre commission), ajoutez « data-partner » suivi de votre identifiant de partenaire (que vous trouverez sur la page « Développeurs » de votre tableau de bord) :

<div
  class="annualads-widget"
  data-category="YOUR_CATEGORY_ID"
  data-geo="global"
  data-partner="YOUR_PARTNER_ID"
></div>
<script async src="https://adhub365.com/widget.js"></script>

Si vos annonceurs appartiennent à plusieurs catégories, supprimez complètement « data-category » : en utilisant uniquement « data-partner », le widget affiche toutes vos publicités, toutes catégories confondues, dans une seule grille, ce qui vous évite d'avoir à créer un bloc de widget par catégorie :

<div
  class="annualads-widget"
  data-geo="global"
  data-partner="YOUR_PARTNER_ID"
></div>
<script async src="https://adhub365.com/widget.js"></script>

Vous souhaitez afficher un bloc de type « pied de page » en plus de celui intégré au contenu, chacun présentant des publicités différentes ? Ajoutez un deuxième bloc de widgets avec l'attribut data-layout="compact" (une seule publicité, pouvant être réduite en une petite bulle) et l'attribut data-offset défini sur le nombre de publicités déjà affichées par votre premier widget :

<!-- in your content -->
<div
  class="annualads-widget"
  data-category="YOUR_CATEGORY_ID"
  data-geo="global"
  data-count="4"
  data-columns="2"
></div>

<!-- in your footer, showing different ads via data-offset -->
<div
  class="annualads-widget"
  data-category="YOUR_CATEGORY_ID"
  data-geo="global"
  data-layout="compact"
  data-offset="4"
></div>
<script async src="https://adhub365.com/widget.js"></script>

Attributs

data-categoryID de la catégorie à afficher. Obligatoire — sauf si le paramètre « data-partner » est défini, auquel cas son omission entraîne l'affichage des publicités de ce partenaire dans toutes les catégories.
data-geoPortée géographique : locale, régionale ou mondiale. La valeur par défaut est « mondiale ».
data-countNombre d'annonces à afficher. Valeur par défaut : 4.
data-columnsNombre de colonnes de la grille. La valeur par défaut est 2.
data-layout« grid », « list » ou « compact ». La valeur par défaut est « grid ». L'option « compact » affiche une seule annonce (la valeur « data-count » est ignorée) accompagnée d'un bouton permettant de la réduire en une petite vignette et de la réafficher — il s'agit d'un élément de type pied de page qui n'est jamais positionné de manière fixe par le script lui-même ; vous pouvez donc placer et styliser la balise div contenante comme bon vous semble sur votre propre page.
data-offsetNombre d'annonces les mieux classées à ignorer. La valeur par défaut est 0. Permet à un deuxième widget sur la même page (par exemple, un widget compact dans le pied de page et un widget en grille plus haut) d'afficher des annonces différentes au lieu de répéter deux fois la même — indiquez le nombre d'annonces que l'autre widget affiche déjà.
data-partnerVotre identifiant de partenaire (vous le trouverez sur la page « Développeurs » de votre tableau de bord). Facultatif : sans cet identifiant, le widget affiche le classement public complet de cette catégorie, c'est-à-dire tous les annonceurs présents sur la plateforme. Avec cet identifiant, seules s'affichent les publicités des annonceurs que vous avez recrutés via le mode Connect, c'est-à-dire celles qui génèrent effectivement votre commission.

Partage des recettes

Comment la commission de parrainage est-elle effectivement versée au partenaire ? Le pourcentage, le mode de versement et les conditions préalables.

GET https://api.adhub365.com/v1/referral-program
{
  "levels": [
    {
      "level": 1,
      "percentage": 0.1
    }
  ],
  "leaders_pool_percentage_of_gmv": 0.05,
  "founding_advertiser_pool_percentage_of_gmv": 0.05,
  "payout_verification_window_hours": 48,
  "min_payout_usd": 1
}

Ce n'est pas un nombre fixe

Le pourcentage de commission est défini de notre côté et peut varier — veillez à toujours le récupérer en temps réel à partir de ce point de terminaison plutôt que d'utiliser une valeur fixe.

Entièrement automatique

Il n'y a pas de date butoir pour les retraits. Une tâche planifiée calcule les gains à verser, les regroupe par annonceur et procède automatiquement au paiement dès que toutes les conditions ci-dessous sont remplies.

Conditions de paiement

  • Le montant total des gains à verser à l'annonceur atteint le seuil minimal de paiement.
  • Un portefeuille de retrait de cryptomonnaies est configuré sur leur compte.
  • Leur statut KYC a été vérifié.

Exemple : lecture des bénéfices cumulés

GET https://api.adhub365.com/v1/partner/referrals/{code}/earnings
Authorization: Bearer sk_sandbox_...
{
  "code": "ann-2f8c",
  "earnings": [
    {
      "id": "earn_1a2b...",
      "payment_id": "pay_9f2a...",
      "amount_usd": 30.0,
      "status": "paid",
      "payable_after": "2026-08-01T00:00:00Z",
      "paid_at": "2026-08-03T14:22:00Z"
    }
  ],
  "total_payable_pending_usd": 0.0,
  "total_payable_usd": 0.0,
  "total_processing_usd": 0.0,
  "total_paid_usd": 30.0
}

Niveaux tarifaires (en ligne)

Lisez les données en temps réel à partir de ce point de terminaison — ne codez jamais ces valeurs en dur, car elles peuvent changer de notre côté. Créez un sélecteur de forfait pour vos propres utilisateurs plutôt qu’un champ de montant libre : chaque prix affiché correspond déjà au montant exact à envoyer lors de la création du paiement, et les avantages débloqués indiqués ici expliquent clairement aux utilisateurs ce que ce prix leur apporte. Ils choisissent ainsi un prix qu’ils comprennent, plutôt que de deviner un chiffre.

TierPrixDébloque
Bronze$50.00

Basic visibility

Silver$300.00

Clickable link unlocked

Lien cliquable
Gold$500.00

Animation unlocked

Lien cliquableAnimation
Platinum$1,000.00

Enhanced exposure

Lien cliquableAnimation
Diamond$2,500.00

Premium placement

Lien cliquableAnimation
Elite$5,000.00

Top-tier visibility

Lien cliquableAnimation
Legendary$10,000.00

Maximum visibility & branding

Lien cliquableAnimation

Limites de débit

Le nombre de requêtes est plafonné par clé et par minute. Chaque réponse authentifiée comporte les en-têtes X-RateLimit-Limit, X-RateLimit-Remaining et X-RateLimit-Reset ; tout dépassement de la limite entraîne le retour du code d'erreur 429 « Too Many Requests » accompagné d'un en-tête Retry-After.

Liste blanche d'adresses IP

Facultatif, par partenaire. Tant que vous n’avez pas ajouté d’entrée, vos clés acceptent les requêtes provenant de n’importe quelle adresse IP ; la première entrée fait passer toutes les clés de ce partenaire en mode « liste blanche uniquement ».

Webhooks

Chaque webhook est signé à l'aide de l'algorithme HMAC-SHA256, avec une clé secrète générée une seule fois, au moment de sa création. Il convient de vérifier la signature avant de considérer la charge utile comme fiable. Les événements ne sont transmis qu'au partenaire auquel appartient l'annonceur concerné.

payment.succeededUn paiement a été validé.
payment.refundedUn remboursement a été effectué.
ad.activatedUne annonce est mise en ligne, soit automatiquement, soit après vérification par un administrateur.
invoice.issuedUne facture est émise.
referral.payout.completedUne commission de parrainage est considérée comme versée.
referral.payout.failedUn lot de paiements liés aux parrainages échoue chez le prestataire — les gains sont replacés dans le compte « À payer » et font l'objet d'une nouvelle tentative.
rank.changedLe classement d'une annonce évolue, notamment lorsque le paiement effectué par un autre annonceur en est la cause.
ad.expiring_soon30, 7 ou 1 jour(s) avant l'expiration d'une annonce.
partner_ad_revenue.payout.completedUn versement au titre de la participation aux recettes publicitaires passe au statut « payé ».
partner_ad_revenue.payout.failedUn lot de paiements au titre du partage des recettes publicitaires échoue chez le fournisseur — les montants reviennent dans le compte des créances et font l'objet d'une nouvelle tentative.

SDK

Des SDK officiels pour JavaScript/TypeScript et Python, générés à partir de cette même spécification d'API, sont prévus mais n'ont pas encore été publiés ; d'ici là, veuillez vous connecter directement à l'API HTTP.

Guide de démarrage rapide

Il n'y a pas encore de SDK : ces outils appellent directement l'API HTTP et fonctionnent dès aujourd'hui dans n'importe quel langage.

cURL

curl -X POST https://api.adhub365.com/v1/partner/ads \
  -H "Authorization: Bearer sk_sandbox_..." \
  -H "Content-Type: application/json" \
  -d '{"advertiser_id":"adv_9f2a...","category_id":"cat_furniture","geo_scope":"local","title":"..."}'

JavaScript

await fetch("https://api.adhub365.com/v1/partner/ads", {
  method: "POST",
  headers: {
    Authorization: "Bearer sk_sandbox_...",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    advertiser_id: "adv_9f2a...",
    category_id: "cat_furniture",
    geo_scope: "local",
    title: "...",
  }),
});

Python

import requests

requests.post(
    "https://api.adhub365.com/v1/partner/ads",
    headers={"Authorization": "Bearer sk_sandbox_..."},
    json={
        "advertiser_id": "adv_9f2a...",
        "category_id": "cat_furniture",
        "geo_scope": "local",
        "title": "...",
    },
)