Blog

Integraties 8 min leestijd

WayForPay-integratie in PHP: betalingsformulier, handtekening en terugbellen

WayForPay is de praktische manier om kaartbetalingen in UAH, USD en EUR van een Oekraïens bedrijf te accepteren. In deze handleiding wordt de volledige integratie in PHP doorlopen: het ondertekenen van het betalingsformulier, het ontvangen van de servercallback, het correct beantwoorden ervan en het bevestigen van de bestelstatus.

Omslagillustratie: WayForPay-integratie in PHP: betalingsformulier, handtekening en terugbellen

In het kort

  • De stroom bestaat uit drie delen: een ondertekend betalingsformulier dat de klant naar WayForPay stuurt, een server-naar-server callback (serviceUrl) en uw eigen bestelstatuspagina.
  • Elk verzoek en antwoord wordt ondertekend met HMAC_MD5 met behulp van uw geheime sleutel voor de verkoper; veldvolgorde is belangrijk.
  • Markeer een bestelling alleen als betaald na een geverifieerde terugbelactie of een CHECK_STATUS-reactie, nooit als de klant terugkeert naar uw site.
  • U moet de terugbelactie beantwoorden met een ondertekend JSON-acceptatieantwoord, anders blijft WayForPay het opnieuw proberen.
  • Bewaar bedragen, valuta en bestelreferentie in uw database en vergelijk deze met wat er in de terugbelactie staat.

Een WayForPay integratie in PHP is een kleine hoeveelheid code, maar er zijn verschillende plaatsen waar een stille fout betekent dat onbetaalde bestellingen zijn gemarkeerd als betaald, of dat betaalde bestellingen nooit worden uitgevoerd. We voeren WayForPay kassa uit op onze eigen sites, inclusief de betaalde services op deze website, en hebben dit aangesloten op verschillende klantenwinkels. Hieronder vindt u de structuur die we gebruiken, met de details die in de documentatie worden vermeld, maar mensen hebben de neiging om er vluchtig naar te kijken.

Hoe de betalingsstroom werkt

  1. De klant klikt op ‘Betalen’. Uw server maakt een bestelling aan in de database met een unieke orderReference, een vast bedrag en een valuta.
  2. Uw server bouwt de velden voor het betalingsformulier op, ondertekent ze en geeft een automatisch verzonden HTML-formulier weer dat op de WayForPay-betalingspagina wordt geplaatst.
  3. De klant betaalt op de WayForPay pagina (kaart, Apple Pay, Google Pay en andere methoden ingeschakeld in uw verkopersaccount).
  4. WayForPay belt uw serviceUrl met het transactieresultaat. Deze server-naar-server-oproep is wat u vertrouwt.
  5. De klant wordt doorgestuurd naar uw returnUrl, waar u de huidige bestelstatus weergeeft.

Stap 5 kan plaatsvinden voordat stap 4 is voltooid, dus op de retourpagina moet 'uw betaling bevestigen' staan totdat het terugbellen is verwerkt.

Wat u nodig heeft van het verkopersaccount

  • merchantAccount - uw verkoperslogin.
  • merchantSecretKey - het geheim dat wordt gebruikt voor handtekeningen. Bewaar het in een omgevingsvariabele of een niet-bijgehouden configuratiebestand, nooit in git of in front-endcode.
  • merchantDomainName - het domein van uw site, zoals geregistreerd in het account.
  • De valuta's en betaalmethoden die voor uw account zijn ingeschakeld.

Stap 1. Maak het betalingsformulier op en onderteken het

De handtekening is een HMAC met MD5 over geselecteerde velden, samengevoegd door een puntkomma. Voor een aankoop is de bestelling: verkopersaccount, domeinnaam van de verkoper, bestelreferentie, besteldatum (Unix-tijdstempel), bedrag, valuta, vervolgens alle productnamen, alle productaantallen en alle productprijzen.

function wfpSignature(array $parts, string $secret): string
{
    return hash_hmac('md5', implode(';', $parts), $secret);
}

$orderReference = 'ORD-' . $orderId . '-' . time();
$orderDate      = time();
$amount         = '50.00';          // string with a dot, the same value everywhere
$currency       = 'EUR';
$products       = [['name' => 'Consultation, 1 hour', 'count' => 1, 'price' => '50.00']];

$parts = [$merchantAccount, $merchantDomain, $orderReference, $orderDate, $amount, $currency];
foreach ($products as $p) { $parts[] = $p['name']; }
foreach ($products as $p) { $parts[] = (string) $p['count']; }
foreach ($products as $p) { $parts[] = $p['price']; }

$signature = wfpSignature($parts, $secretKey);

Geef vervolgens het formulier weer. Productvelden zijn arrays, dus gebruiken ze het achtervoegsel []:

