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