Documentation

Le manuel de votre tableau

Une page, trois couloirs : commencez ici, passez le deuxième à qui traite les dossiers, et envoyez le troisième à qui écrit le code.

COMMENCEZ ICI

Pour qui administre

Activez la formule, invitez votre équipe, définissez votre préfixe de dossiers et pilotez la facturation.

Guide de démarrage →
VOTRE SITE WEB

Pour qui publie le site

Trois widgets intégrables en une ligne de script : contact, ouverture de dossiers et tableau du client final.

Widgets →
INTÉGRATION

Pour qui intègre

API REST avec clés dédiées, webhooks signés et synchronisation incrémentale.

Référence de l’API →

Qu’est-ce que le tableau

Un tableau de support multi-marque : vous servez VOS clients, sous VOTRE marque, sur notre infrastructure.

Le tableau de support est une file unique de dossiers pour votre opération : vos clients ouvrent des dossiers depuis votre site (widgets), par API ou par e-mail, et votre équipe les traite depuis un panneau dédié sur dash.elportaldelcliente.com. Chaque dossier entre, avance et escalade même quand tout le monde dort — mais ne se conclut pas sans un nom derrière.

Votre tableau est un locataire isolé : vos dossiers, vos clients finaux et vos agents ne se mélangent avec ceux de personne d’autre. L’isolation fait partie de la conception du système, pas d’une configuration que l’on pourrait oublier. Si notre personnel touche à l’un de vos dossiers en support de dernier niveau, l’accès est consigné et vous pouvez le consulter.

Vos clients n’ont pas besoin de compte chez nous. Ils s’adressent à votre marque : le widget, votre site et votre e-mail. C’est vous qui détenez le compte (et le contrôle).

Guide de démarrage

De zéro à opérationnel, en cinq étapes.

  1. Créez votre compte sur dash.elportaldelcliente.com.
  2. Activez une formule. Elle se paie avec le solde de votre compte (le même portefeuille pour tout l’écosystème) ; s’il en manque, l’écran vous propose de recharger exactement le montant manquant.
  3. Invitez vos agents dans l’onglet « Agents » : e-mail et rôle (agent ou administrateur). Vous recevrez un lien d’accès à leur remettre.
  4. Activez un widget dans « Widgets et API » : enregistrez le domaine de votre site comme origine autorisée, copiez le script et collez-le sur votre site.
  5. Vous intégrez par le code ? Émettez votre clé tab_live_ dans le même onglet et suivez la référence de l’API sur cette page.
Votre préfixe de dossiers : dans « Widgets et API », vous pouvez définir 4 lettres à vous (par exemple ACME) et vos dossiers seront numérotés ACME-1044. Les dossiers déjà émis ne sont pas renumérotés.

Le panneau du tableau

Le panneau du locataire sur dash.elportaldelcliente.com, onglet par onglet.

OngletCe qu’il fait
RésuméÉtat de votre abonnement, échéance, renouvellement et renouvellement automatique. C’est aussi ici que l’on résilie.
AgentsInviter par e-mail avec un rôle d’agent ou d’administrateur ; changer les rôles ; retirer l’accès. Le titulaire reste protégé.
Widgets et APIPréfixe de dossiers, origines autorisées (CORS), les trois widgets avec leur script, et les clés de l’API.
Accès du fournisseurL’audit : chaque accès de notre personnel à vos dossiers, avec qui, quoi et quand.

Les agents que vous invitez voient et traitent les dossiers de votre tableau ; les administrateurs gèrent en plus l’abonnement, l’équipe et les intégrations.

Widgets pour votre site

Trois widgets, une ligne de script chacun. Sans iframes tiers, sans cookies de suivi.

Dans l’onglet « Widgets et API » de votre panneau : activez le widget, enregistrez le domaine de votre site comme origine autorisée et copiez le script généré. Le paramètre data-color accepte votre couleur de marque.

<script src="https://api.elportaldelcliente.com/api/tablero/widget/tablero.js"
        data-tenant="su-tablero" data-widget="contacto" data-color="#a177ff"></script>
