Paiements

Page de paiement hébergée

Une page de paiement que nous hébergeons pour la carte et les espèces, à vos couleurs. Créer une session de paiement, ce que voit votre client, et comment une session se termine.

Ouvrir en Markdown
Sur cette page
  1. La vie d’une session
  2. Créer une session
  3. Envoyer votre client sur la page
  4. Ce que voit votre client
  5. Savoir quand c’est payé
  6. Faire expirer une session
  7. Votre image de marque
  8. Sans aucun code

La page de paiement hébergée est une page que AdProMaxPay héberge pour vous. Votre serveur crée une session de paiement (checkout session), votre client paie sur la page par carte ou en espèces, et votre serveur apprend le résultat par un webhook. Vous ne manipulez jamais un numéro de carte, et la même session sert pour les deux moyens de paiement.

La page :

  • montre votre logo, le nom de votre entreprise, le montant et votre contact d’assistance ;
  • parle français, anglais et arabe : elle suit la langue du navigateur de votre client, prend le français quand elle ne peut pas savoir, et propose un sélecteur de langue ;
  • est pensée d’abord pour le téléphone, avec le bouton Payer toujours à portée ;
  • porte en mode test un bandeau rayé TEST, pour que personne ne prenne une page de test pour une vraie.

Pour l’essayer de bout en bout en dix minutes, suivez le démarrage rapide carte.

La vie d’une session

Les statuts d’une session de paiement
  • open → complete: payée
  • open → expired: terminée sans paiement, ou expirée par vous

Une session est open dès sa création. Elle devient complete quand son intention de paiement réussit, et expired quand elle atteint son expires_at sans avoir été payée, ou quand vous la faites expirer. Chaque session a une intention de paiement, nommée par son payment_intent.

Créer une session

Créez une session pour chaque commande que votre client s’apprête à payer, avec POST /v1/checkout/sessions. L’en-tête Idempotency-Key est obligatoire : voir Idempotence.

ParamètreCe qu’il contient
amountLe montant, un entier en centimes : 45000 vaut 450,00 MAD.
currencyToujours mad.
payment_method_typesLes moyens que votre client peut choisir : card, cash, ou les deux. Les espèces sont proposées à partir de 100,00 MAD.
success_urlLà où la page envoie votre client après le paiement. En https ; http://localhost n’est accepté qu’en mode test.
cancel_urlLà où Retour envoie votre client avant le paiement. Même règle.
expires_atFacultatif. La fin de la session, en secondes Unix, entre 30 minutes et 24 heures à partir de maintenant. 24 heures par défaut.
customerFacultatif. Un client (cus_…) de la même organisation et du même mode : le paiement apparaît dans son historique.
metadataFacultatif. Vos propres références, comme le numéro de commande : voir Métadonnées.

La réponse est la session : son id, son url, son payment_intent et son status. Conservez l’identifiant de l’intention de paiement avec votre commande : les événements que vous recevez le nomment.

  • curl
  • Node.js
  • TypeScript
  • Python
  • PHP
  • Ruby
  • Go
  • Java
  • C#
  • Rust
session.mjssession.tssession.pysession.phpsession.rbsession.goSession.javaSession.csmain.rs
curl https://pay-api.adpromax.com/v1/checkout/sessions \
  -u "$APX_SECRET_KEY:" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: checkout-order-2087" \
  -d '{
    "amount": 45000,
    "currency": "mad",
    "payment_method_types": ["card", "cash"],
    "success_url": "https://shop.example.com/orders/2087/thanks",
    "cancel_url": "https://shop.example.com/cart",
    "expires_at": '"$(($(date +%s) + 7200))"',
    "customer": "cus_01k7e2f9g3h6j8k2m5n7p4q1sd",
    "metadata": { "order_id": "2087" }
  }'
