Aller au contenu principal

Créer un dossier depuis un formulaire

Ce guide vous montre comment créer un dossier bénéficiaire dans téo à partir d'un formulaire web (site internet, landing page, etc.).

Cas d'usage​

Vous souhaitez :

  • Permettre aux visiteurs de votre site de s'inscrire à une formation
  • Automatiser la création de dossiers depuis un CRM externe
  • Intégrer téo avec un outil de marketing automation

Prérequis​

Vue d'ensemble​

Sécurité

N'exposez jamais vos identifiants API côté client (JavaScript navigateur). Utilisez toujours un backend pour communiquer avec l'API téo.

Étape 1 : Collecter les données​

Créez un formulaire avec les champs nécessaires. Voici les champs minimums pour créer un dossier :

<form action="/api/inscription" method="POST">
<input type="text" name="firstName" placeholder="Prénom" required />
<input type="text" name="lastName" placeholder="Nom" required />
<input type="email" name="email" placeholder="Email" required />
<input type="tel" name="phone" placeholder="Téléphone" />

<!-- Prestation cachée ou en select -->
<input type="hidden" name="serviceId" value="UUID_DE_LA_PRESTATION" />

<button type="submit">S'inscrire</button>
</form>

Étape 2 : Traiter les données côté serveur​

Exemple Node.js (Express)​

const express = require('express');
const app = express();

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// Configuration
const TEO_API = 'https://teoapp.fr/api';
const CLIENT_ID = process.env.TEO_CLIENT_ID;
const CLIENT_SECRET = process.env.TEO_CLIENT_SECRET;
const TEO_ID = process.env.TEO_ID;

// Cache du token
let tokenCache = { token: null, expiresAt: 0 };

async function getAccessToken() {
// Réutiliser le token s'il est encore valide
if (tokenCache.token && Date.now() < tokenCache.expiresAt) {
return tokenCache.token;
}

const credentials = Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString('base64');

const response = await fetch('https://auth.teoapp.fr/oauth2/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': `Basic ${credentials}`
},
body: `grant_type=client_credentials&scope=target-entity:${TEO_ID}`
});

const data = await response.json();

// Mettre en cache (expire 1 minute avant pour éviter les erreurs)
tokenCache = {
token: data.access_token,
expiresAt: Date.now() + (data.expires_in - 60) * 1000
};

return data.access_token;
}

app.post('/api/inscription', async (req, res) => {
try {
const { firstName, lastName, email, phone, serviceId } = req.body;

// Validation basique
if (!firstName || !lastName || !email || !serviceId) {
return res.status(400).json({ error: 'Champs obligatoires manquants' });
}

const token = await getAccessToken();

// Créer le dossier dans téo
const response = await fetch(`${TEO_API}/production/dossiers`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
'Accept': 'application/ld+json'
},
body: JSON.stringify({
firstName,
lastName,
email,
phone: phone || null,
service: `/api/production/services/${serviceId}`
})
});

if (!response.ok) {
const error = await response.json();
console.error('Erreur API téo:', error);
return res.status(response.status).json({
error: 'Erreur lors de la création du dossier',
details: error
});
}

const dossier = await response.json();

res.json({
success: true,
message: 'Inscription enregistrée',
dossierId: dossier.id
});

} catch (error) {
console.error('Erreur serveur:', error);
res.status(500).json({ error: 'Erreur interne' });
}
});

app.listen(3000);

Exemple PHP​

<?php

// Configuration
define('TEO_API', 'https://teoapp.fr/api');
define('CLIENT_ID', getenv('TEO_CLIENT_ID'));
define('CLIENT_SECRET', getenv('TEO_CLIENT_SECRET'));
define('TEO_ID', getenv('TEO_ID'));

// Cache simple en session (utilisez Redis/Memcached en production)
session_start();

function getAccessToken(): string
{
// Vérifier le cache
if (isset($_SESSION['teo_token']) && $_SESSION['teo_token_expires'] > time()) {
return $_SESSION['teo_token'];
}

$credentials = base64_encode(CLIENT_ID . ':' . CLIENT_SECRET);

$ch = curl_init('https://auth.teoapp.fr/oauth2/token');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/x-www-form-urlencoded',
"Authorization: Basic $credentials"
],
CURLOPT_POSTFIELDS => 'grant_type=client_credentials&scope=target-entity:' . TEO_ID
]);

$response = json_decode(curl_exec($ch));
curl_close($ch);

// Mettre en cache
$_SESSION['teo_token'] = $response->access_token;
$_SESSION['teo_token_expires'] = time() + $response->expires_in - 60;

return $response->access_token;
}

function createDossier(array $data): array
{
$token = getAccessToken();

$ch = curl_init(TEO_API . '/production/dossiers');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer $token",
'Content-Type: application/json',
'Accept: application/ld+json'
],
CURLOPT_POSTFIELDS => json_encode($data)
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

return [
'success' => $httpCode === 201,
'code' => $httpCode,
'data' => json_decode($response, true)
];
}