<form id="wfp" method="post" action="https://secure.wayforpay.com/pay" accept-charset="utf-8">
  <input type="hidden" name="merchantAccount" value="...">
  <input type="hidden" name="merchantAuthType" value="SimpleSignature">
  <input type="hidden" name="merchantDomainName" value="example.com">
  <input type="hidden" name="merchantSignature" value="<?= htmlspecialchars($signature) ?>">
  <input type="hidden" name="orderReference" value="<?= htmlspecialchars($orderReference) ?>">
  <input type="hidden" name="orderDate" value="<?= $orderDate ?>">
  <input type="hidden" name="amount" value="50.00">
  <input type="hidden" name="currency" value="EUR">
  <input type="hidden" name="productName[]" value="Consultation, 1 hour">
  <input type="hidden" name="productCount[]" value="1">
  <input type="hidden" name="productPrice[]" value="50.00">
  <input type="hidden" name="returnUrl" value="https://example.com/pay/return">
  <input type="hidden" name="serviceUrl" value="https://example.com/pay/callback">
</form>
<script>document.getElementById('wfp').submit();</script>

De meest voorkomende handtekeningfouten zijn: een ander getalformaat in de handtekening en het formulier (50 versus 50.00), een productnaam die na ondertekening wordt gewijzigd (getrimd, HTML-escaped) en vergeten dat de volgorde van de velden vaststaat.

Stap 2. Ontvang de callback op serviceUrl

Wanneer de betaling een definitieve status bereikt, plaatst WayForPay het resultaat naar serviceUrl. Lees de onbewerkte body (het is JSON; sommige setups leveren ook formuliervelden, dus behandel beide) en verifieer de handtekening. Voor het terugbellen wordt het berekend over: verkopersaccount, orderreferentie, bedrag, valuta, autorisatiecode, kaartmasker, transactiestatus en redencode.

$raw  = file_get_contents('php://input');
$data = json_decode($raw, true) ?: $_POST;

$line = implode(';', [
    $data['merchantAccount'] ?? '',
    $data['orderReference'] ?? '',
    $data['amount'] ?? '',
    $data['currency'] ?? '',
    $data['authCode'] ?? '',
    $data['cardPan'] ?? '',
    $data['transactionStatus'] ?? '',
    $data['reasonCode'] ?? '',
]);
$expected = hash_hmac('md5', $line, $secretKey);

if (!hash_equals(strtolower($expected), strtolower((string) ($data['merchantSignature'] ?? '')))) {
    http_response_code(400);
    exit;
}

Gebruik hash_equals voor de vergelijking om timinglekken te voorkomen. Pas nadat de handtekening geldig is, kunt u de bestelling opzoeken en amount en currency vergelijken met wat u hebt opgeslagen. Als ze verschillen, log dit dan in en markeer de bestelling niet als betaald.

Stap 3. Update de bestelling en antwoord correct

Het veld transactionStatus vertelt u wat er is gebeurd: Approved betekent dat het geld is vastgelegd; Declined, Expired en vergelijkbare waarden betekenen mislukking; Pending of InProcessing betekent wachten; Refunded en Voided betekent dat het geld terug is gegaan. Werk uw bestelling dienovereenkomstig bij in een transactie en maak deze idempotent: als de bestelling al is betaald, doet u niets en antwoordt u nog steeds met succes.

WayForPay vereist een ondertekend antwoord, zodat het weet dat u het bericht hebt ontvangen. De handtekening staat boven de bestelreferentie, het woord accept en de huidige tijd:

$time   = time();
$status = 'accept';
$reply  = [
    'orderReference' => $data['orderReference'],
    'status'         => $status,
    'time'           => $time,
    'signature'      => hash_hmac('md5', "{$data['orderReference']};{$status};{$time}", $secretKey),
];

header('Content-Type: application/json');
echo json_encode($reply);

Als uw server niet op deze manier antwoordt, beschouwt WayForPay de bezorging als mislukt en probeert het opnieuw, wat betekent dat u meerdere keren hetzelfde terugbelverzoek ontvangt. Dat is nog een reden voor de idempotentiecontrole.

Stap 4. Bevestig de status met CHECK_STATUS

Terugbelverzoeken kunnen worden gemist: uw server was uitgevallen, een firewall blokkeerde het verzoek, een implementatie verbrak de route. WayForPay biedt een CHECK_STATUS API-aanroep die de huidige status van een bestelling retourneert aan de hand van zijn referentie. Gebruik het op twee plaatsen: op de retourpagina, als het terugbelverzoek na een paar seconden nog niet is ontvangen, en in een kleine cronjob die bestellingen die langer dan bijvoorbeeld vijftien minuten in de wachtrij staan, opnieuw controleert. Het verzoek wordt ondertekend met HMAC_MD5 via het verkopersaccount en de bestelreferentie.

