Suivez-nous :

Intégrer une API PayPal en PHP pour débutant et facilement

Publié le 20 juin 2017 • par 3VG

Intégrer une API PayPal en PHP pour débutant et facilement

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

  1. Pré-requis & concepts clés
  2. Création des identifiants PayPal (Sandbox)
  3. Arborescence de projet (PHP)
  4. Obtenir un access token (OAuth2)
  5. Créer un Order (intention CAPTURE) côté serveur
  6. Capturer le paiement après approbation
  7. Vérifier un webhook (sécurité)
  8. Front minimal (optionnel) avec PayPal JS SDK
  9. Passage en production (Live)
  10. Intégration WordPress (snippet rapide)
  11. 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 :
    1. Votre serveur crée un Order auprès de PayPal (montant, devise, etc.)
    2. L’utilisateur approuve sur la page PayPal
    3. Votre serveur capture l’Order pour confirmer le paiement
    4. PayPal envoie un webhook (confirmation asynchrone)

Devise la plus courante : USD ou EUR. Pour l’Afrique de l’Ouest, on utilise souvent XOF (vérifiez la disponibilité côté PayPal pour votre compte).


2) Créer les identifiants (Sandbox)

  1. Allez sur developer.paypal.comDashboardMy Apps & Credentials.
  2. Onglet Sandbox, créez une App → récupérez Client ID et Secret.
  3. 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 via pp_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’API verify-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&currency=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)

  1. Dans le Dashboard, onglet Live → créez une App → récupérez Client ID & Secret.
  2. Mettez MODE=live dans .env.
  3. Remplacez l’URL SDK JS avec votre Client ID Live.
  4. Activez et vérifiez vos webhooks Live.
  5. 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&currency=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

 

Partager

Aucun commentaire

Soyez le premier à laisser un commentaire