Documentation PunchOut
Cette page résume le fonctionnement d’un catalogue PunchOut. Les noms de champs OCI et cXML, ainsi que les exemples de code, restent dans leur forme d’origine.
1. Principe de base
Un PunchOut relie l’application d’achat de l’entreprise (ERP, e-procurement) au site marchand d’un fournisseur. L’acheteur ne ressaisit pas le catalogue : il « sort » vers la boutique du fournisseur, déjà reconnu, puis revient avec un panier structuré. La commande proprement dite reste ensuite dans le circuit d’approbation de l’acheteur.
Les deux rôles sont stables :
- Acheteur — tient les comptes, les habilitations, les validations et le bon de commande. C’est lui qui ouvre la session et qui reçoit le panier.
- Fournisseur — héberge le catalogue, les prix négociés et le stock. Il authentifie la session grâce aux identifiants transmis au départ, puis renvoie les articles choisis.
Session
Chaque visite est une session. L’acheteur y place un jeton (BuyerCookie en cXML, ou simplement le couple HOOK_URL + paramètres de contrôle en OCI). Le fournisseur doit le restituer au retour pour que le panier soit rattaché au bon utilisateur et à la bonne demande.
Retour panier
Le paiement n’a pas lieu sur le site fournisseur. L’utilisateur clique sur un bouton du type « retourner vers l’achat ». Le navigateur poste alors le contenu du panier vers une URL de callback fournie au début : HOOK_URL pour OCI, BrowserFormPost pour cXML. L’acheteur transforme ces lignes en demande d’achat.
- L’employé ouvre son outil d’achat et choisit un fournisseur PunchOut.
- L’outil transmet une demande de session (formulaire OCI ou message cXML).
- Le fournisseur reconnaît le compte et affiche son catalogue, sans nouvel identifiant saisi par l’employé.
- L’employé compose son panier.
- Le site fournisseur renvoie les lignes vers l’outil d’achat.
- L’employé soumet la demande ; plus tard, un bon de commande peut être transmis au fournisseur.
Deux standards couvrent l’essentiel des déploiements actuels. cXML est le plus répandu auprès des plateformes d’e-procurement. OCI (Open Catalog Interface) vient de l’écosystème SAP. Le scénario fonctionnel est le même ; le format des messages change.
2. PunchOut OCI
OCI est un échange HTTP de formulaires. L’ERP ouvre le catalogue en envoyant le navigateur de l’utilisateur vers l’URL du fournisseur, en POST le plus souvent, parfois en GET. Il n’y a pas d’enveloppe XML pour l’aller : ce sont des champs nommés.
Champs typiques à l’aller
| Champ | Rôle |
|---|---|
HOOK_URL | Adresse où le fournisseur doit poster le panier. Sans elle, le retour ne sait pas où revenir. |
USERNAME / PASSWORD | Compte technique du client chez le fournisseur. Ce ne sont pas les identifiants personnels de l’employé. |
~OkCode | Code de fonction SAP. ADDI signifie en pratique « ajouter les articles à la demande ». D’autres codes existent selon le scénario. |
~CALLER | Origine de l’appel. CTLG indique un appel depuis le catalogue. |
~TARGET | Cible de navigation HTML (_top, _parent…). Utile quand le catalogue était affiché dans un cadre. |
OCI_VERSION | Version du dialecte OCI attendue, souvent 4.0. |
D’autres champs circulent selon les projets : charset, société, langue, centre de coûts. Le fournisseur les lit s’il les connaît et ignore le reste.
Formulaire d’ouverture
Exemple illustratif, à adapter. Les valeurs ne correspondent à aucun compte réel.
<form method="post" action="https://fournisseur.exemple/oci"> <input type="hidden" name="USERNAME" value="compte-client"> <input type="hidden" name="PASSWORD" value="secret-exemple"> <input type="hidden" name="HOOK_URL" value="https://achat.exemple/oci/retour"> <input type="hidden" name="~OkCode" value="ADDI"> <input type="hidden" name="~CALLER" value="CTLG"> <input type="hidden" name="~TARGET" value="_top"> <input type="hidden" name="OCI_VERSION" value="4.0"> </form>
Retour panier
Le fournisseur répond par un POST vers HOOK_URL. Chaque article est un indice entre crochets, en commençant généralement à 1. Le nom du champ porte à la fois la donnée et le numéro de ligne.
| Champ | Contenu |
|---|---|
NEW_ITEM-DESCRIPTION[n] | Libellé affiché à l’acheteur |
NEW_ITEM-QUANTITY[n] | Quantité |
NEW_ITEM-UNIT[n] | Unité (PCE, EA, KG…) |
NEW_ITEM-PRICE[n] | Prix unitaire |
NEW_ITEM-CURRENCY[n] | Devise |
NEW_ITEM-VENDORMAT[n] | Référence article chez le fournisseur |
NEW_ITEM-MATGROUP[n] | Groupe de marchandises ou code de classement |
NEW_ITEM-MANUFACTCODE[n] | Code fabricant |
NEW_ITEM-MANUFACTMAT[n] | Référence fabricant |
NEW_ITEM-LEADTIME[n] | Délai, souvent en jours |
NEW_ITEM-DESCRIPTION[1]=Ramette papier A4 NEW_ITEM-QUANTITY[1]=5 NEW_ITEM-UNIT[1]=PCE NEW_ITEM-PRICE[1]=4.50 NEW_ITEM-CURRENCY[1]=EUR NEW_ITEM-VENDORMAT[1]=PAP-A4 NEW_ITEM-DESCRIPTION[2]=Stylo bille bleu NEW_ITEM-QUANTITY[2]=10 NEW_ITEM-UNIT[2]=PCE NEW_ITEM-PRICE[2]=0.80 NEW_ITEM-CURRENCY[2]=EUR NEW_ITEM-VENDORMAT[2]=STYLO-B
Le testeur OCI de ce site prépare ce formulaire, vous laisse l’envoyer, puis décode les NEW_ITEM-* reçus sur la HOOK_URL.
3. PunchOut cXML
cXML est un document XML échangé en HTTP. L’aller n’est pas un formulaire visible : le système d’achat poste un PunchOutSetupRequest au endpoint du fournisseur. La réponse contient une URL de page de démarrage. Le navigateur de l’utilisateur n’intervient qu’ensuite.
PunchOutSetupRequest
Le message a un en-tête d’identité et un corps de requête.
From— qui achète (domaine + identité, par exemple NetworkId ou DUNS).To— le fournisseur visé.Sender— l’émetteur technique, avec le secret partagé et un UserAgent.deploymentMode—testouproduction.operation—create(nouveau panier),edit(revenir sur une ligne) ouinspect(consulter sans forcément modifier).BuyerCookie— jeton opaque de session, à renvoyer tel quel.Extrinsic— données libres : e-mail, nom, identifiant utilisateur. Les noms varient selon les plateformes.BrowserFormPost— URL où le navigateur postera le panier.SupplierSetup— URL du endpoint, parfois répétée dans le message.ShipTo— adresse de livraison indicative, pour filtrer le catalogue ou les prix.
Pour edit et inspect, un bloc SelectedItem (ou équivalent) désigne la référence à rouvrir.
<?xml version="1.0" encoding="UTF-8"?>
<cXML payloadID="setup.exemple@achat.local" timestamp="2026-09-22T15:00:00Z">
<Header>
<From>
<Credential domain="NetworkId"><Identity>AcheteurDemo</Identity></Credential>
</From>
<To>
<Credential domain="DUNS"><Identity>FournisseurDemo</Identity></Credential>
</To>
<Sender>
<Credential domain="NetworkId">
<Identity>AcheteurDemo</Identity>
<SharedSecret>secret-demo</SharedSecret>
</Credential>
<UserAgent>visual-punchout.com</UserAgent>
</Sender>
</Header>
<Request deploymentMode="test">
<PunchOutSetupRequest operation="create">
<BuyerCookie>BC-EXEMPLE-001</BuyerCookie>
<Extrinsic name="UserEmail">jean.dupont@exemple.fr</Extrinsic>
<BrowserFormPost>
<URL>https://achat.exemple/cxml/retour</URL>
</BrowserFormPost>
<ShipTo>
<Address addressID="default">
<Name xml:lang="fr">Jean Dupont</Name>
<PostalAddress>
<Street>12 rue de la Paix</Street>
<City>Paris</City>
<PostalCode>75002</PostalCode>
<Country isoCountryCode="FR">FR</Country>
</PostalAddress>
</Address>
</ShipTo>
</PunchOutSetupRequest>
</Request>
</cXML>
PunchOutSetupResponse et StartPage
Si la session est acceptée, le fournisseur répond avec un statut 200 et une URL. L’outil d’achat redirige alors le navigateur vers cette page : c’est le catalogue, déjà positionné sur le bon compte.
<cXML payloadID="reponse.exemple@fournisseur.local" timestamp="2026-09-22T15:00:01Z">
<Response>
<Status code="200" text="OK"/>
<PunchOutSetupResponse>
<StartPage>
<URL>https://fournisseur.exemple/catalogue?session=abc</URL>
</StartPage>
</PunchOutSetupResponse>
</Response>
</cXML>
Un code autre que 200, ou une page HTML d’erreur, indique un rejet : secret incorrect, identité inconnue, URL mal formée. Ce testeur affiche le code HTTP, le statut cXML s’il est lisible, et le corps brut.
PunchOutOrderMessage
Au moment de revenir, le catalogue poste un PunchOutOrderMessage vers l’URL BrowserFormPost. Le transport habituel est un formulaire dont le champ s’appelle cxml-urlencoded ou cxml-base64. Le message reprend le BuyerCookie, un en-tête avec l’opération et le total, puis une balise ItemIn par ligne.
<cXML payloadID="poom.exemple@fournisseur.local" timestamp="2026-09-22T15:04:00Z">
<Message>
<PunchOutOrderMessage>
<BuyerCookie>BC-EXEMPLE-001</BuyerCookie>
<PunchOutOrderMessageHeader operation="create">
<Total><Money currency="EUR">9.00</Money></Total>
</PunchOutOrderMessageHeader>
<ItemIn quantity="2">
<ItemID><SupplierPartID>PAP-A4</SupplierPartID></ItemID>
<ItemDetail>
<UnitPrice><Money currency="EUR">4.50</Money></UnitPrice>
<Description xml:lang="fr">Ramette papier A4</Description>
<UnitOfMeasure>EA</UnitOfMeasure>
<Classification domain="UNSPSC">14111507</Classification>
</ItemDetail>
</ItemIn>
</PunchOutOrderMessage>
</Message>
</cXML>
Le BuyerCookie permet de retrouver la session ouverte au setup. S’il ne correspond pas, l’acheteur ne peut pas ranger le panier au bon endroit.
4. OrderRequest
Le PunchOut s’arrête au panier. Quand la demande est approuvée, l’acheteur peut envoyer un OrderRequest : numéro de commande, date, total, adresses de livraison et de facturation, lignes ItemOut (quantité, référence, prix, unité, classification). Le fournisseur répond par un statut cXML. Ce n’est plus une session de navigation : c’est un message serveur à serveur, comme le setup.
5. Comment s’en servir ici
- cXML PunchOut — génère et poste le setup, puis propose la StartPage.
- OCI RoundTrip — prépare le formulaire et laisse le navigateur l’envoyer.
- Commande cXML — poste un OrderRequest et montre la réponse.
- Historique — conserve requête, réponse et panier sur ce serveur. Cette page demande un compte ; le reste du site reste ouvert.
Les URL d’exemple pointent vers le fournisseur simulé (mock/). Vous pouvez les remplacer par un endpoint réel. Les secrets préremplis sont fictifs.
Pour un fournisseur externe, l’URL de retour (HOOK_URL ou BrowserFormPost) doit être joignable depuis le navigateur qui affiche le catalogue. En local, cela fonctionne avec le fournisseur simulé. Un catalogue hébergé ailleurs ne pourra poster vers localhost que si le navigateur qui fait le retour est la même machine.