Tutoriel SEO (débutant) — Intégrer l’API PayPal en PHP facilement (Sandbox → Live)
Objectif : accepter des paiements PayPal avec PHP en moins d’1h, en commençant par le mode Sandbox puis passage en production. Compatible WordPress (template, plugin custom) ou PHP “from scratch”.
Sommaire
- Pré-requis & concepts clés
- Création des identifiants PayPal (Sandbox)
- Arborescence de projet (PHP)
- Obtenir un access token (OAuth2)
- Créer un Order (intention
CAPTURE
) côté serveur - Capturer le paiement après approbation
- Vérifier un webhook (sécurité)
- Front minimal (optionnel) avec PayPal JS SDK
- Passage en production (Live)
- Intégration WordPress (snippet rapide)
- Conseils SEO & FAQ (rich snippet)
1) Pré-requis & concepts clés
- Compte PayPal Business (gratuit pour sandbox).
- Clés API :
Client ID
&Secret
(Sandbox puis Live). - API REST v2 : endpoints
/v2/checkout/orders
(Create/Capture). - Flux standard :
- Votre serveur crée un Order auprès de PayPal (montant, devise, etc.)
- L’utilisateur approuve sur la page PayPal
- Votre serveur capture l’Order pour confirmer le paiement
- PayPal envoie un webhook (confirmation asynchrone)
Devise la plus courante :
USD
ouEUR
. Pour l’Afrique de l’Ouest, on utilise souventXOF
(vérifiez la disponibilité côté PayPal pour votre compte).
2) Créer les identifiants (Sandbox)
- Allez sur developer.paypal.com → Dashboard → My Apps & Credentials.
- Onglet Sandbox, créez une App → récupérez Client ID et Secret.
- Créez un Sandbox Business (vendeur) et un Sandbox Personal (acheteur) pour tester.
Base URLs :
- Sandbox :
https://api-m.sandbox.paypal.com
- Live :
https://api-m.paypal.com
3) Arborescence de projet
/paypal-php
├─ .env # CLIENT_ID=... / CLIENT_SECRET=... / MODE=sandbox|live
├─ config.php
├─ create-order.php
├─ capture-order.php
├─ webhook.php
└─ utils.php
config.php
<?php
// Charge .env (facultatif) ou remplacez par des constantes
$env = parse_ini_file(__DIR__ . '/.env');
define('PP_MODE', $env['MODE'] ?? 'sandbox'); // sandbox | live
define('PP_CLIENT_ID', $env['CLIENT_ID'] ?? '');
define('PP_SECRET', $env['CLIENT_SECRET'] ?? '');
function pp_base_url() {
return PP_MODE === 'live'
? 'https://api-m.paypal.com'
: 'https://api-m.sandbox.paypal.com';
}
utils.php
<?php
require __DIR__.'/config.php';
function pp_token() {
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => pp_base_url().'/v1/oauth2/token',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_USERPWD => PP_CLIENT_ID . ':' . PP_SECRET,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => 'grant_type=client_credentials',
CURLOPT_HTTPHEADER => ['Accept: application/json','Accept-Language: en_US'],
]);
$res = curl_exec($ch);
if ($res === false) { throw new Exception(curl_error($ch)); }
$data = json_decode($res, true);
curl_close($ch);
if (empty($data['access_token'])) { throw new Exception('Token error'); }
return $data['access_token'];
}
function pp_request($method, $endpoint, $payload = null) {
$token = pp_token();
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => pp_base_url().$endpoint,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Authorization: Bearer '.$token
],
]);
if ($payload) curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
$res = curl_exec($ch);
if ($res === false) { throw new Exception(curl_error($ch)); }
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return [$code, json_decode($res, true)];
}
function json_out($data, $code = 200) {
http_response_code($code);
header('Content-Type: application/json; charset=utf-8');
echo json_encode($data, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT);
exit;
}
4) Obtenir un access token (OAuth2)
Déjà géré dans
utils.php
viapp_token()
. Test rapide :
<?php
// test-token.php (optionnel)
require __DIR__.'/utils.php';
try {
$token = pp_token();
json_out(['ok' => true, 'token_sample' => substr($token,0,12).'...']);
} catch (Throwable $e) {
json_out(['ok' => false, 'error' => $e->getMessage()], 500);
}
5) Créer un Order (serveur)
create-order.php
<?php
require __DIR__.'/utils.php';
$amount = $_POST['amount'] ?? '10.00';
$currency = $_POST['currency'] ?? 'USD';
$payload = [
'intent' => 'CAPTURE',
'purchase_units' => [[
'amount' => [
'currency_code' => $currency,
'value' => $amount
]
]],
'application_context' => [
'brand_name' => 'Ma Boutique',
'landing_page' => 'NO_PREFERENCE',
'user_action' => 'PAY_NOW',
// Vos URLs (frontend) : le client y revient après approbation/annulation
'return_url' => 'https://example.com/success',
'cancel_url' => 'https://example.com/cancel'
]
];
list($code, $res) = pp_request('POST', '/v2/checkout/orders', $payload);
if ($code >= 200 && $code < 300) {
json_out($res);
} else {
json_out(['ok'=>false,'code'=>$code,'res'=>$res], $code);
}
Réponse attendue (extrait) :
{
"id": "5O190127TN364715T",
"status": "CREATED",
"links": [
{"href":".../approve","rel":"approve","method":"GET"}
]
}
- Redirigez l’utilisateur vers le lien
rel=approve
ou utilisez le SDK JS (section 8).
6) Capturer le paiement
Après approbation, PayPal vous renvoie un token
côté front. Côté serveur, on capture l’Order :
capture-order.php
<?php
require __DIR__.'/utils.php';
$orderId = $_POST['orderID'] ?? null;
if (!$orderId) json_out(['ok'=>false,'error'=>'orderID manquant'], 422);
list($code, $res) = pp_request('POST', "/v2/checkout/orders/$orderId/capture");
if ($code >= 200 && $code < 300) {
// Enregistrer la transaction dans votre DB ici
json_out(['ok'=>true,'data'=>$res]);
} else {
json_out(['ok'=>false,'code'=>$code,'res'=>$res], $code);
}
Statut réussi : COMPLETED
avec un capture.id
. Conservez l’ID et le montant.
7) Webhook (recommandé)
- Configurez un Webhook dans le Dashboard (Sandbox d’abord).
- Événements utiles :
CHECKOUT.ORDER.APPROVED
,PAYMENT.CAPTURE.COMPLETED
.
webhook.php (simplifié)
En production, validez la signature avec les en-têtes
PAYPAL-TRANSMISSION-*
et l’APIverify-webhook-signature
. (Ici: pseudo-validation à compléter.)
<?php
require __DIR__.'/utils.php';
// Récupération brute
$body = file_get_contents('php://input');
$event = json_decode($body, true);
// TODO: Vérifier la signature via /v1/notifications/verify-webhook-signature
// Doc: envoyez transmission_id, timestamp, cert_url, auth_algo, transmission_sig, webhook_id, et le corps
if (!empty($event['event_type'])) {
// Exemple: PAYMENT.CAPTURE.COMPLETED
// Mettez à jour votre DB (statut commande, email client, etc.)
http_response_code(200);
echo 'OK';
} else {
http_response_code(400);
echo 'Invalid';
}
Sécurité à respecter absolument :
- Ne stockez jamais
Client Secret
dans le front. - Stockez les secrets en
.env
ou variables d’environnement. - Vérifiez le webhook (signature).
- Forcez HTTPS et vérifiez l’amount/devise reçus vs vos propres données.
8) Front minimal (optionnel) avec PayPal JS SDK
Dans votre page (HTML) :
<script src="https://www.paypal.com/sdk/js?client-id=VOTRE_CLIENT_ID_SANDBOX¤cy=USD"></script>
<div id="paypal-button-container"></div>
<script>
paypal.Buttons({
createOrder: async function() {
const res = await fetch('/paypal-php/create-order.php', {method:'POST'});
const data = await res.json();
return data.id; // orderID
},
onApprove: async function(data) {
const res = await fetch('/paypal-php/capture-order.php', {
method:'POST',
headers:{'Content-Type':'application/x-www-form-urlencoded'},
body: new URLSearchParams({orderID: data.orderID})
});
const out = await res.json();
if (out.ok) {
// Afficher "Paiement réussi", rediriger, etc.
alert('Paiement réussi ✅');
} else {
alert('Erreur capture ❌');
}
}
}).render('#paypal-button-container');
</script>
9) Passer en production (Live)
- Dans le Dashboard, onglet Live → créez une App → récupérez
Client ID
&Secret
. - Mettez
MODE=live
dans.env
. - Remplacez l’URL SDK JS avec votre Client ID Live.
- Activez et vérifiez vos webhooks Live.
- Testez un petit montant réel.
10) Intégration WordPress (snippet rapide)
Ajoutez un endpoint via un mini plugin :
<?php
/**
* Plugin Name: PayPal Gateway (Lite)
*/
if (!defined('ABSPATH')) exit;
add_action('rest_api_init', function() {
register_rest_route('paypal/v1','/create',[
'methods' => 'POST',
'callback' => function(WP_REST_Request $r){
require __DIR__.'/paypal-php/utils.php';
$amount = $r->get_param('amount') ?: '10.00';
$payload = [
'intent'=>'CAPTURE',
'purchase_units'=>[[ 'amount'=>['currency_code'=>'USD','value'=>$amount] ]]
];
list($code,$res) = pp_request('POST','/v2/checkout/orders',$payload);
return new WP_REST_Response($res, $code);
},
'permission_callback' => '__return_true'
]);
register_rest_route('paypal/v1','/capture',[
'methods' => 'POST',
'callback' => function(WP_REST_Request $r){
require __DIR__.'/paypal-php/utils.php';
$orderId = $r->get_param('orderID');
list($code,$res) = pp_request('POST',"/v2/checkout/orders/$orderId/capture");
return new WP_REST_Response($res, $code);
},
'permission_callback' => '__return_true'
]);
});
Front (dans une page WP) :
<script src="https://www.paypal.com/sdk/js?client-id=VOTRE_CLIENT_ID¤cy=USD"></script>
<div id="paypal-button-container"></div>
<script>
paypal.Buttons({
createOrder: async () => {
const r = await fetch('/wp-json/paypal/v1/create', {method:'POST'});
const j = await r.json();
return j.id;
},
onApprove: async (data) => {
const r = await fetch('/wp-json/paypal/v1/capture', {
method:'POST',
headers:{'Content-Type':'application/json'},
body: JSON.stringify({orderID: data.orderID})
});
const j = await r.json();
if (j.status === 'COMPLETED') alert('Paiement OK');
}
}).render('#paypal-button-container');
</script>
Faites correspondre la devise, la TVA et vos validations (montant côté serveur).
11) SEO : structure prête à ranker + FAQ
Balises conseillées (Rank Math / Yoast)
- Titre : Intégrer l’API PayPal en PHP (Tutoriel Débutant + Code)
- Meta description : Guide pas à pas pour connecter PayPal en PHP : sandbox, création & capture d’Orders, webhooks et intégration WordPress. Code prêt à copier.
- Mots-clés (variantes longue traîne) :
- intégrer PayPal en PHP, API PayPal PHP débutant, PayPal sandbox PHP, capture order PayPal PHP, webhook PayPal PHP, WordPress PayPal API sans plugin
- H1 unique + H2 structurés (comme ce tutoriel).
- FAQPage JSON-LD (copiez/collez) :
<script type="application/ld+json">
{
"@context":"https://schema.org",
"@type":"FAQPage",
"mainEntity":[
{
"@type":"Question",
"name":"Comment obtenir un access token PayPal en PHP ?",
"acceptedAnswer":{"@type":"Answer","text":"Utilisez l'endpoint /v1/oauth2/token avec vos identifiants (Client ID/Secret) en Basic Auth et le paramètre grant_type=client_credentials. Voir fonction pp_token()."}
},
{
"@type":"Question",
"name":"Quelle est la différence entre Sandbox et Live ?",
"acceptedAnswer":{"@type":"Answer","text":"Sandbox sert aux tests avec de l'argent fictif. Live est la production. Les bases d'URL et vos identifiants (Client ID/Secret) changent."}
},
{
"@type":"Question",
"name":"Comment sécuriser les webhooks PayPal ?",
"acceptedAnswer":{"@type":"Answer","text":"Vérifiez la signature via l’API verify-webhook-signature en envoyant les en-têtes transmis par PayPal, le webhook_id et le corps exact de la requête."}
}
]}
</script>
Bonnes pratiques SEO techniques
- Page rapide (minifier CSS/JS, cache).
- Core Web Vitals OK (lazyload, images WebP).
- Données structurées (FAQ + Article).
- Maillage interne : liez vers “Paiement par carte”, “Configurer Stripe”, “Sécuriser un webhook”, etc.
- CTA clair : “Obtenir l’ID client PayPal”, “Tester en Sandbox”.
Dépannage (erreurs fréquentes)
401 Unauthorized
lors du token : vérifiez Client ID/Secret + Base URL correcte (Sandbox vs Live).ORDER_NOT_APPROVED
: l’utilisateur n’a pas validé.INVALID_RESOURCE_ID
à la capture : utilisez l’id
reçu à la création.- Webhook non reçu : URL pas publique/HTTPS, event non abonné, signature non validée.
- Montant/Devise incohérents entre front et back : source de litige → toujours valider côté serveur.
Checklist passage en prod
- MODE=
live
+ nouveaux identifiants - Webhook Live + signature OK
- Montants réels & TVA
- Logs d’erreurs centralisés
- Page de succès/échec UX propre + emails
Aucun commentaire
Soyez le premier à laisser un commentaire