Traitez votre premier paiement de bac à sable
Traitez un paiement de commande sandbox de votre moteur de commerce et confirmez le résultat final par un webhook vérifié.
Sur cette page
Ce Quickstart utilise le paramètre d'achat marchand-backend. Avant de commencer, complètez configuration du compte, choisir votre intégration, et confirmez que votre marchand de bacs à sable a:
- Une clé API privée stockée sur votre serveur.
- Au moins une connexion de paiement active et une stratégie de routage.
- Un jeton de commande et un jeton de paiement créé par l'intégration de votre client sélectionné.
- Un paramètre HTTPS public qui peut recevoir des webhooks DEUNA.
Préparer la requête du serveur#
Chargez la clé privée sandbox depuis votre serveur. Gardez le jeton de commande et le jeton de paiement produit par le même flux de bac à sable disponible pour le corps de la demande.
DEUNA_PRIVATE_API_KEY=YOUR_SANDBOX_PRIVATE_API_KEYTraitement du paiement de l'ordre#
Envoyer la commande et la méthode de paiement tokenized au point d'achat marchand vérifié. Réutiliser la même X-Idempotency-Key et demander à l'organisme si un délai de traitement du réseau rend le résultat incertain.
curl --request POST \
--url https://api.sandbox.deuna.io/v2/merchants/orders/purchase \
--header "X-Api-Key: ${DEUNA_PRIVATE_API_KEY}" \
--header "X-Idempotency-Key: order_1042-attempt_1" \
--header "Content-Type: application/json" \
--data '{
"order_token": "YOUR_SANDBOX_ORDER_TOKEN",
"payer_info": {
"email": "buyer@example.com",
"external_user_id": "customer_1042"
},
"payment_source": {
"method_type": "credit_card",
"payment_method": "YOUR_PAYMENT_METHOD_TOKEN"
}
}'const response = await fetch("https://api.sandbox.deuna.io/v2/merchants/orders/purchase", {
method: "POST",
headers: {
"X-Api-Key": "${DEUNA_PRIVATE_API_KEY}",
"X-Idempotency-Key": "order_1042-attempt_1",
"Content-Type": "application/json"
},
body: JSON.stringify({
"order_token": "YOUR_SANDBOX_ORDER_TOKEN",
"payer_info": {
"email": "buyer@example.com",
"external_user_id": "customer_1042"
},
"payment_source": {
"method_type": "credit_card",
"payment_method": "YOUR_PAYMENT_METHOD_TOKEN"
}
})
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
const data = await response.json();import requests
response = requests.request(
"POST",
"https://api.sandbox.deuna.io/v2/merchants/orders/purchase",
headers={
"X-Api-Key": "${DEUNA_PRIVATE_API_KEY}",
"X-Idempotency-Key": "order_1042-attempt_1",
"Content-Type": "application/json"
},
json={
"order_token": "YOUR_SANDBOX_ORDER_TOKEN",
"payer_info": {
"email": "buyer@example.com",
"external_user_id": "customer_1042"
},
"payment_source": {
"method_type": "credit_card",
"payment_method": "YOUR_PAYMENT_METHOD_TOKEN"
}
},
)
response.raise_for_status()
data = response.json()<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.sandbox.deuna.io/v2/merchants/orders/purchase",
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"X-Api-Key: ${DEUNA_PRIVATE_API_KEY}",
"X-Idempotency-Key: order_1042-attempt_1",
"Content-Type: application/json"
],
CURLOPT_POSTFIELDS => json_encode([
"order_token" => "YOUR_SANDBOX_ORDER_TOKEN",
"payer_info" => [
"email" => "buyer@example.com",
"external_user_id" => "customer_1042"
],
"payment_source" => [
"method_type" => "credit_card",
"payment_method" => "YOUR_PAYMENT_METHOD_TOKEN"
]
])
]);
$response = curl_exec($curl);
curl_close($curl);import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Example {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.sandbox.deuna.io/v2/merchants/orders/purchase"))
.header("X-Api-Key", "${DEUNA_PRIVATE_API_KEY}")
.header("X-Idempotency-Key", "order_1042-attempt_1")
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{\n \"order_token\": \"YOUR_SANDBOX_ORDER_TOKEN\",\n \"payer_info\": {\n \"email\": \"buyer@example.com\",\n \"external_user_id\": \"customer_1042\"\n },\n \"payment_source\": {\n \"method_type\": \"credit_card\",\n \"payment_method\": \"YOUR_PAYMENT_METHOD_TOKEN\"\n }\n }"))
.build();
HttpResponse<String> response = HttpClient.newHttpClient().send(
request, HttpResponse.BodyHandlers.ofString()
);
System.out.println(response.body());
}
}package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
request, err := http.NewRequest("POST", "https://api.sandbox.deuna.io/v2/merchants/orders/purchase", strings.NewReader("{\n \"order_token\": \"YOUR_SANDBOX_ORDER_TOKEN\",\n \"payer_info\": {\n \"email\": \"buyer@example.com\",\n \"external_user_id\": \"customer_1042\"\n },\n \"payment_source\": {\n \"method_type\": \"credit_card\",\n \"payment_method\": \"YOUR_PAYMENT_METHOD_TOKEN\"\n }\n }"))
if err != nil { panic(err) }
request.Header.Set("X-Api-Key", "${DEUNA_PRIVATE_API_KEY}")
request.Header.Set("X-Idempotency-Key", "order_1042-attempt_1")
request.Header.Set("Content-Type", "application/json")
response, err := http.DefaultClient.Do(request)
if err != nil { panic(err) }
defer response.Body.Close()
body, _ := io.ReadAll(response.Body)
fmt.Println(string(body))
}Le exact payment_source et n'importe quelle specific_fields dépendent du mode de paiement et du fournisseur sélectionnés. Voir Traiter le paiement d’une commande pour le contrat de demande complète.
Gérer le résultat immédiat#
Lire order.payment.data.status et toute action suivante requise de l'ordre retourné. Un HTTP 2xx signifie que DEUNA a accepté ou traité la demande; elle ne prouve pas en soi que l'argent a été déplacé.
- Continuer à remplir les obligations uniquement pour l'état de réussite confirmé documenté dans Workflow et statuts de paiement.
- Présentez toute action client, comme l'authentification 3DS, avant de réessayer.
- Pour les résultats en attente ou incertains, récupérer l'ordre original au lieu de créer une tentative dupliquée.
- Utilisez une nouvelle clé d'idempotency uniquement pour une nouvelle tentative de paiement matériellement.
Confirmer l'état final#
Utilisez la réponse synchrone pour mettre à jour l'expérience client, mais prenez des décisions de réalisation à partir de l'état vérifié le plus récent. Configurer un webhook marchand, vérifier sa signature, déduire l'événement, puis réconcilier l'ordre.
app.post('/webhooks/deuna', express.raw({type: 'application/json'}), async (request, response) => {
const event = verifyDeunaSignature(request.body, request.headers);
await storeEventOnce(event.id);
await reconcileOrder(event.data.order_token);
response.sendStatus(200);
});