const response = await fetch('https://pay-api.adpromax.com/v1/checkout/sessions', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.APX_SECRET_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': 'checkout-order-2087',
  },
  body: JSON.stringify({
    amount: 45000,
    currency: 'mad',
    payment_method_types: ['card', 'cash'],
    success_url: 'https://shop.example.com/orders/2087/thanks',
    cancel_url: 'https://shop.example.com/cart',
    // Two hours from now, in Unix seconds.
    expires_at: Math.floor(Date.now() / 1000) + 2 * 60 * 60,
    customer: 'cus_01k7e2f9g3h6j8k2m5n7p4q1sd',
    metadata: { order_id: '2087' },
  }),
})
const session = await response.json()
if (!response.ok)
  throw new Error(session.error.message)
console.log(session.payment_intent, session.url)
interface CheckoutSession {
  id: string
  object: 'checkout.session'
  amount: number
  currency: string
  payment_intent: string
  status: string
  url: string
  expires_at: number
  customer: string | null
  metadata: Record<string, string>
}

interface ApiError {
  error: { type: string, code: string, message: string, request_id: string }
}

const response = await fetch('https://pay-api.adpromax.com/v1/checkout/sessions', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.APX_SECRET_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': 'checkout-order-2087',
  },
  body: JSON.stringify({
    amount: 45000,
    currency: 'mad',
    payment_method_types: ['card', 'cash'],
    success_url: 'https://shop.example.com/orders/2087/thanks',
    cancel_url: 'https://shop.example.com/cart',
    // Two hours from now, in Unix seconds.
    expires_at: Math.floor(Date.now() / 1000) + 2 * 60 * 60,
    customer: 'cus_01k7e2f9g3h6j8k2m5n7p4q1sd',
    metadata: { order_id: '2087' },
  }),
})
if (!response.ok) {
  const { error } = (await response.json()) as ApiError
  throw new Error(`${error.code}: ${error.message}`)
}
const session = (await response.json()) as CheckoutSession
console.log(session.payment_intent, session.url)
import os
import time

import requests

response = requests.post(
    "https://pay-api.adpromax.com/v1/checkout/sessions",
    auth=(os.environ["APX_SECRET_KEY"], ""),
    headers={"Idempotency-Key": "checkout-order-2087"},
    json={
        "amount": 45000,
        "currency": "mad",
        "payment_method_types": ["card", "cash"],
        "success_url": "https://shop.example.com/orders/2087/thanks",
        "cancel_url": "https://shop.example.com/cart",
        # Two hours from now, in Unix seconds.
        "expires_at": int(time.time()) + 2 * 60 * 60,
        "customer": "cus_01k7e2f9g3h6j8k2m5n7p4q1sd",
        "metadata": {"order_id": "2087"},
    },
)
session = response.json()
response.raise_for_status()
print(session["payment_intent"], session["url"])
<?php
$ch = curl_init('https://pay-api.adpromax.com/v1/checkout/sessions');
curl_setopt_array($ch, [
    CURLOPT_USERPWD => getenv('APX_SECRET_KEY') . ':',
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json',
        'Idempotency-Key: checkout-order-2087',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'amount' => 45000,
        'currency' => 'mad',
        'payment_method_types' => ['card', 'cash'],
        'success_url' => 'https://shop.example.com/orders/2087/thanks',
        'cancel_url' => 'https://shop.example.com/cart',
        // Two hours from now, in Unix seconds.
        'expires_at' => time() + 2 * 60 * 60,
        'customer' => 'cus_01k7e2f9g3h6j8k2m5n7p4q1sd',
        'metadata' => ['order_id' => '2087'],
    ]),
    CURLOPT_RETURNTRANSFER => true,
]);
$session = json_decode(curl_exec($ch), true);
echo $session['payment_intent'], ' ', $session['url'], PHP_EOL;
require 'json'
require 'net/http'

uri = URI('https://pay-api.adpromax.com/v1/checkout/sessions')
request = Net::HTTP::Post.new(uri)
request.basic_auth(ENV.fetch('APX_SECRET_KEY'), '')
request['Content-Type'] = 'application/json'
request['Idempotency-Key'] = 'checkout-order-2087'
request.body = JSON.generate(
  amount: 45000,
  currency: 'mad',
  payment_method_types: %w[card cash],
  success_url: 'https://shop.example.com/orders/2087/thanks',
  cancel_url: 'https://shop.example.com/cart',
  # Two hours from now, in Unix seconds.
  expires_at: Time.now.to_i + 2 * 60 * 60,
  customer: 'cus_01k7e2f9g3h6j8k2m5n7p4q1sd',
  metadata: { order_id: '2087' }
)

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
  http.request(request)