// Traitement du formulaire
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$firstName = trim($_POST['firstName'] ?? '');
$lastName = trim($_POST['lastName'] ?? '');
$email = trim($_POST['email'] ?? '');
$phone = trim($_POST['phone'] ?? '');
$serviceId = $_POST['serviceId'] ?? '';

// Validation
if (empty($firstName) || empty($lastName) || empty($email) || empty($serviceId)) {
http_response_code(400);
echo json_encode(['error' => 'Champs obligatoires manquants']);
exit;
}

if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
http_response_code(400);
echo json_encode(['error' => 'Email invalide']);
exit;
}

// Créer le dossier
$result = createDossier([
'firstName' => $firstName,
'lastName' => $lastName,
'email' => $email,
'phone' => $phone ?: null,
'service' => "/api/production/services/$serviceId"
]);

if ($result['success']) {
echo json_encode([
'success' => true,
'message' => 'Inscription enregistrée',
'dossierId' => $result['data']['id']
]);
} else {
http_response_code($result['code']);
echo json_encode([
'error' => 'Erreur lors de la création',
'details' => $result['data']
]);
}
}

Exemple Python (Flask)​

import os
import time
import requests
from flask import Flask, request, jsonify

app = Flask(__name__)

# Configuration
TEO_API = 'https://teoapp.fr/api'
CLIENT_ID = os.environ['TEO_CLIENT_ID']
CLIENT_SECRET = os.environ['TEO_CLIENT_SECRET']
TEO_ID = os.environ['TEO_ID']

# Cache du token
token_cache = {'token': None, 'expires_at': 0}

def get_access_token():
global token_cache

# Réutiliser le token s'il est encore valide
if token_cache['token'] and time.time() < token_cache['expires_at']:
return token_cache['token']

import base64
credentials = base64.b64encode(f"{CLIENT_ID}:{CLIENT_SECRET}".encode()).decode()

response = requests.post(
'https://auth.teoapp.fr/oauth2/token',
headers={
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': f'Basic {credentials}'
},
data=f'grant_type=client_credentials&scope=target-entity:{TEO_ID}'
)

data = response.json()

# Mettre en cache
token_cache = {
'token': data['access_token'],
'expires_at': time.time() + data['expires_in'] - 60
}

return data['access_token']

@app.route('/api/inscription', methods=['POST'])
def inscription():
data = request.form

first_name = data.get('firstName', '').strip()
last_name = data.get('lastName', '').strip()
email = data.get('email', '').strip()
phone = data.get('phone', '').strip()
service_id = data.get('serviceId', '')

# Validation
if not all([first_name, last_name, email, service_id]):
return jsonify({'error': 'Champs obligatoires manquants'}), 400

try:
token = get_access_token()

response = requests.post(
f'{TEO_API}/production/dossiers',
headers={
'Authorization': f'Bearer {token}',
'Content-Type': 'application/json',
'Accept': 'application/ld+json'
},
json={
'firstName': first_name,
'lastName': last_name,
'email': email,
'phone': phone or None,
'service': f'/api/production/services/{service_id}'
}
)

if response.status_code == 201:
dossier = response.json()
return jsonify({
'success': True,
'message': 'Inscription enregistrée',
'dossierId': dossier['id']
})
else:
return jsonify({
'error': 'Erreur lors de la création',
'details': response.json()
}), response.status_code

except Exception as e:
return jsonify({'error': str(e)}), 500

if __name__ == '__main__':
app.run(port=3000)

Étape 3 : Champs disponibles​

Voici les principaux champs que vous pouvez envoyer lors de la création d'un dossier :

ChampTypeObligatoireDescription
firstNamestringOuiPrénom du bénéficiaire
lastNamestringOuiNom du bénéficiaire
emailstringOuiEmail du bénéficiaire
phonestringNonTéléphone
serviceIRIOuiRéférence à la prestation (format /api/production/services/{uuid})
birthDatedateNonDate de naissance (format YYYY-MM-DD)
addressstringNonAdresse postale
postalCodestringNonCode postal
citystringNonVille
Champs personnalisés

Pour ajouter des données spécifiques à votre téo, utilisez la propriété data. Contactez le support pour connaître les champs disponibles.

Gestion des erreurs​

Doublons​

Si un dossier existe déjà avec le même email pour la même prestation, l'API retournera une erreur 422.

if (response.status === 422) {
const error = await response.json();
if (error.violations?.some(v => v.message.includes('doublon'))) {
return res.status(409).json({
error: 'Un dossier existe déjà avec cet email'
});
}
}

Prestation invalide​

Si l'UUID de prestation est incorrect ou la prestation n'est pas accessible :

if (response.status === 400 || response.status === 404) {
console.error('Prestation invalide:', serviceId);
// Vérifiez l'UUID dans téo (voir guide Identifiants)
}

Bonnes pratiques​

  1. Validez côté client ET serveur - Ne faites jamais confiance aux données du formulaire
  2. Utilisez HTTPS - Toutes les communications doivent être chiffrées
  3. Limitez les tentatives - Implémentez un rate limiting pour éviter les abus
  4. Loggez les erreurs - Conservez une trace pour le debugging
  5. Confirmez l'inscription - Envoyez un email de confirmation au bénéficiaire

Aller plus loin​