data-widgetCe qu’il faitPrérequis
contactoFormulaire de contact : nom, e-mail et message. Crée un dossier dans votre tableau.Widget activé + origine autorisée
abrir-casoOuverture de dossiers avec objet : renvoie le numéro de dossier au visiteur.Widget activé + origine autorisée
tableroTableau du client final : il voit ses dossiers, en ouvre de nouveaux et répond depuis votre site.Ce qui précède + jeton client (ci-dessous)

Protections du widget

Les widgets anonymes acceptent 10 tentatives par visiteur (IP) toutes les 10 minutes et par tableau. Si le widget est désactivé, si l’origine n’est pas autorisée ou si l’abonnement a expiré, le widget répond 404 widget no disponible — indiscernable à dessein, pour ne pas révéler la configuration de votre tableau.

Le widget « tablero » : identifier votre client

Le widget de tableau montre à chaque client final uniquement ses propres dossiers. Pour cela, votre serveur échange un jeton éphémère par client : appelez POST /v1/clientes/:ref/token-widget avec votre clé d’API (côté serveur, jamais depuis le navigateur) et remettez le jeton au widget.

curl -X POST https://api.elportaldelcliente.com/api/tablero/v1/clientes/cli-842/token-widget \
  -H "Authorization: Bearer $TABLERO_KEY"

HTTP/1.1 201
{"success":true,"data":{"token":"tabw_…","expires_at":"2026-08-18 21:15:00"}}
window.TableroPortal.setToken(token);
Le jeton tabw_ vit 15 minutes et ne se rafraîchit pas. À son expiration, le widget recevra 401 token_vencido : échangez-en un autre. N’exposez jamais votre clé tab_live_ dans le navigateur — le jeton éphémère existe exactement pour cela.

Clés de l’API

Une clé Bearer par intégration, à portée restreinte et révocable.

Les clés s’émettent depuis votre panneau (« Widgets et API » → « Clés de l’API »). Elles ont la forme tab_live_… et ne s’affichent qu’une seule fois : conservez-les dans votre gestionnaire de secrets. Nous n’en stockons que le hash.

curl -H "Authorization: Bearer tab_live_…" \
  https://api.elportaldelcliente.com/api/tablero/v1/

À l’émission, vous pouvez restreindre ses scopes. Une clé sans scopes explicites a accès à tout votre tableau :

ScopeAutorise
casos.readLire les dossiers et leurs réponses
casos.writeCréer des dossiers, répondre et changer le statut/la priorité
clientes.readLire vos clients finaux
clientes.writeCréer/désactiver des clients finaux et émettre des jetons de widget
departamentos.manageLire et administrer les départements (boîtes IMAP comprises)
webhooks.manageLire et administrer les webhooks
accesos.readLire l’audit des accès du fournisseur
  • Maximum 5 clés actives par tableau. Révoquez celles que vous n’utilisez plus.
  • La clé identifie votre tableau : n’envoyez jamais tenant_id dans le corps — l’API le rejette avec un 400.
  • Abonnement expiré : la clé continue de lire (GET) ; toute écriture répond 402 suscripcion_vencida.
  • Une clé révoquée répond 401 immédiatement sur toutes les routes.
Côté serveur uniquement. La clé tab_live_ ne va jamais dans le navigateur, dans une app mobile ni dans un dépôt. Pour le navigateur, il y a le jeton éphémère tabw_.

Référence de l’API

REST sur HTTPS, JSON dans les deux sens, réponses de la forme {success, data}.

Conventions : les corps s’envoient en Content-Type: application/json ; les dates sont en UTC YYYY-MM-DD HH:MM:SS ; les listes paginées renvoient total, page et limit. Ce qui n’est pas à vous répond 404, jamais 403 : l’API ne confirme pas l’existence de ressources d’autrui.

https://api.elportaldelcliente.com/api/tablero/v1

Racine : identité, formule et usage

GET / est le contrat qui ne peut pas mentir : il renvoie qui vous êtes, les scopes de cette clé, votre formule avec ses limites, l’état de votre abonnement et votre consommation en cours.

curl -H "Authorization: Bearer $TABLERO_KEY" \
  https://api.elportaldelcliente.com/api/tablero/v1/

