Documentation développeur

API Produits

Lis et exporte tes données Mepaye — produits, ventes, clients, boutique, codes promo, licences — vers ton site, ton app ou ton outil interne. API REST, lecture seule, format aligné Chariow.

Deux APIs distinctes

  • API Produits (cette page) — menu Clés API, scopes *:read, sans KYC. Sert à LIRE tes données.
  • API Paiement — menu Développeur, scope payments:write, KYC requis. Sert à ENCAISSER via pay.mepaye.com. Voir la doc Paiement →

👉 Pour accepter des paiements, utilise l'API Paiement. Cette API-ci sert à lire tes données.

Introduction

API REST/JSON. Base URL : https://mepaye.com/api/v1. Toutes les ressources sont en lecture seule (verbe GETuniquement) et scopées à ta boutique : une clé ne voit jamais les données d'une autre boutique.

Champs en snake_case, dates en ISO 8601 UTC, montants en minor units (voir Format). Si tu gères plusieurs boutiques, précise laquelle avec l'en-tête X-Store-Id.

Authentification

Crée une clé read-only dans le menu Clés API aucun KYC requis(contrairement à l'API Paiement). Authentifie chaque requête :

http
Authorization: Bearer mp_live_xxxxxxxx
# ou : X-Api-Key: mp_live_xxxxxxxx

Chaque clé porte une liste de scopes ; un endpoint exige le sien :

  • store:read — la boutique
  • products:read — les produits
  • sales:read — les ventes
  • customers:read — les clients
  • discounts:read — les codes promo
  • licenses:read — les clés de licence

Limite : 100 requêtes/minute par clé (en-têtes X-RateLimit-Remaining / X-RateLimit-Reset, puis 429 + Retry-After). Garde la clé côté serveur.

Format des réponses

Toute réponse est une enveloppe uniforme :

json
{
  "message": "success",
  "data": { /* objet, ou { data: [...], pagination: {...} } pour les listes */ },
  "errors": []
}

Pagination (curseur)

Les listes renvoient data.data (les éléments) + data.pagination. Contrôle la taille avec per_page (défaut 20, max 100) et avance avec cursor :

json
{
  "message": "success",
  "data": {
    "data": [ /* … les éléments de la page … */ ],
    "pagination": {
      "next_cursor": "cmp6ljlhl0066jrmw33nbddkz",
      "prev_cursor": null,
      "has_more": true
    }
  },
  "errors": []
}
bash
# Page 1
curl -H "Authorization: Bearer mp_live_xxx" \
  "https://mepaye.com/api/v1/sales?per_page=50"
# → data.pagination.next_cursor = "cmqxshpz5001ojr40e071659h", has_more = true

# Page suivante : repasse le next_cursor reçu
curl -H "Authorization: Bearer mp_live_xxx" \
  "https://mepaye.com/api/v1/sales?per_page=50&cursor=cmqxshpz5001ojr40e071659h"
# Boucle tant que has_more === true.

next_cursor est null et has_more vaut false sur la dernière page.

Montants — minor units

⚠️ Tous les montants sont des entiers en minor units de leur devise (pas de décimales dans value). C'est la différence clé avec un format décimal : on évite toute erreur d'arrondi. Les champs formatted / shortsont fournis pour l'affichage.

json
"current_price": {
  "value": 25000,          // ENTIER en minor units (centimes)
  "formatted": "25 000 XOF",
  "short": "25000",
  "currency": "XOF"
}
// XOF/XAF/GNF/CDF (0 décimale) : value = unité entière → 25000 = 25 000 FCFA
// EUR/USD (2 décimales)        : value = centimes      → 2599  = 25,99 €

Store

GET/api/v1/store

Profil de ta boutique. Scope store:read. id préfixé str_.

curl
curl -H "Authorization: Bearer mp_live_xxx" \
  "https://mepaye.com/api/v1/store"
json
{
  "message": "success",
  "data": {
    "id": "str_cmo9u8zse0001jrof6fhec8rv",
    "name": "Ma Boutique",
    "slug": "ma-boutique",
    "tagline": "Formations & guides",
    "description": null,
    "logo_url": null,
    "favicon_url": null,
    "cover_url": null,
    "url": "https://ma-boutique.mepaye.shop",
    "currency": "XOF",
    "primary_color": "#10B981",
    "seo": { "title": null, "description": null },
    "refund_policy_days": 7,
    "is_verified": true,
    "created_at": "2026-04-22T09:16:29.871Z",
    "updated_at": "2026-06-29T07:37:16.495Z"
  },
  "errors": []
}

Products

GET/api/v1/products

GET/api/v1/products/{id}

Catalogue. Scope products:read. Filtres : search (nom), category, type, per_page, cursor.

curl
curl -H "Authorization: Bearer mp_live_xxxxxxxx" \
  "https://mepaye.com/api/v1/products?per_page=20"
json
{
  "id": "cmp6ljlhl0066jrmw33nbddkz",
  "name": "Guide Chine",
  "slug": "guide-chine",
  "type": "downloadable",
  "status": "PUBLISHED",
  "category": { "value": "business_&_entrepreneuriat", "label": "Business & Entrepreneuriat" },
  "is_free": false,
  "pictures": {
    "thumbnail": "/uploads/2026/05/7ec0…IMG_8975.png",
    "cover": "/uploads/2026/05/7ec0…IMG_8975.png"
  },
  "pricing": {
    "type": "one_time",
    "current_price": { "value": 10000, "formatted": "10 000 XOF", "short": "10000", "currency": "XOF" },
    "price":         { "value": 10000, "formatted": "10 000 XOF", "short": "10000", "currency": "XOF" }
  },
  "tagline": null,
  "refund_policy_days": 7,
  "created_at": "2026-05-15T07:29:11.817Z",
  "sales_count": 13,
  "reviews_count": 0
}

Types de produit (type)

downloadableEbook, template, fichier téléchargeable
courseFormation / cours en ligne
coachingCoaching / accompagnement
bundlePack de plusieurs produits
licenseProduit à clé de licence
serviceService, communauté, prestation

category.value est un slug best-effort, category.labell'intitulé lisible. Le détail/products/{id} renvoie le même objet pour un produit unique.

Sales

GET/api/v1/sales

GET/api/v1/sales/{id}

Commandes (tout le cycle de vie, pas seulement les payées). Scope sales:read. Filtres : status, customer_id, search, start_date, end_date (YYYY-MM-DD).

curl
curl -H "Authorization: Bearer mp_live_xxx" \
  "https://mepaye.com/api/v1/sales?status=completed&per_page=50"
json
{
  "id": "cmqxshpz5001ojr40e071659h",
  "reference": "MEP-20260628-CB7866",
  "status": "completed",
  "refunded_at": null,
  "original_amount":  { "value": 25000, "formatted": "25 000 XOF", "short": "25000", "currency": "XOF" },
  "amount":           { "value": 25000, "formatted": "25 000 XOF", "short": "25000", "currency": "XOF" },
  "discount_amount":  { "value": 0,     "formatted": "0 XOF",      "short": "0",     "currency": "XOF" },
  "payment": { "amount": { "value": 25000, "currency": "XOF" }, "status": "success", "exchange_rate": 1 },
  "product":  { "id": "cmp6l0wf9005jjrmwlztzgtiu", "name": "Guide Chine", "type": "downloadable" },
  "customer": { "id": "cus_YXdhQGV4ZW1wbGUuY29t", "email": "awa@exemple.com", "name": "Awa Diop", "country": "BJ" },
  "discount": null,
  "store": { "id": "cmo9u8zse0001jrof6fhec8rv", "name": "Ma Boutique", "slug": "ma-boutique" },
  "post_purchase": {
    "files": [
      { "id": "cmp6lfy020064jrmwu5phw9yv", "name": "guide.pdf", "size": 419348,
        "download_url": "https://mepaye.com/api/download/eyJmaWxlSWQi…" }
    ],
    "licences": [],
    "instructions": null
  },
  "created_at": "2026-06-28T12:53:10.722Z",
  "paid_at": "2026-06-28T12:55:23.243Z"
}

Statuts (status)

awaiting_paymentOrder PENDING — paiement initié, pas encore confirmé
completedOrder PAID — payé (ou remboursé : voir refunded_at)
failedOrder FAILED — paiement échoué
abandonedOrder CANCELLED — abandonné / annulé

Téléchargements sécurisés : pour une vente payée, chaque fichier de post_purchase.files porte un download_url signé et expirant (token /api/download/…, ~24 h) — jamais un chemin /uploads brut. customer.id (cus_*) relie la vente à Customers.

Customers

GET/api/v1/customers

GET/api/v1/customers/{id}

Clients agrégés par email. Scope customers:read. Filtres : search, start_date, end_date.

curl
curl -H "Authorization: Bearer mp_live_xxx" \
  "https://mepaye.com/api/v1/customers?search=awa"
json
{
  "id": "cus_YXdhQGV4ZW1wbGUuY29t",
  "name": "Awa Diop",
  "first_name": "Awa",
  "last_name": "Diop",
  "email": "awa@exemple.com",
  "avatar_url": null,
  "phone": { "number": "+221770000000", "country": null },
  "store": {
    "id": "cmo9u8zse0001jrof6fhec8rv",
    "name": "Ma Boutique",
    "logo_url": null,
    "url": "https://ma-boutique.mepaye.shop"
  },
  "created_at": "2026-04-25T17:41:30.610Z",
  "updated_at": "2026-04-25T17:41:30.610Z"
}

Le customer_id (cus_*) est stable et déterministe(dérivé de l'email) : le même client porte le même id sur Sales et Customers. Récupère toutes ses commandes via /api/v1/sales?customer_id=cus_….

Discounts

GET/api/v1/discounts

GET/api/v1/discounts/{id}

Codes promo. Scope discounts:read. Filtre : search (code). id préfixé dis_.

curl
curl -H "Authorization: Bearer mp_live_xxx" \
  "https://mepaye.com/api/v1/discounts"
json
{
  "id": "dis_cmqzbw3rk0001jr2i6hl2zyf6",
  "code": "BIENVENUE25",
  "type": "percentage",          // ou "fixed" (montant en minor units)
  "value": 25,                   // 25 = -25 %  ·  pour "fixed" : minor units
  "is_active": true,
  "expires_at": null,
  "max_uses": 100,
  "used_count": 3,
  "min_order_xof_cents": null,
  "created_at": "2026-06-29T14:44:00.656Z"
}

type: "percentage"value est un pourcentage (0–100). type: "fixed" value est un montant en minor units.

Licenses

GET/api/v1/licenses

GET/api/v1/licenses/{id}

Clés de licence de tes produits. Scope licenses:read. Filtre : status (available / used). id préfixé lic_.

curl
curl -H "Authorization: Bearer mp_live_xxx" \
  "https://mepaye.com/api/v1/licenses?status=available"
json
{
  "id": "lic_cmqzbw3rv0003jr2ifk5u3w72",
  "key": "XXXX-YYYY-ZZZZ-1234",
  "status": "available",         // "available" | "used"
  "product": { "id": "cmp6of1fm002cjr3rga7gq3bq", "name": "Mon logiciel", "type": "license" },
  "customer": null,              // { id (cus_*), email, name } une fois attribuée
  "used_at": null,
  "created_at": "2026-06-29T14:44:00.668Z"
}
⚠️ Lecture seule.Contrairement à d'autres plateformes, Mepaye ne fournit aucune route activate / revoke / activations : Mepaye livreles clés, il n'est pas serveur d'activation. status reflète l'attribution (available useddès qu'une clé est rattachée à une commande).

Codes d'erreur

Même enveloppe en cas d'erreur : message = libellé HTTP, data = [], errors = messages lisibles.

json
{
  "message": "Forbidden",
  "data": [],
  "errors": ["Cette clé n'a pas le scope requis (products:read)."]
}
HTTPmessageSignification
401UnauthorisedClé API manquante ou invalide (header Authorization / X-Api-Key).
403ForbiddenLa clé n'a pas le scope requis (ex. products:read).
404Not FoundRessource introuvable (ou hors de ta boutique).
429Too Many RequestsPlus de 100 requêtes/minute pour cette clé. Voir Retry-After.

Les filtres inconnus (ex. type ou status non reconnu) sont ignorés gracieusement plutôt que rejetés.

Prêt ? Crée ta clé read-only dans le menu Clés API. Besoin d'encaisser plutôt que de lire ? API Paiement →