Exemples¶
Cette page regroupe des exemples d'appels à l'API REST pour les opérations les plus courantes. Ils utilisent curl ; quelques exemples en PHP et en Python figurent en fin de page.
Dans les exemples :
- le jeton fictif
iwal_xxxxxxxxest à remplacer par votre propre jeton d'accès ; - les identifiants (
12345pour un service,678pour un client…) sont fictifs : remplacez-les par ceux renvoyés par l'API ; - les réponses sont abrégées.
Pour éviter de répéter le jeton, enregistrez-le dans une variable d'environnement :
Attention
Les appels sont réels : une création, une suppression ou une commande faite par l'API a le même effet que dans le manager iWal.
Vérifier son jeton¶
GET /v2/me (périmètre me:read) renvoie votre compte, ainsi que la méthode d'authentification et les périmètres du jeton utilisé :
{
"data": {
"id": 4321,
"login": "utilisateur",
"email": "contact@exemple.fr",
"auth": { "method": "token", "token_id": 42, "scopes": ["services:read", "billing:read"] }
},
"meta": {}
}
Lister ses services¶
GET /v2/services (périmètre services:read) liste les services que vous pouvez voir. Les services résiliés sont masqués, sauf avec include_terminated=1.
Filtres utiles :
| Paramètre | Effet |
|---|---|
client_id |
Services d'un client (titulaire) |
status |
Code de statut exact (par exemple 30 pour les services actifs) |
category_id |
Services d'une catégorie |
q |
Recherche sur le nom, la référence ou l'identifiant |
include_terminated=1 |
Inclure les services résiliés |
{
"data": [
{
"id": 12345,
"client_id": 678,
"reference": "...",
"name": "Hébergement exemple.fr",
"status": { "code": 30, "label": "OK", "detail": "Le service est actif. Aucun problème à signaler." },
"product": { "id": 10, "name": "...", "billing_frequency": "..." },
"category": { "id": 3, "label": "...", "type": "hosting_pack" },
"auto_renew_duration": 12,
"expires_at": "2027-03-01 00:00:00"
}
],
"meta": { "page": 1, "per_page": 100, "total": 1, "total_pages": 1 }
}
Le détail d'un service (avec vos rôles sur ce service et ses services rattachés) s'obtient avec GET /v2/services/{id} :
Astuce
Les libellés de tous les statuts sont disponibles avec GET /v2/meta/statuses?domain=service (valeurs de domain : service, user, right, client, orderform, billout).
Lire ses factures et bons de commande¶
Ces routes demandent le périmètre billing:read, et un rôle permettant de voir la facturation du client ou du service.
Lister les dernières factures :
Lister les bons de commande non payés (statut 2001) :
Les deux listes acceptent les filtres client_id, service_id (documents dont une ligne porte sur ce service), status (codes séparés par des virgules) et q (référence, référence comptable ou nom du titulaire).
Le détail d'une facture, avec ses lignes et ses paiements :
Télécharger la facture au format PDF :
curl -s -H "Authorization: Bearer $IWAL_TOKEN" \
-o facture-98765.pdf "$IWAL_API/billouts/98765/pdf"
Les bons de commande ont les mêmes routes : GET /v2/orderforms/{id} et GET /v2/orderforms/{id}/pdf.
Zones DNS : consulter et ajouter un enregistrement¶
Les zones DNS s'utilisent à partir d'un service d'hébergement ou d'un nom de domaine enregistré chez YULPA. Il faut les périmètres hosting:read (lecture) et hosting:write (modification), et un rôle technique sur le service.
Lister les domaines et leurs zones¶
{
"data": [
{
"domain_id": 555,
"domain": "exemple.fr",
"zone_id": 777,
"status": 30,
"secondaries": [],
"records": 12
}
],
"meta": {}
}
Le champ domain_id sert à désigner le domaine dans les routes suivantes. status vaut 30 pour une zone active (null si le domaine n'a pas de zone).
Lire les enregistrements d'une zone¶
{
"data": [
{ "id": 9001, "type": "A", "name": "www", "ttl": 0, "target": "203.0.113.10", "priority": 0, "weight": 0, "port": 0, "service": null, "protocol": null }
],
"meta": { "zone_status": 30 }
}
Ajouter un enregistrement¶
Ajouter un enregistrement A pour intranet.exemple.fr :
curl -s -X POST -H "Authorization: Bearer $IWAL_TOKEN" \
-H "Content-Type: application/json" \
-d '{"type": "A", "name": "intranet", "ttl": 3600, "target": "203.0.113.20"}' \
"$IWAL_API/services/12345/dns/zones/555/records"
Champs d'un enregistrement :
| Champ | Description |
|---|---|
type |
A, AAAA, CNAME, MX, TXT, SRV, NS ou CAA (obligatoire) |
name |
Nom relatif à la zone, par exemple intranet pour intranet.exemple.fr (obligatoire) |
target |
Cible : adresse IP, nom d'hôte ou texte (obligatoire) |
ttl |
0 (TTL de la zone, par défaut), 900, 1800, 3600, 7200, 10800, 14400, 21600, 28800, 43200, 86400 ou 172800 |
priority, weight |
MX et SRV |
port, protocol |
SRV (protocol : _tcp, _udp) |
service |
SRV (par exemple _sip) ou CAA (issue, issuewild, iodef) |
L'API applique les mêmes contrôles que le manager (syntaxe selon le type, doublons, CNAME exclusif…). La réponse 201 renvoie l'enregistrement créé ; la zone est ensuite régénérée sur nos serveurs DNS.
Pour modifier un enregistrement, utilisez PUT /v2/services/{id}/dns/zones/{domain_id}/records/{record_id} avec les mêmes champs ; pour le supprimer, DELETE sur la même adresse :
curl -s -X DELETE -H "Authorization: Bearer $IWAL_TOKEN" \
"$IWAL_API/services/12345/dns/zones/555/records/9002"
Pour en savoir plus sur les enregistrements DNS, voir Zones DNS.
Gérer une base MySQL¶
Ces routes concernent les bases MySQL d'un hébergement. Il faut les périmètres hosting:read et hosting:write, un rôle technique, et un service actif. Les créations et suppressions sont exécutées immédiatement sur le serveur MySQL.
Consulter les quotas et les serveurs¶
La réponse indique le préfixe ajouté automatiquement aux noms de bases et d'utilisateurs (prefix), les quotas (limits), l'utilisation (usage), les serveurs MySQL disponibles (servers, avec leur id) et la liste des droits attribuables (privileges_available).
Créer une base¶
curl -s -X POST -H "Authorization: Bearer $IWAL_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "boutique", "server_id": 3, "description": "Base de la boutique"}' \
"$IWAL_API/services/12345/mysql/databases"
Le nom s'indique sans le préfixe ; server_id est l'identifiant d'un des serveurs renvoyés par GET /v2/services/{id}/mysql.
Créer un utilisateur¶
curl -s -X POST -H "Authorization: Bearer $IWAL_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "boutique", "server_id": 3, "password": "MotDePasse-Solide-2026", "password_confirmation": "MotDePasse-Solide-2026"}' \
"$IWAL_API/services/12345/mysql/users"
Le champ host est facultatif (% par défaut). L'utilisateur doit être créé sur un serveur où l'hébergement a déjà une base active.
Donner des droits à l'utilisateur sur la base¶
curl -s -X POST -H "Authorization: Bearer $IWAL_TOKEN" \
-H "Content-Type: application/json" \
-d '{"database_id": 2001, "user_id": 3001, "privileges": ["ALL PRIVILEGES"]}' \
"$IWAL_API/services/12345/mysql/privileges"
database_id et user_id sont les identifiants renvoyés à la création (ou par GET .../mysql/databases et GET .../mysql/users). privileges vaut ["ALL PRIVILEGES"] (tous les droits sauf GRANT) ou une liste de droits, par exemple ["SELECT", "INSERT", "UPDATE", "DELETE"].
Changer le mot de passe d'un utilisateur¶
curl -s -X PUT -H "Authorization: Bearer $IWAL_TOKEN" \
-H "Content-Type: application/json" \
-d '{"password": "Nouveau-MotDePasse-2026", "password_confirmation": "Nouveau-MotDePasse-2026"}' \
"$IWAL_API/services/12345/mysql/users/3001/password"
Supprimer une base¶
curl -s -X DELETE -H "Authorization: Bearer $IWAL_TOKEN" \
"$IWAL_API/services/12345/mysql/databases/2001"
Danger
La suppression d'une base est immédiate et définitive sur le serveur MySQL. Pensez à en faire une copie avant.
Pour en savoir plus, voir Bases MySQL.
Renouveler un service : devis puis commande¶
Le renouvellement se fait en trois étapes : repérer les services à renouveler, obtenir un devis, puis passer commande. Le bon de commande créé se paie ensuite comme d'habitude (voir Payer).
1. Trouver l'identifiant du client¶
(périmètre clients:read). L'identifiant du client figure aussi dans chaque service (client_id).
2. Lister les services à renouveler¶
GET /v2/clients/{id}/renewals (périmètre billing:read) liste les services renouvelables du client, avec les durées possibles et leur prix. Par exemple, ceux qui arrivent à échéance dans moins de 30 jours :
{
"data": [
{
"service_id": 12345,
"name": "Hébergement exemple.fr",
"expires_at": "2026-12-01 00:00:00",
"pending_order": false,
"renewable": true,
"durations": [
{ "duration": 12, "default": true, "total_ht": 100.0, "total_ttc": 120.0 }
]
}
],
"meta": { "vat_rate": 20 }
}
Les montants de cet exemple sont fictifs. pending_order indique qu'une commande est déjà en cours pour ce service.
3. Demander un devis¶
POST /v2/orders/quote (périmètre billing:read) calcule les lignes et les totaux, sans rien enregistrer :
curl -s -X POST -H "Authorization: Bearer $IWAL_TOKEN" \
-H "Content-Type: application/json" \
-d '{"client_id": 678, "items": [{"type": "renew", "service_id": 12345, "duration": 12}]}' \
"$IWAL_API/orders/quote"
La réponse détaille chaque ligne (période couverte begins_at / ends_at, montants HT, TVA et TTC) et les totaux total_ht et total_ttc. En cas de problème sur un élément, l'erreur est indiquée dans errors (items.0, items.1…).
4. Passer commande¶
POST /v2/orders (périmètre billing:write) reçoit les mêmes données et crée le bon de commande. Avec send_mail, le bon de commande vous est aussi envoyé par mail :
curl -s -X POST -H "Authorization: Bearer $IWAL_TOKEN" \
-H "Content-Type: application/json" \
-d '{"client_id": 678, "items": [{"type": "renew", "service_id": 12345, "duration": 12}], "send_mail": true}' \
"$IWAL_API/orders"
La réponse 201 contient l'identifiant (orderform_id), la référence, le statut et les montants du bon de commande. Un service ne peut figurer que dans une seule commande en cours : sinon, l'API répond 409.
Il reste à payer le bon de commande depuis le manager iWal (voir Payer et Renouvellements).
Astuce
Pour ne plus avoir à renouveler un service à la main, réglez son renouvellement automatique : PATCH /v2/services/{id} avec {"auto_renew_duration": 12} (périmètre services:write, 0 pour le désactiver).
Vérifier la disponibilité d'un nom de domaine¶
GET /v2/domains/check (périmètre billing:read) vérifie qu'un nom de domaine est valide et disponible, et indique le produit à commander :
La réponse indique notamment :
action:createsi le domaine est libre (achat),transfers'il est déjà enregistré ailleurs (transfert possible) ;product: le produit correspondant, ses durées possibles et son prix ;requires: ce qu'il faudra fournir à la commande (identifiant WhoIs, code de transfert, acceptation de conditions particulières) ;conditions: un texte si l'extension est soumise à des conditions du registre.
Si le nom n'est pas commandable, l'API répond 400 avec la raison dans errors.name.
Note
Chaque vérification interroge le registrar : elle est limitée à 60 vérifications par utilisateur toutes les 10 minutes.
Pour commander un nom de domaine, voir Commander un domaine.
Exemples en PHP et en Python¶
<?php
// Liste des services actifs, avec l'extension cURL de PHP
$token = getenv('IWAL_TOKEN'); // iwal_xxxxxxxx
$ch = curl_init('https://my.yulpa.io/api/v2/services?status=30&per_page=100');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $token,
'Accept: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$json = json_decode($body, true);
if ($status !== 200) {
// Erreur au format application/problem+json
fwrite(STDERR, $json['title'] . ' : ' . ($json['detail'] ?? '') . PHP_EOL);
exit(1);
}
foreach ($json['data'] as $service) {
printf("%d\t%s\t%s\n", $service['id'], $service['name'], $service['expires_at'] ?? '-');
}
# Ajout d'un enregistrement DNS, avec la bibliothèque requests
import os
import requests
API = "https://my.yulpa.io/api/v2"
session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['IWAL_TOKEN']}" # iwal_xxxxxxxx
response = session.post(
f"{API}/services/12345/dns/zones/555/records",
json={"type": "TXT", "name": "verification", "ttl": 3600, "target": "valeur-de-verification"},
)
if response.status_code == 201:
print("Enregistrement ajouté :", response.json()["data"]["id"])
else:
problem = response.json() # application/problem+json
print(problem["title"], problem.get("detail"), problem.get("errors"))
Parcourir toutes les pages d'une liste¶
import os
import requests
API = "https://my.yulpa.io/api/v2"
headers = {"Authorization": f"Bearer {os.environ['IWAL_TOKEN']}"}
page = 1
while True:
r = requests.get(f"{API}/billouts", headers=headers, params={"page": page, "per_page": 100})
r.raise_for_status()
body = r.json()
for billout in body["data"]:
print(billout["reference"], billout["issued_at"], billout["amount_ttc"])
if page >= body["meta"]["total_pages"]:
break
page += 1