end
session = JSON.parse(response.body)
raise session.dig('error', 'message') unless response.is_a?(Net::HTTPSuccess)

puts "#{session['payment_intent']} #{session['url']}"
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"time"
)

type CheckoutSession struct {
	ID            string `json:"id"`
	PaymentIntent string `json:"payment_intent"`
	Status        string `json:"status"`
	URL           string `json:"url"`
	ExpiresAt     int64  `json:"expires_at"`
}

type APIError struct {
	Error struct {
		Code    string `json:"code"`
		Message string `json:"message"`
	} `json:"error"`
}

func main() {
	// Two hours from now, in Unix seconds.
	expiresAt := time.Now().Add(2 * time.Hour).Unix()
	body, err := json.Marshal(map[string]any{
		"amount":               45000,
		"currency":             "mad",
		"payment_method_types": []string{"card", "cash"},
		"success_url":          "https://shop.example.com/orders/2087/thanks",
		"cancel_url":           "https://shop.example.com/cart",
		"expires_at":           expiresAt,
		"customer":             "cus_01k7e2f9g3h6j8k2m5n7p4q1sd",
		"metadata":             map[string]string{"order_id": "2087"},
	})
	if err != nil {
		log.Fatal(err)
	}
	req, err := http.NewRequest(http.MethodPost,
		"https://pay-api.adpromax.com/v1/checkout/sessions", bytes.NewReader(body))
	if err != nil {
		log.Fatal(err)
	}
	req.SetBasicAuth(os.Getenv("APX_SECRET_KEY"), "")
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Idempotency-Key", "checkout-order-2087")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer res.Body.Close()

	if res.StatusCode >= 400 {
		var apiErr APIError
		json.NewDecoder(res.Body).Decode(&apiErr)
		log.Fatal(apiErr.Error.Message)
	}
	var session CheckoutSession
	if err := json.NewDecoder(res.Body).Decode(&session); err != nil {
		log.Fatal(err)
	}
	fmt.Println(session.PaymentIntent, session.URL)
}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Instant;

public class Session {
    public static void main(String[] args) throws Exception {
        // Two hours from now, in Unix seconds.
        long expiresAt = Instant.now().getEpochSecond() + 2 * 60 * 60;
        String body = """
            {
              "amount": 45000,
              "currency": "mad",
              "payment_method_types": ["card", "cash"],
              "success_url": "https://shop.example.com/orders/2087/thanks",
              "cancel_url": "https://shop.example.com/cart",
              "expires_at": %d,
              "customer": "cus_01k7e2f9g3h6j8k2m5n7p4q1sd",
              "metadata": { "order_id": "2087" }
            }
            """.formatted(expiresAt);
        HttpRequest request = HttpRequest.newBuilder(
                URI.create("https://pay-api.adpromax.com/v1/checkout/sessions"))
            .header("Authorization", "Bearer " + System.getenv("APX_SECRET_KEY"))
            .header("Content-Type", "application/json")
            .header("Idempotency-Key", "checkout-order-2087")
            .POST(HttpRequest.BodyPublishers.ofString(body))
            .build();
        HttpResponse<String> response = HttpClient.newHttpClient()
            .send(request, HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() >= 400) {
            throw new IllegalStateException(response.body());
        }
        // The session as JSON: read payment_intent and url with a JSON library.
        System.out.println(response.statusCode() + " " + response.body());
    }
}
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;

var json = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower };
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
    "Bearer", Environment.GetEnvironmentVariable("APX_SECRET_KEY"));

using var request = new HttpRequestMessage(
    HttpMethod.Post, "https://pay-api.adpromax.com/v1/checkout/sessions");
