Aller au contenu

Trois analyses gratuites, sans compte pour juger Soumize sur votre propre appel d'offres. Sans carte bancaire. Essayer maintenant

Soumize

API et SDK

Les marchés publics marocains, lisibles par une machine. Aujourd'hui 0 consultations collectées sur le portail officiel, 0 acheteurs et 0 attributions, dont 0 consultations encore ouvertes.

S'authentifier

Créez une clé dans Réglages › API. Elle est affichée une seule fois : nous n'en gardons qu'une empreinte, et nous ne pouvons pas vous la réafficher. Envoyez-la en en-tête porteur.

curl -H "Authorization: Bearer sk_live_…" \
  "https://www.soumize.com/api/v1/consultations?open=true&limit=5"

Portées

Une clé ne peut que ce qu'on lui a explicitement accordé. Les portées se cochent à la création ; une route hors portée répond 403, jamais des données partielles.

  • marches:lireLire les données publiques des marchés
  • espace:lireLire les données de votre espace
  • documents:genererGénérer des documents administratifs
  • webhooks:gererCréer et supprimer des abonnements webhook

Le client TypeScript

Sans aucune dépendance : uniquement fetch. La pagination est enchaînée pour vous par all().

import { Soumize } from "@soumize/sdk";

const soumize = new Soumize({ cle: process.env.SOUMIZE_API_KEY! });

for await (const c of soumize.consultations.all({ category: "travaux", open: true })) {
  console.log(c.reference, c.title, c.deadline);
}

La spécification complète est publique, sans clé : openapi.json. Elle est engendrée depuis les mêmes descripteurs que les réponses : elle ne peut donc pas décrire un champ que l'API ne rend plus.

Pagination

limit (200 au maximum) et offset. Chaque réponse porte has_more et next_offset : il n'y a pas de comptage total, parce que compter l'ensemble à chaque appel coûterait plus cher que la page elle-même. Au-delà de quelques milliers d'éléments, filtrez plutôt que de décaler.

Quotas

Le plafond est porté par la clé, par minute. Chaque réponse porte X-RateLimit-Limit, X-RateLimit-Remaining et X-RateLimit-Reset ; un dépassement répond 429 avec Retry-After. Le client réessaie de lui-même les 429 et les 5xx, en suivant cet en-tête.

Engendrer un document

Sans état : vos données entrent, le texte sort, rien n'est conservé. Vous n'avez pas à créer un marché chez nous au préalable.

const doc = await soumize.documents.create({
  doc_type: "avis_appel_offres",
  entite: { legal_name_fr: "COMMUNE DE X" },
  marche: {
    reference: "12/2026",
    fiscal_year: 2026,
    object_fr: "Travaux de voirie",
    estimation_ttc: 1200000,
  },
});

if (!doc.complet) console.warn("Sections manquantes :", doc.manquantes);

complet vaut faux dès qu'une variable manque, et manquantes les nomme. Le document est engendré quand même, avec ses marqueurs visibles : un document troué doit se voir. Chaque réponse porte un avertissement non paramétrable : aide à la conformité, pas conseil juridique.

Webhooks : être prévenu, plutôt qu'interroger

Souscrivez à consultation.publiee ou attribution.publiee et nous appelons votre serveur dès qu'un avis paraît, au lieu que vous veniez demander.

const abonnement = await soumize.webhooks.create({
  url: "https://votre-serveur.ma/soumize",
  events: ["consultation.publiee"],
  filtres: { category: "travaux", region: "Casablanca-Settat" },
});

// Le secret n'est renvoyé qu'ici. Conservez-le.
console.log(abonnement.secret);

Vérifiez toujours la signature. Sans elle, n'importe qui connaissant votre URL peut vous envoyer de faux appels d'offres. Elle se vérifie sur le corps brut, avant tout JSON.parse : un objet ré-sérialisé n'a plus les mêmes octets que celui qui a été signé.

import { verifierSignatureWebhook } from "@soumize/sdk";

export async function POST(request) {
  const brut = await request.text();
  const valide = await verifierSignatureWebhook(
    brut,
    request.headers.get("X-Soumize-Signature") ?? "",
    process.env.SOUMIZE_WEBHOOK_SECRET,
  );
  if (!valide) return new Response("signature invalide", { status: 400 });

  const { evenement, donnees } = JSON.parse(brut);
  // … répondez 2xx rapidement, traitez ensuite.
  return new Response("ok");
}

Répondez 2xx. Toute autre réponse est rejouée à 1, 5, 25 puis 125 minutes, puis abandonnée. Vingt échecs d'affilée désactivent l'abonnement : corrigez l'URL et recréez-le.

La charge reste mince : l'identifiant, de quoi décider, et le lien officiel. Pour l'objet complet, un GET /v1/consultations/{id} : vous obtenez ainsi la version à jour plutôt que celle figée au moment de l'événement.

L'URL doit être en https et publique. Les adresses privées, locales et réservées sont refusées dès la création, et revérifiées après résolution du nom avant chaque envoi.

Erreurs

Une enveloppe unique, quelle que soit la route. Testez type, jamais le message : le code est stable, le texte peut être reformulé.

{ "error": { "type": "portee_absente", "message": "…", "doc_url": "…" } }

Les données de marchés proviennent du portail public marchespublics.gov.ma. Soumize les collecte, les normalise et rapproche les variantes de dénomination d'un même acheteur ; elle ne les certifie pas. En cas d'écart, l'avis publié au portail fait foi.