{"success":true,"data":{
  "tenant":{"slug":"su-tablero","nombre":"Su Marca"},
  "scopes_de_esta_credencial":["casos.read","casos.write"],
  "plan":{"id":"tablero-base","nombre":"BASE","limites":{"max_agentes":5,"max_departamentos":5,"max_articulos_kb":100}},
  "suscripcion":{"estado":"active","current_period_end":"2027-08-18"},
  "uso":{"agentes":3,"departamentos":2},
  "recursos":["/casos","/clientes","/departamentos","/accesos","/webhooks"],
  "version":"v1"}}

Clients finaux

Un client final est un client à vous (pas un compte de notre écosystème). Il s’identifie par external_ref : l’ID que ce client porte dans VOTRE système.

MéthodeRouteScopeCe qu’il fait
GET/clientesclientes.readLister les clients (jusqu’à 500, les plus récents d’abord)
POST/clientesclientes.writeCréer ou mettre à jour par external_ref (upsert idempotent)
GET/clientes/:refclientes.readLire un client par son external_ref
DELETE/clientes/:refclientes.writeDésactiver (sans supprimer : l’historique des dossiers est conservé)
POST/clientes/:ref/token-widgetclientes.writeÉmettre un jeton éphémère pour le widget « tablero » (15 min)
curl -X POST https://api.elportaldelcliente.com/api/tablero/v1/clientes \
  -H "Authorization: Bearer $TABLERO_KEY" \
  -H "Content-Type: application/json" \
  -d '{"external_ref":"cli-842","email":"[email protected]","name":"Maria Rojas"}'
Réessais sûrs : POST /clientes est un upsert par external_ref — répéter l’appel ne duplique pas les clients. À la création de dossiers, en revanche, un réessai réseau crée un nouveau dossier : ne réessayez que si vous n’avez pas reçu de réponse.

Dossiers

La ressource centrale. Un dossier a un statut, une priorité, un client final facultatif et une conversation de réponses. Les notes internes des agents ne sont jamais exposées par l’API.

MéthodeRouteScopeCe qu’il fait
GET/casoscasos.readLister avec filtres : statut, client, updated_since, limit (1-100), page
POST/casoscasos.writeCréer un dossier (subject requis ; cliente_ref, priority, department_id, body/body_html facultatifs)
GET/casos/:idcasos.readDétail avec la conversation complète (réponses ordonnées). Accepte l’ID ou le numéro du dossier (ex. SOLC-1051) indifféremment
POST/casos/:id/respuestascasos.writeRépondre au nom de votre équipe, ou au nom du client avec en_nombre_de
PATCH/casos/:idcasos.writeChanger status et/ou priority

Créer un dossier lié à un client final :

curl -X POST https://api.elportaldelcliente.com/api/tablero/v1/casos \
  -H "Authorization: Bearer $TABLERO_KEY" \
  -H "Content-Type: application/json" \
  -d '{"subject":"No puedo entrar al panel","cliente_ref":"cli-842","priority":"high",
       "body":"Al iniciar sesion la pagina queda en blanco."}'

HTTP/1.1 201
{"success":true,"data":{"id":"…","numero":"SOLC-1051"}}

Lister avec filtres, et synchronisation incrémentale avec updated_since (ISO 8601) : dans ce mode, l’ordre est updated_at croissant, pensé pour avancer page par page sans perdre de changements. Conservez le updated_at le plus élevé traité et utilisez-le comme curseur de la passe suivante.

curl -H "Authorization: Bearer $TABLERO_KEY" \
  "https://api.elportaldelcliente.com/api/tablero/v1/casos?estado=open&cliente=cli-842&limit=50&page=1"

# synchronisation incrementale (ordre : updated_at croissant)
curl -H "Authorization: Bearer $TABLERO_KEY" \
  "https://api.elportaldelcliente.com/api/tablero/v1/casos?updated_since=2026-08-18T00:00:00Z&limit=100"
Un filtre qui ne filtre pas est pire qu'une erreur : un estado hors de la liste valide (ou tout paramètre non reconnu) répond 400 avec le détail — jamais ignoré silencieusement, ni renvoyé comme liste complète sans avertissement.

Répondre à un dossier. Sans en_nombre_de, la réponse est signée par votre équipe (author_type: agent) ; avec en_nombre_de, elle est signée par ce client final (author_type: client) :

