Betaling og stabil drift
Sikker onlinebetaling: markér ikke ordren som betalt på et løfte fra browseren
En flot betalingsside gør ikke betalingsforløbet driftsklart. Appen skal kunne bevise, hvilken ordre betalingen tilhører, hvilket beløb udbyderen har bekræftet, og om varen, bookingen eller adgangen allerede er leveret – også når kunden lukker fanen, nettet falder ud, eller den samme besked kommer flere gange.
Lad en betalingsudbyder håndtere kortoplysningerne
Brug som udgangspunkt udbyderens hostede betalingsside eller dokumenterede betalingskomponenter, så rå kortoplysninger ikke passerer gennem jeres egen server. Det reducerer angrebsfladen og omfanget af det PCI-arbejde, virksomheden selv skal håndtere. Det fjerner ikke virksomhedens ansvar for en sikker integration eller for at afklare de konkrete PCI-krav med betalingsudbyder, indløser eller anden relevant rådgiver.
Stripe bruges som praktisk eksempel her, men arkitekturen gælder også andre udbydere: følg altid den valgte udbyders aktuelle dokumentation for betalingsside, hændelser, testmiljø og sikkerhed.
Opret ordre og betalingsforsøg på serveren
Browseren må gerne sende et produkt-id, en kurv eller et ordrenummer. Serveren skal kontrollere bruger, varer, pris, valuta, rabat, moms og ejerskab mod betroede data, før den opretter en betalingssession. Et beløb fra browseren er input – ikke sandheden.
- Opret en lokal ordre: Giv den et stabilt id og en tydelig status som afventer betaling.
- Beregn på serveren: Hent priser og regler fra jeres egne betroede data; kontrollér også valuta og samlet beløb.
- Opret ét betalingsforsøg: Knyt udbyderens betalings- eller sessions-id til den lokale ordre.
- Brug idempotens: Et timeout eller dobbeltklik må ikke oprette flere logiske betalinger for samme forsøg.
- Gem kun nødvendige referencer: Ordre-id, udbyder-id, forventet beløb, valuta, status og relevante tidspunkter er typisk vigtigere end hele udbyderens svar.
Stripe understøtter idempotency keys på oprettende og ændrende API-kald. Nøglen skal repræsentere det samme betalingsforsøg ved et sikkert nyt forsøg – ikke genbruges til en ny ordre eller et nyt beløb.
Retur-siden er status – ikke betalingsbevis
Kunden kan ændre parametre i en URL, åbne en gammel retur-side igen eller forsvinde, før siden overhovedet indlæses. Derfor må teksten “Tak for din betaling”, en success=true-parameter eller en klientcallback ikke alene markere ordren som betalt og udløse levering.
- Browseren viser
- “Vi kontrollerer betalingen”, “Betalt” eller en ærlig fejlstatus fra serveren.
- Serveren kontrollerer
- Session, betalingsstatus, ordre, beløb og valuta hos udbyderen.
- Webhooken sikrer
- At betalingen også behandles, når kunden aldrig vender tilbage til appen.
Stripe kræver webhooks til pålidelig fulfillment. En retur-side kan stadig bede serveren hente den aktuelle Checkout Session og forsøge den samme idempotente leveringsfunktion, så kunden får hurtig feedback. Begge veje skal ende i samme serverkontrol og må kun levere én gang.
Gør betalingswebhooken sikker at gentage
En webhook er et offentligt endpoint. Verificér udbyderens signatur med den rå request-body og det rigtige endpoint-secret, før eventet accepteres. Parse eller ændr ikke body først, hvis udbyderens signaturkontrol kræver de oprindelige bytes.
- Afvis ugyldig signatur: En eventtype og et betalings-id i JSON er ikke dokumentation for afsenderen.
- Registrér behandlede events: Samme event kan leveres flere gange; gem event-id og gør ordreopdateringen atomisk.
- Vær uafhængig af rækkefølge: Stripe garanterer ikke, at events kommer i den rækkefølge, de blev skabt. Hent om nødvendigt den aktuelle betalingsressource.
- Lever kun én gang: Fulfillment skal kunne kaldes samtidigt fra både webhook og retur-side uden dobbelt booking, mail eller adgang.
- Svar hurtigt: Gem eller kø eventet, returnér succes, og flyt langsomt efterarbejde til en kontrolleret proces.
- Overvåg leveringen: Følg fejlede og ventende events, og dokumentér hvordan en event genbehandles uden at omgå kontrollerne.
Den generelle model for rå body, signatur, dubletter, kø og genbehandling findes iguiden om sikre webhooks.
Brug mere end et enkelt betalt/ikke betalt-felt
Betalinger har en livscyklus. Nogle betalingsmetoder bekræftes senere, og en betalt ordre kan efterfølgende få en hel eller delvis refundering eller en indsigelse. Hold betalingsstatus og leveringsstatus adskilt, så “refunderet” ikke ligner “aldrig betalt”, og så et fornyet webhook-event ikke leverer ordren igen.
| Betalingstilstand | Hvad brugeren bør se | Sikker driftsadfærd |
|---|---|---|
| Afventer | Betalingen behandles eller mangler | Lever ikke endnu; afvent eller hent ny status |
| Betalt | Bekræftet betaling og konkret næste handling | Lever højst én gang og registrér tidspunkt |
| Fejlet eller udløbet | Ingen bekræftet betaling; tilbyd et nyt kontrolleret forsøg | Bevar historikken og opret et nyt betalingsforsøg |
| Helt eller delvist refunderet | Vis beløb og status uden at omskrive historikken | Håndtér adgang, ordre og regnskab efter virksomhedens regel |
| Indsigelse | Vis kun nødvendige oplysninger til de rette roller | Alarmér ansvarlig og bevar relevant dokumentation |
De præcise statusser og events afhænger af betalingsmetode, produkt og udbyder. Definér dem ud fra jeres leveringsregel, og kortlæg dem til den valgte platforms aktuelle model.
Beskyt nøgler og adskil test fra rigtige penge
Den offentlige nøgle er lavet til klienten; den hemmelige API-nøgle og webhookens signing secret skal blive i servermiljøets secret-lager. Brug mindst mulige rettigheder, når udbyderen tilbyder begrænsede nøgler, og rotér straks en nøgle, der har været synlig i kode, logs, chat eller frontend.
- Separate miljøer: Test og produktion har egne nøgler, webhook-endpoints, produkter og hændelser.
- Ingen test med rigtige kortdata: Brug udbyderens dokumenterede testmetoder og testkort i testmiljøet.
- Kontrollér live-konfiguration: En vellykket test beviser ikke, at produkt-id'er, URL'er, events og secrets er rigtige i produktion.
- Begræns dashboardadgang: Kun navngivne personer skal kunne se betalinger, oprette nøgler eller refundere.
Afstem appens ordrer med betalingsudbyderen
Logs og webhooks kan fejle, og manuelle refunderinger kan ske direkte hos udbyderen. Lav derfor en periodisk kontrol, som sammenholder lokale ordrer med udbyderens betalinger, refunderinger og indsigelser. Afvigelser skal ende hos en navngiven person – ikke kun i en teknisk log.
- Find manglende koblinger: Betaling uden lokal ordre eller ordre markeret betalt uden bekræftet udbyderreference.
- Sammenlign beløb og valuta: Kontrollér også delvise refunderinger og gebyrfri forretningsfelter separat.
- Fang fastlåste betalinger: En ordre må ikke stå “behandles” for evigt uden alarm eller afklaring.
- Bevar sporbarheden: Notér automatisk og manuel håndtering uden at gemme unødige betalingsdata.
Test betalingsforløbets fejlveje
Testmiljøet skal bruges til mere end én vellykket betaling. Afprøv de hændelser, som kan efterlade kunden eller virksomheden i tvivl, og kontrollér både brugerflade, database, webhookhistorik, logs og den efterfølgende levering.
- Succes: Korrekt ordre, beløb og valuta bliver betalt og leveret én gang.
- Afvisning og afbrudt checkout: Ordren bliver ikke betalt eller leveret, og kunden kan forstå næste skridt.
- Dobbeltklik og timeout: Samme forsøg opretter ikke to betalinger eller to ordrer.
- Ingen retur-side: Luk browseren efter betaling; webhooken skal stadig føre ordren sikkert videre.
- Ugyldig signatur: Eventet afvises uden ordreændring eller læk af tekniske detaljer.
- Dublet og forkert rækkefølge: Genlever samme event og byt rækkefølgen; resultatet skal være konsistent.
- Forsinket betaling: Vis “behandles”, indtil udbyderen faktisk bekræfter succes eller fejl.
- Refundering og indsigelse: Status, adgang, notifikation og ansvar følger den aftalte forretningsregel.
Typiske fejl i AI-byggede betalingsflows
- Prisen kommer fra browseren: En bruger kan ændre requestet og betale et andet beløb end ordren kræver.
- Retur-URL betyder betalt: En redigeret eller genåbnet URL udløser levering uden serverbekræftelse.
- Webhookens JSON stoles på: Endpointet ændrer ordrer uden at verificere signaturen på den rå body.
- Eventet kan kun behandles én gang: Et retry sender en mail, booking eller adgang endnu en gang.
- Kun eventrækkefølgen styrer status: Et forsinket event overskriver en nyere og mere korrekt tilstand.
- Betalt er en boolean: Forsinkelse, refundering og indsigelse kan ikke beskrives eller afstemmes.
- Testnøgler skiftes direkte til live: Produkter, priser, endpoints eller signing secrets mangler i produktionsmiljøet.
- Den hemmelige nøgle ligger i frontend: Alle kan hente den fra det leverede JavaScript og kalde udbyderen med virksomhedens adgang.
Tjekliste før kunder betaler i appen
- ☐ Kortoplysninger indsamles af en dokumenteret løsning fra betalingsudbyderen og passerer ikke gennem vores server.
- ☐ Virksomhedens konkrete PCI-ansvar er afklaret med de relevante parter.
- ☐ Ordre, pris, valuta, rabat og adgang kontrolleres på serveren.
- ☐ Hvert betalingsforsøg har stabile lokale og eksterne referencer.
- ☐ Oprettende betalingskald er beskyttet mod dobbeltklik, timeout og sikre retries.
- ☐ Retur-siden viser kun en status, som serveren har kontrolleret hos udbyderen.
- ☐ Webhooken verificerer signaturen på den rå request-body med det korrekte secret.
- ☐ Dubletter, samtidighed og events i forkert rækkefølge kan ikke give dobbelt levering.
- ☐ Betalingsstatus og leveringsstatus kan beskrive afventning, succes, fejl og efterfølgende ændringer.
- ☐ Hemmelige nøgler ligger i serverens secret-lager med mindst mulige rettigheder.
- ☐ Test og produktion har separate nøgler, data, endpoints og en kontrolleret go-live-plan.
- ☐ Succes, afvisning, afbrudt flow, timeout, dublet, ugyldig signatur, forsinkelse og refundering er afprøvet.
- ☐ Fejlede webhooks, fastlåste ordrer og afstemningsafvigelser når en navngiven ansvarlig.
Relaterede guides
Officielle kilder
Betalingsmetoder, events, PCI-krav og dashboardfunktioner ændrer sig. Brug principperne til at gennemgå jeres flow, og følg derefter betalingsudbyderens og PCI Security Standards Councils aktuelle dokumentation for den konkrete løsning.
- Stripe: Gennemfør ordrer på baggrund af bekræftet betaling
- Stripe: Følg PaymentIntent-status med webhooks
- Stripe: Modtag, verificér og genbehandl webhook-events
- Stripe: Idempotente API-requests
- Stripe: Sikker håndtering af hemmelige API-nøgler
- Stripe: Testmiljøer og betalingsscenarier
- Stripe: Sikkerhed og PCI-ansvar i en integration
- PCI Security Standards Council: Betalingssider og SAQ A
Virker betalingen i demoen, men er vejen til en rigtig ordre stadig uklar?
Startklar er til virksomheder med en fungerende AI-bygget app, som skal kunne bruges trygt af kunder eller medarbejdere. Her kan betalingsflow, serverkontrol, webhooks, nøgler, statusmodel, test og drift blive gennemgået i den stack, appen faktisk bruger.
Se Startklar-forløbet