request.Headers.Add("Idempotency-Key", "checkout-order-2087");
request.Content = JsonContent.Create(new
{
    amount = 45000,
    currency = "mad",
    payment_method_types = new[] { "card", "cash" },
    success_url = "https://shop.example.com/orders/2087/thanks",
    cancel_url = "https://shop.example.com/cart",
    // Two hours from now, in Unix seconds.
    expires_at = DateTimeOffset.UtcNow.ToUnixTimeSeconds() + 2 * 60 * 60,
    customer = "cus_01k7e2f9g3h6j8k2m5n7p4q1sd",
    metadata = new { order_id = "2087" },
});

using var response = await http.SendAsync(request);
if (!response.IsSuccessStatusCode)
{
    var failure = await response.Content.ReadFromJsonAsync<ApiError>(json);
    throw new InvalidOperationException(failure?.Error.Message);
}
var session = await response.Content.ReadFromJsonAsync<CheckoutSession>(json);
Console.WriteLine($"{session!.PaymentIntent} {session.Url}");

record CheckoutSession(string Id, string PaymentIntent, string Status, string Url);
record ApiError(ApiErrorBody Error);
record ApiErrorBody(string Code, string Message);
// Cargo.toml: reqwest = { version = "0.12", features = ["blocking", "json"] }
//             serde = { version = "1", features = ["derive"] }
//             serde_json = "1"
use std::time::{SystemTime, UNIX_EPOCH};

use serde::Deserialize;
use serde_json::json;

#[derive(Deserialize)]
struct CheckoutSession {
    payment_intent: String,
    url: String,
}

#[derive(Deserialize)]
struct ApiError {
    error: ErrorBody,
}

#[derive(Deserialize)]
struct ErrorBody {
    message: String,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Two hours from now, in Unix seconds.
    let now = SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs();
    let expires_at = now + 2 * 60 * 60;

    let response = reqwest::blocking::Client::new()
        .post("https://pay-api.adpromax.com/v1/checkout/sessions")
        .bearer_auth(std::env::var("APX_SECRET_KEY")?)
        .header("Idempotency-Key", "checkout-order-2087")
        .json(&json!({
            "amount": 45000,
            "currency": "mad",
            "payment_method_types": ["card", "cash"],
            "success_url": "https://shop.example.com/orders/2087/thanks",
            "cancel_url": "https://shop.example.com/cart",
            "expires_at": expires_at,
            "customer": "cus_01k7e2f9g3h6j8k2m5n7p4q1sd",
            "metadata": { "order_id": "2087" }
        }))
        .send()?;
    if !response.status().is_success() {
        let failure: ApiError = response.json()?;
        return Err(failure.error.message.into());
    }
    let session: CheckoutSession = response.json()?;
    println!("{} {}", session.payment_intent, session.url);
    Ok(())
}
Réponse200 OK
{
  "id": "cs_01k7e3m5q8w2r6t9y4b7n1v5ca",
  "amount": 45000,
  "currency": "mad",
  "payment_method_types": ["card", "cash"],
  "payment_intent": "pi_01k7e3m5px4z8c2v6b9n3m7hra",
  "customer": "cus_01k7e2f9g3h6j8k2m5n7p4q1sd",
  "status": "open",
  "url": "https://pay.example.com/c/cs_01k7e3m5q8w2r6t9y4b7n1v5ca#…",
  "success_url": "https://shop.example.com/orders/2087/thanks",
  "cancel_url": "https://shop.example.com/cart",
  "expires_at": 1790854200,
  "metadata": { "order_id": "2087" },
  "livemode": false
}

Envoyer votre client sur la page

Redirigez le navigateur de votre client vers l’url de la session avec un HTTP 303, comme dans le démarrage rapide.

Gardez l’adresse entière, y compris la partie après #. Cette partie est l’accès de votre client à cette session : les navigateurs ne l’envoient jamais à un serveur, elle reste donc hors des journaux. Ne la journalisez pas, ne la raccourcissez pas, et ne l’envoyez à personne d’autre que votre client.

Ce que voit votre client

D’abord, le montant et un choix entre les moyens de paiement que vous avez proposés.