curl -X POST https://api.elportaldelcliente.com/api/tablero/v1/casos/$CASO_ID/respuestas \
  -H "Authorization: Bearer $TABLERO_KEY" \
  -H "Content-Type: application/json" \
  -d '{"body":"Ya lo revisamos: intente de nuevo.","autor_nombre":"Soporte Acme"}'

# ...ou au nom du client final :
  -d '{"body":"Sigue igual desde mi lado.","en_nombre_de":"cli-842"}'
ChampValeurs
statusopen · pending · resolved · closed
prioritylow · medium · high · urgent
author_typeclient · agent
Isolation vérifiable : toute requête de dossiers passe par le périmètre de votre locataire côté serveur. Un ID de dossier d’un autre tableau répond 404 — l’API se comporte comme s’il n’existait pas, parce que pour vous il n’existe pas.

Départements

Les files internes de votre tableau (ventes, facturation, technique…). Chacune peut avoir sa propre boîte IMAP : le tableau la sonde et convertit les e-mails entrants en dossiers.

MéthodeRouteScopeCe qu’il fait
GET/departamentosdepartamentos.manageLister les départements (configuration e-mail incluse, sans le mot de passe)
POST/departamentosdepartamentos.manageCréer (name requis ; boîte IMAP facultative ; soumis à la limite de la formule)
PUT/departamentos/:iddepartamentos.manageModifier n’importe quel champ ; email_password vide efface le mot de passe enregistré
DELETE/departamentos/:iddepartamentos.manageArchiver (les dossiers existants restent intacts)

La boîte parle toujours IMAP (email_protocol: imap) ; le mot de passe est chiffré au repos et jamais renvoyé. Avec email_polling_enabled: 1, le sondage s’exécute automatiquement.

Audit des accès

Chaque accès de notre personnel aux dossiers de votre tableau est consigné. C’est le même audit que l’onglet « Accès du fournisseur », lisible par API :

curl -H "Authorization: Bearer $TABLERO_KEY" \
  https://api.elportaldelcliente.com/api/tablero/v1/accesos

Webhooks

Votre système est prévenu à l’instant même : chaque événement part signé vers votre URL HTTPS.

ÉvénementSe déclenche quand
caso.creadoUn dossier naît dans votre tableau — par API, par widget ou par e-mail entrant
caso.respondidoQuelqu’un répond : votre équipe (depuis le panneau ou l’API), ou votre client final (widget, API ou e-mail)
caso.estado_cambiadoLe statut d’un dossier change (par votre équipe, par l’API ou par notre système)

Enregistrez autant que nécessaire avec POST /webhooks : une URL https, les événements voulus et un secret d’au moins 16 caractères avec lequel nous signerons chaque livraison.

curl -X POST https://api.elportaldelcliente.com/api/tablero/v1/webhooks \
  -H "Authorization: Bearer $TABLERO_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://su-sistema.com/hooks/tablero",
       "eventos":["caso.creado","caso.respondido","caso.estado_cambiado"],
       "secret":"un-secreto-de-al-menos-16-caracteres"}'

Chaque livraison est un POST avec l’événement, le moment d’émission et les données minimales pour réagir. La signature couvre timestamp.corps :

POST /hooks/tablero
Content-Type: application/json
X-Tablero-Evento: caso.respondido
X-Tablero-Timestamp: 1765432100
X-Tablero-Firma: 3f1a…  # HMAC-SHA256(secret, timestamp + "." + corps)

{"evento":"caso.respondido","emitido_at":"2026-08-18T20:15:00.000Z",
 "data":{"caso_id":"…","numero":"SOLC-1051","respuesta_id":"…","autor_tipo":"agent"}}

Vérifier la signature

Rejetez toute livraison dont la signature ne se vérifie pas ou dont le timestamp s’écarte de plus de 5 minutes de l’horloge. Comparez en temps constant.

// Node.js
const crypto = require('node:crypto');

function verificarFirma(rawBody, headers, secret) {
  const ts  = headers['x-tablero-timestamp'];
  const sig = headers['x-tablero-firma'];
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
  const esperado = crypto.createHmac('sha256', secret)
    .update(ts + '.' + rawBody).digest('hex');
  return sig.length === esperado.length &&
    crypto.timingSafeEqual(Buffer.from(esperado), Buffer.from(sig));
}
# Python
import hashlib, hmac, time

