pbs-dropin
v0.4.0
Published
Septeo Payments public API Adyen drop-in shell
Readme
pbs-dropin
English —
npm install pbs-dropin(and@adyen/adyen-webif you do not already have major 6). Thenimport "pbs-dropin/styles". Pass session fields as props. LeavecreateSessionKeyat0until the shopper should pay, then increment it. Jump to Install, Usage, Props.
React shell for the Septeo Payments public session API and the Adyen Drop-in. Version 0.4.0.
The package does not render a session form. The host (PMS or back-office) owns the UI. Adyen mounts only after POST /api/public/v1/sessions succeeds.
Install
@adyen/adyen-web ^6 is a peer dependency. Always one copy in the PMS app.
npm install pbs-dropin @adyen/adyen-webIf the app already has @adyen/adyen-web major 6: npm install pbs-dropin is enough.
Other peers: react (>=18), react-dom (>=18).
import { PbsDropin } from "pbs-dropin";
import "pbs-dropin/styles";The widget fills 100% of the width of its parent. Put PbsDropin in a container you size and style (width, max-width, grid column, …).
<div style={{ width: "100%", maxWidth: 480 }}>
<PbsDropin ... />
</div>The widget loads Adyen Web 6 in auto mode. Do not pass paymentMethodComponents.
When the POST runs
createSessionKey (number, default 0):
0— idle empty shell. No POST (do not create a session just because checkout is mounted).- Increment (
1,2, …) when the host wants to pay — typically a PMS Pay click. The hook POSTs with the current props. - Success — Adyen mounts in the same container.
- Error — message in the container, no Adyen.
- Retry or cancel — increment again, or set the key back to
0to empty the shell (onSessionCancelledif a session was showing).
The package does not auto-create a session on mount.
Usage
import { useState } from "react";
import { PbsDropin } from "pbs-dropin";
import "pbs-dropin/styles";
export function Checkout() {
const [createSessionKey, setCreateSessionKey] = useState(0);
return (
<>
<button type="button" onClick={() => setCreateSessionKey((key) => key + 1)}>
Payer
</button>
<div style={{ width: "100%", maxWidth: 480 }}>
<PbsDropin
createSessionKey={createSessionKey}
accessToken={hydraAccessToken}
publicStoreId={publicStoreId}
returnUrl="https://votre-pms.fr/retour"
apiBaseUrl="https://septeo-payments-public-api-sandbox.septeo.fr"
adyenClientKey="test_…"
adyenEnvironment="test"
locale="fr-FR"
amount="10"
currency="EUR"
reference="CMD-2026-0001"
shopperCountryCode="FR"
captureMode="IMMEDIATE"
captureDelayHours=""
preAuth={false}
moto={false}
tokenizationEnabled={false}
shopperReference=""
recurringModel="CARD_ON_FILE"
consentMode="ASK_FOR_CONSENT"
lineItems={[
{
id: "SKU-1",
description: "Massage 60 min",
quantity: 1,
amountIncludingTax: 10000,
},
]}
onSessionCreated={(session) => {
console.info("session créée", session.sessionId);
}}
onPaymentCompleted={({ resultCode }) => {
console.info("resultCode Adyen", resultCode);
}}
onError={(error) => {
console.error(error);
}}
/>
</div>
</>
);
}amount is in major units (10 = 10,00 €). The API receives minor units (1000). amountIncludingTax on lineItems is already minor units (10000 = 100,00 € TTC).
Hydra / SSO is configured in Septeo Payments back-office and in the public API Swagger. This README does not copy the auth flow.
Props
The package does not render a form and does not block payment if a prop is missing: incrementing createSessionKey runs POST /sessions. If the body is incomplete, the API (or client validation) returns an error in the shell. The host must supply a valid payload.
Required to create a session (POST /sessions)
| Prop | Notes |
| --- | --- |
| accessToken | Bearer Hydra. |
| publicStoreId | Public store id. |
| returnUrl | Shopper return URL. |
| amount | Major units, string ("10" → API 1000). |
| currency | ISO (e.g. EUR). |
| reference | Merchant reference. |
| shopperCountryCode | ISO country (Adyen filters methods; required for Klarna / BNPL). |
| captureMode | IMMEDIATE | DELAYED | MANUAL. |
Required in some cases
| Prop | When |
| --- | --- |
| captureDelayHours | captureMode === "DELAYED" (hours, string). |
| shopperReference | tokenizationEnabled === true. |
| recurringModel | tokenizationEnabled === true (SUBSCRIPTION | CARD_ON_FILE | UNSCHEDULED). |
| consentMode | Sent when tokenisation is on (ASK_FOR_CONSENT | FORCED). |
| adyenClientKey | After a successful POST, to mount Adyen Drop-in. Without it the session can exist but the widget cannot render. |
| lineItems | Klarna / BNPL: non-empty basket and an EU shopperCountryCode. |
Recommended / optional
| Prop | Default / behaviour |
| --- | --- |
| createSessionKey | 0 idle, no POST. Increment to pay. |
| locale | Adyen UI locale (e.g. fr-FR). |
| preAuth | true only with MANUAL. |
| moto | Agent collection. |
| tokenizationEnabled | When false, tokenization is null on the body. |
| apiBaseUrl | Sandbox public API if omitted. |
| adyenEnvironment | "test" (default) or "live". |
| adyenTranslations | Adyen Drop-in translations. |
| className | Extra class on the root (pbs-dropin). |
| onSessionCreated | Public session created. |
| onPaymentCompleted | Adyen { resultCode }. Not the source of truth — see Après le paiement. |
| onPaymentFailed | Adyen / mount failure. |
| onSessionCancelled | Host set createSessionKey back to 0 after a session. |
| onError | Session or Adyen error. |
You can also import toCreateSessionRequest to preview the JSON body in the host UI.
Capture et pré-autorisation
Les montants envoyés à l’API sont toujours en unités mineures : 10,00 € → 1000.
| Le PMS veut… | capture.mode | preAuth |
| --- | --- | --- |
| Encaisser tout de suite | IMMEDIATE | false |
| Encaisser plus tard, automatiquement | DELAYED + delayHours | false |
| Autoriser maintenant, capturer / annuler / ajuster plus tard | MANUAL | false |
| Caution / pré-auth (hôtel, location) | MANUAL | true |
- IMMEDIATE — encaissement tout de suite.
- DELAYED +
delayHours— capture automatique plus tard. - MANUAL — autoriser maintenant ; ensuite capturer, annuler, rembourser, ajuster.
- Pré-auth — uniquement avec MANUAL. Cocher la pré-auth force Manuel côté hôte ; Immédiat ou Différé décoche la pré-auth.
MOTO
moto=true pour un encaissement par un agent (téléphone / courrier). Compatible avec les trois modes de capture.
Tokenisation
{
"shopperReference": "client-42",
"recurringModel": "SUBSCRIPTION",
"consentMode": "ASK_FOR_CONSENT"
}| recurringModel | Usage typique |
| --- | --- |
| SUBSCRIPTION | Abonnement. |
| CARD_ON_FILE | Carte à la demande. |
| UNSCHEDULED | Débit marchand irrégulier. |
ASK_FOR_CONSENT— case Adyen ; le client peut refuser.FORCED— enregistrement imposé.
Montant 0,00 € : autorisé uniquement si la tokenisation est activée.
lineItems et Klarna / BNPL
There is no Klarna checkbox in the package. The host passes the real basket via lineItems.
Adyen offers Klarna (and other BNPL) only if:
lineItemsis non-empty;shopperCountryCodeis an EU country for Klarna;- Klarna is enabled on the Adyen store.
Do not import Klarna. The method appears if Adyen returns it on the session.
| Field | Type | Notes |
| --- | --- | --- |
| id | string? | SKU. |
| description | string | Label. |
| quantity | number | Quantity. |
| amountIncludingTax | number | TTC in minor units. |
Payment methods
Auto mode: whatever is enabled on the Adyen store and allowed by the session.
Flow
flowchart LR
host[Host PMS or BO]
api[API publique POST sessions]
dropin[PbsDropin]
adyen[Adyen Drop-in auto]
wh[Webhook AUTHORISATION]
host -->|"props + createSessionKey"| dropin
dropin --> api
api --> dropin
dropin --> adyen
adyen --> wh
wh --> hostAprès le paiement
onPaymentCompleted only shows the Adyen resultCode. Business confirmation is the webhook (e.g. AUTHORISATION) on the PMS server.
Later operations use the pspReference from the webhook or the Adyen Customer Area.
Playground
npm install
npm run devScripts
npm test
npm run type-check
npm run build