Par carte :

  1. Votre client choisit la carte et appuie sur Payer. La page prépare le paiement, puis explique qu’elle l’emmène sur la page carte sécurisée de notre partenaire carte. En mode test, cette page est notre simulation marquée TEST, qui n’accepte que les cartes de test.
  2. Il saisit sa carte sur cette page. Si sa banque demande 3-D Secure, il confirme là.
  3. Il revient sur notre page, qui affiche « Confirmation auprès de votre banque… » jusqu’à la confirmation du paiement, puis la page de réussite.
  4. Après 5 secondes, la page de réussite l’envoie sur votre success_url.

Si la carte est refusée, la page donne la raison et propose Essayer une autre carte, ou Payer en espèces quand vous avez proposé les espèces et que le montant atteint 100,00 MAD. Voir Paiements par carte.

En espèces : votre client donne son nom complet et sa ville (un numéro de téléphone est facultatif), puis reçoit un bon avec un code de paiement à régler chez un agent de paiement partenaire. Voir Paiements en espèces.

Pour les deux moyens, votre client peut donner une adresse e-mail pour recevoir un reçu ; le reçu n’est envoyé que s’il le fait.

Le lien ← Retour de la page, qui nomme votre entreprise, envoie votre client sur votre cancel_url. La session reste open jusqu’à son expiration : la même url fonctionne encore s’il revient.

Savoir quand c’est payé

Livrez la commande sur l’un de ces événements, jamais sur le retour à votre success_url :

ÉvénementQuand
payment_intent.succeededL’intention de paiement de la session a réussi.
checkout.session.completedLa session a été payée : elle nomme son payment_intent.
checkout.session.expiredLa session s’est terminée sans paiement. Libérez la commande ou le stock.

Vous recevez aussi les autres événements de l’intention de paiement, comme payment_intent.payment_failed après une carte refusée. Lisez Redirections et webhooks pour comprendre pourquoi le retour ne prouve rien.

Un code espèces que votre client a déjà reçu garde sa propre échéance, environ trois jours, même quand l’expires_at de la session arrive avant : il peut encore le payer.

Faire expirer une session

Si la commande est annulée ou que le stock est épuisé, faites expirer vous-même la session ouverte avec POST /v1/checkout/sessions/{id}/expire. La session devient expired et son intention de paiement non payée est annulée : votre client ne peut plus la payer. Seule une session open peut expirer ainsi.

Pour relire une session, utilisez GET /v1/checkout/sessions/{id} ; pour les lister, GET /v1/checkout/sessions.

  • curl
  • Node.js
  • TypeScript
  • Python
  • PHP
  • Ruby
  • Go
  • Java
  • C#
  • Rust
expire.mjsexpire.tsexpire.pyexpire.phpexpire.rbexpire.goExpire.javaExpire.csmain.rs
curl -X POST \
  https://pay-api.adpromax.com/v1/checkout/sessions/cs_01k7e3m5q8w2r6t9y4b7n1v5ca/expire \
  -u "$APX_SECRET_KEY:"
const id = 'cs_01k7e3m5q8w2r6t9y4b7n1v5ca'
const response = await fetch(`https://pay-api.adpromax.com/v1/checkout/sessions/${id}/expire`, {
  method: 'POST',
  headers: { Authorization: `Bearer ${process.env.APX_SECRET_KEY}` },
})
const session = await response.json()
console.log(session.status) // expired
interface CheckoutSession {
  id: string
  object: 'checkout.session'
  status: string
}

const id = 'cs_01k7e3m5q8w2r6t9y4b7n1v5ca'
const response = await fetch(`https://pay-api.adpromax.com/v1/checkout/sessions/${id}/expire`, {
  method: 'POST',
  headers: { Authorization: `Bearer ${process.env.APX_SECRET_KEY}` },
})
const session = (await response.json()) as CheckoutSession
console.log(session.status) // expired
import os

import requests

session_id = "cs_01k7e3m5q8w2r6t9y4b7n1v5ca"
response = requests.post(
    f"https://pay-api.adpromax.com/v1/checkout/sessions/{session_id}/expire",
    auth=(os.environ["APX_SECRET_KEY"], ""),
)
print(response.json()["status"])  # expired
<?php
$id = 'cs_01k7e3m5q8w2r6t9y4b7n1v5ca';
$ch = curl_init("https://pay-api.adpromax.com/v1/checkout/sessions/{$id}/expire");
curl_setopt_array($ch, [
    CURLOPT_USERPWD => getenv('APX_SECRET_KEY') . ':',
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
]);
$session = json_decode(curl_exec($ch), true);
echo $session['status'], PHP_EOL; // expired
require 'json'
require 'net/http'