def verificar_firma(raw_body: bytes, headers: dict, secret: str) -> bool:
    ts  = headers.get("x-tablero-timestamp", "")
    sig = headers.get("x-tablero-firma", "")
    if abs(time.time() - float(ts or 0)) > 300:
        return False
    esperado = hmac.new(secret.encode(), f"{ts}.".encode() + raw_body,
                        hashlib.sha256).hexdigest()
    return hmac.compare_digest(esperado, sig)

Sémantique de livraison (à lire avant de s’y fier)

  • Une tentative par événement, sans réessais. Si votre endpoint ne répond pas 2xx en 10 secondes, cette livraison est perdue — l’état réel reste toujours relisible par l’API.
  • Votre filet de sécurité est la synchronisation incrémentale : une passe périodique de GET /casos?updated_since=… récupère tout événement perdu.
  • GET /webhooks expose fail_count, last_ok_at et last_error_at pour chaque webhook : consultez-les au débogage.
  • Les événements s’émettent quelle que soit la voie : API, widgets, le panneau de votre équipe, notre personnel ou l’e-mail entrant de votre client final.

Erreurs

Erreurs JSON avec success:false ; le code HTTP fait foi.

{"success":false,"error":"…"}
HTTPSignification
400Requête invalide : un champ requis manque ou une valeur échoue à la validation
401Clé absente, invalide ou révoquée
402Abonnement expiré : lecture seule jusqu’au renouvellement (suscripcion_vencida)
403La clé n’a pas le scope qu’exige l’endpoint
404N’existe pas pour vous : les ressources d’autrui et les routes inexistantes répondent à l’identique
409Conflit : limite de la formule atteinte ou slug déjà utilisé
429Trop de tentatives (widgets anonymes : 10 par IP toutes les 10 minutes)
500Erreur de notre côté ; si elle persiste, écrivez-nous en précisant l’heure exacte

Les messages d’error sont du texte lisible par des humains et peuvent changer. Aiguillez votre code sur le code HTTP et sur ces slugs stables :

Slug stableSignification
suscripcion_vencida402 sur les écritures quand l’abonnement a expiré
token_vencido401 du widget « tablero » quand le jeton tabw_ a expiré : échangez-en un autre
saldo_insuficiente402 du panneau à l’activation/au renouvellement sans solde suffisant

Formules

Cinq formules annuelles, le même tableau. La différence, c’est combien de personnes et de structure y tiennent.

Les tarifs en vigueur se publient sur la page principale et par API publique (GET /api/public/tablero/plans). Toutes les formules incluent dossiers illimités, widgets, API, webhooks et audit des accès.

FormuleAgentsDépartementsArticles de KB
ZERO2225
BASE55100
PLUS1010250
PRO2015500
MAX50251000
Sans essai gratuit, à dessein. La formule ZERO existe pour commencer petit avec un engagement réel. L’activation débite l’année complète du solde de votre compte.

À l’échéance de votre abonnement s’ouvre une période de grâce ; ensuite le tableau passe en lecture seule (les GET continuent de répondre, les écritures renvoient 402). Vos données ne sont pas supprimées.

Limites opérationnelles

  • Dossiers : illimités dans toutes les formules. Les listes acceptent un limit de 1 à 100 par page.
  • Clients finaux et audit : les listes renvoient jusqu’à 500 lignes (les plus récentes d’abord). Utilisez GET /clientes/:ref pour des lectures ponctuelles.
  • Clés : jusqu’à 5 actives par tableau.
  • Widgets anonymes : 10 tentatives par visiteur (IP) toutes les 10 minutes.
  • Pièces jointes : l’API n’accepte pas encore de fichiers ; les pièces jointes des e-mails entrants sont conservées avec le dossier.

L’API principale n’impose pas aujourd’hui de quota rigide d’appels ; opérez à un rythme raisonnable (pauses entre les pages, réessais avec attente exponentielle). Si une intégration a besoin d’un volume garanti, parlons-en d’abord.