$payload = [
    'transactionType'   => 'CHECK_STATUS',
    'merchantAccount'   => $merchantAccount,
    'orderReference'    => $orderReference,
    'merchantSignature' => hash_hmac('md5', "{$merchantAccount};{$orderReference}", $secretKey),
    'apiVersion'        => 1,
];

$ch = curl_init('https://api.wayforpay.com/api');
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => json_encode($payload),
    CURLOPT_HTTPHEADER     => ['Content-Type: application/json'],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 15,
]);
$result = json_decode((string) curl_exec($ch), true);

Pas dezelfde controles toe als bij een terugbelactie: verifieer de handtekening van het antwoord, indien aanwezig, vergelijk het bedrag en de valuta, en werk de bestelling idempotent bij.

Testen voordat je live gaat

  • Gebruik de testmodus en testkaarten uit de WayForPay-documentatie totdat een volledige betaling, een weigering en een terugbetaling allemaal in uw logboeken zijn gezien.
  • Uw serviceUrl moet bereikbaar zijn vanaf internet via HTTPS. Gebruik op localhost een tunnel of implementeer het in een stagingdomein.
  • Registreer elke terugbelactie met zijn onbewerkte tekst, het verificatieresultaat en de uitkomst. Log nooit de geheime sleutel in.
  • Zorg ervoor dat de WAF- of botbescherming (bijvoorbeeld in Cloudflare) de terugbelverzoeken van WayForPay niet uitdaagt of blokkeert.

Veel voorkomende fouten

  • De retour-URL vertrouwen. De klant kan deze openen zonder te betalen.
  • Hergebruik van een bestelreferentie. Elke poging heeft een unieke referentie nodig, anders haal je pogingen door elkaar.
  • Het bedrag wijzigen na ondertekening, of de ene prijs weergeven en de andere ondertekenen.
  • Het terugbellen niet beantwoorden met het ondertekende acceptatieantwoord.
  • Markeer als betaald voordat u het bedrag en de valuta controleert.
  • Meerdere valuta, één gedeeld geheim en geen mapping: houd de valuta in de juiste volgorde en verifieer deze bij terugbellen.

Hoe wij kunnen helpen

We bouwen betalingsintegraties van begin tot eind: WayForPay, Stripe, PayPal, terugkerende facturering, terugbetalingen en afstemmingsrapporten. Als u al een werkende kassa heeft, maar niet zeker bent van de storingsmodi, boek dan een architectuuranalyse en we zullen de callback-afhandeling, idempotentie en logboekregistratie beoordelen. Voor een vergelijkbare handleiding bij een andere provider zie Stripe webhooks in PHP, en voor de algemene aanpak lees ons playbook voor startup-integraties.

Veelgestelde vragen

Welke handtekening gebruikt WayForPay ?

HMAC_MD5 over geselecteerde velden, samengevoegd met een puntkomma, met behulp van de geheime sleutel van de verkoper. De veldvolgorde ligt vast en verschilt voor het betaalformulier, de terugbelreactie en de terugbelreactie.

Wat moet het serviceUrl-eindpunt retourneren?

Een JSON-antwoord met orderReference, de status "accept", de huidige Unix-tijd en een handtekening berekend als HMAC_MD5 van "orderReference;accept;time". Zonder dit probeert WayForPay opnieuw terug te bellen.

Kan ik erop vertrouwen dat de returnUrl-pagina een bestelling als betaald markeert?

Nee. De browser van de klant kan die URL openen zonder te betalen. Markeer bestellingen alleen als betaald na een geverifieerde serviceUrl-callback of een CHECK_STATUS reactie met de status Goedgekeurd en het overeenkomende bedrag en de bijbehorende valuta.

Hoe controleer ik de status van een WayForPay-bestelling?

Stuur een ondertekend CHECK_STATUS verzoek naar de WayForPay API met uw verkopersaccount en de bestelreferentie. Gebruik het op de retourpagina en in een cronjob die bestellingen die in behandeling zijn gebleven opnieuw controleert.

Waarom zegt WayForPay dat de handtekening ongeldig is?

Meestal verschilt het formaat van het bedrag tussen de handtekening en het formulier (50 versus 50,00), is een productnaam na ondertekening gewijzigd, is de volgorde van de velden verkeerd of is er een verkeerde geheime sleutel gebruikt.

Gratis ontdekkingsgesprek

Breng een rommelige stack of vastgelopen integratie - Integrono schetst de slimste eerste zet.

U krijgt een senior blik op budgetvallen, afhankelijkheden en of u moet kopen, lijmen of bouwen - voordat betaald werk start. De CEO blijft in the loop.