id = 'cs_01k7e3m5q8w2r6t9y4b7n1v5ca'
uri = URI("https://pay-api.adpromax.com/v1/checkout/sessions/#{id}/expire")
request = Net::HTTP::Post.new(uri)
request.basic_auth(ENV.fetch('APX_SECRET_KEY'), '')

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
  http.request(request)
end
puts JSON.parse(response.body)['status'] # expired
package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
)

type CheckoutSession struct {
	ID     string `json:"id"`
	Status string `json:"status"`
}

func main() {
	id := "cs_01k7e3m5q8w2r6t9y4b7n1v5ca"
	req, err := http.NewRequest(http.MethodPost,
		"https://pay-api.adpromax.com/v1/checkout/sessions/"+id+"/expire", nil)
	if err != nil {
		log.Fatal(err)
	}
	req.SetBasicAuth(os.Getenv("APX_SECRET_KEY"), "")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer res.Body.Close()

	var session CheckoutSession
	if err := json.NewDecoder(res.Body).Decode(&session); err != nil {
		log.Fatal(err)
	}
	fmt.Println(session.Status) // expired
}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Expire {
    public static void main(String[] args) throws Exception {
        String id = "cs_01k7e3m5q8w2r6t9y4b7n1v5ca";
        HttpRequest request = HttpRequest.newBuilder(
                URI.create("https://pay-api.adpromax.com/v1/checkout/sessions/" + id + "/expire"))
            .header("Authorization", "Bearer " + System.getenv("APX_SECRET_KEY"))
            .POST(HttpRequest.BodyPublishers.noBody())
            .build();
        HttpResponse<String> response = HttpClient.newHttpClient()
            .send(request, HttpResponse.BodyHandlers.ofString());
        // The session as JSON: its status is now "expired".
        System.out.println(response.body());
    }
}
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;

var json = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower };
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
    "Bearer", Environment.GetEnvironmentVariable("APX_SECRET_KEY"));

var id = "cs_01k7e3m5q8w2r6t9y4b7n1v5ca";
using var response = await http.PostAsync(
    $"https://pay-api.adpromax.com/v1/checkout/sessions/{id}/expire", null);
var session = await response.Content.ReadFromJsonAsync<CheckoutSession>(json);
Console.WriteLine(session!.Status); // expired

record CheckoutSession(string Id, string Status);
// Cargo.toml: reqwest = { version = "0.12", features = ["blocking", "json"] }
//             serde = { version = "1", features = ["derive"] }
use serde::Deserialize;

#[derive(Deserialize)]
struct CheckoutSession {
    status: String,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let id = "cs_01k7e3m5q8w2r6t9y4b7n1v5ca";
    let session: CheckoutSession = reqwest::blocking::Client::new()
        .post(format!("https://pay-api.adpromax.com/v1/checkout/sessions/{id}/expire"))
        .bearer_auth(std::env::var("APX_SECRET_KEY")?)
        .send()?
        .json()?;
    println!("{}", session.status); // expired
    Ok(())
}

Votre image de marque

Réglez l’apparence de la page une fois, sur le tableau de bord sous Paramètres → Image de marque :

  • un logo, en PNG, JPEG ou WebP, jusqu’à 512 Ko ;
  • le nom affiché, ainsi que votre e-mail et votre téléphone d’assistance ;
  • une couleur de bouton : si un texte blanc y serait difficile à lire, elle est assombrie jusqu’à devenir lisible, et la page des paramètres vous le signale ;
  • un fond blanc, ou légèrement teinté de votre couleur.

La page du bon d’un paiement en espèces utilise les mêmes réglages.

Sans aucun code

Un lien de paiement, créé sur le tableau de bord, ouvre la même page hébergée pour toute personne qui a le lien. Voir Sans code : un lien de paiement.