المدفوعات

صفحة الدفع المستضافة

صفحة دفع نستضيفها للبطاقة والنقد، بألوانك. كيف تنشئ جلسة دفع، وما يراه عميلك، وكيف تنتهي الجلسة.

فتح بصيغة Markdown
في هذه الصفحة
  1. حياة الجلسة
  2. أنشئ جلسة
  3. أرسل عميلك إلى الصفحة
  4. ما يراه عميلك
  5. اعرف متى تم الدفع
  6. أنهِ صلاحية جلسة
  7. علامتك التجارية
  8. بلا كود إطلاقًا

صفحة الدفع المستضافة (hosted checkout) صفحة دفع يستضيفها AdProMaxPay لك. ينشئ خادمك جلسة دفع (checkout session)، ويدفع عميلك في الصفحة بالبطاقة أو نقدًا، ويعرف خادمك النتيجة من webhook. لا تتعامل مع رقم بطاقة أبدًا، وتعمل الجلسة نفسها مع الطريقتين.

الصفحة:

  • تعرض شعارك واسم نشاطك التجاري والمبلغ وجهة اتصال الدعم لديك؛
  • تتحدث الفرنسية والإنجليزية والعربية: تتبع متصفح عميلك، وتعود إلى الفرنسية إذا تعذّر عليها تحديد اللغة، وفيها مبدّل للغة؛
  • مصممة للهواتف أولًا، وزر ادفع في المتناول دائمًا؛
  • تحمل شريطًا مخططًا TEST في وضع الاختبار، حتى لا يخلط أحد بين صفحة اختبار وصفحة حقيقية.

لتجربتها من البداية إلى النهاية في عشر دقائق، اتبع البدء السريع للبطاقة.

حياة الجلسة

حالات جلسة الدفع
  • open → complete: دُفعت
  • open → expired: انتهت دون دفع، أو أنهيتها أنت

تكون الجلسة open منذ إنشائها. تصبح complete عند نجاح نية الدفع (payment intent) الخاصة بها، وexpired عند بلوغها expires_at دون دفع، أو عندما تنهي صلاحيتها أنت. لكل جلسة نية دفع واحدة، يسميها الحقل payment_intent.

أنشئ جلسة

أنشئ جلسة واحدة لكل طلبية يوشك عميلك أن يدفعها، عبر POST /v1/checkout/sessions. ترويسة Idempotency-Key إلزامية: انظر عدم التكرار (idempotency).

المعاملما يحمله
amountالمبلغ، عدد صحيح بالسنتيم: 45000 تساوي 450.00 MAD.
currencyدائمًا mad.
payment_method_typesالطرق التي يمكن لعميلك اختيارها: card أو cash أو كلتاهما. يُعرض الدفع نقدًا ابتداءً من 100.00 MAD.
success_urlالعنوان الذي ترسل إليه الصفحة عميلك بعد الدفع. بـ https؛ ويُقبل http://localhost في وضع الاختبار فقط.
cancel_urlالعنوان الذي يرسل إليه رجوع عميلك قبل الدفع. القاعدة نفسها.
expires_atاختياري. وقت انتهاء الجلسة، بثواني Unix، بين 30 دقيقة و24 ساعة من الآن. 24 ساعة افتراضيًا.
customerاختياري. عميل (cus_…) من المؤسسة نفسها والوضع نفسه: تظهر الدفعة في سجله.
metadataاختياري. مراجعك الخاصة، مثل رقم الطلبية: انظر البيانات الوصفية.

الاستجابة هي الجلسة: id وurl وpayment_intent وstatus الخاصة بها. احفظ معرّف نية الدفع مع طلبيتك: تذكره الأحداث التي تتلقاها.

  • 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(())
}
الاستجابة200 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
}

أرسل عميلك إلى الصفحة

أعد توجيه متصفح عميلك إلى url الجلسة برمز HTTP 303، كما في البدء السريع.

احتفظ بالعنوان كاملًا، بما فيه الجزء الذي يلي #. هذا الجزء هو وسيلة وصول عميلك إلى هذه الجلسة: لا ترسله المتصفحات إلى أي خادم أبدًا، فيبقى خارج السجلات. لا تسجّله ولا تختصره ولا ترسله إلى أحد غير عميلك.

ما يراه عميلك

أولًا، المبلغ والاختيار بين الطرق التي عرضتها.

بالبطاقة:

  1. يختار عميلك البطاقة ويضغط ادفع. تجهّز الصفحة الدفعة، ثم توضح أنها ستنقله إلى صفحة البطاقة الآمنة لشريكنا في البطاقات. في وضع الاختبار، تلك الصفحة هي محاكاتنا التي تحمل علامة TEST، ولا تقبل إلا بطاقات الاختبار.
  2. يكتب بيانات بطاقته في تلك الصفحة. وإذا طلب بنكه 3-D Secure، يؤكد هناك.
  3. يعود إلى صفحتنا، فتعرض «جارٍ التأكيد مع بنكك…» إلى أن تتأكد الدفعة، ثم صفحة النجاح.
  4. بعد 5 ثوانٍ، ترسله صفحة النجاح إلى success_url.

إذا رُفضت البطاقة، تذكر الصفحة السبب وتعرض جرّب بطاقة أخرى، أو ادفع نقدًا بدلًا من ذلك إن كنت عرضت الدفع نقدًا وكان المبلغ 100.00 MAD على الأقل. انظر الدفع بالبطاقة.

نقدًا: يدخل عميلك اسمه الكامل ومدينته (رقم الهاتف اختياري)، ثم يحصل على قسيمة فيها رمز دفع يسدده لدى وكيل دفع شريك. انظر الدفع نقدًا.

في الطريقتين، يمكن لعميلك إدخال عنوان بريد إلكتروني لتلقي إيصال؛ ولا يُرسل الإيصال إلا إذا أدخله.

رابط رجوع في الصفحة، وهو يذكر اسم نشاطك التجاري، يرسل عميلك إلى cancel_url. تبقى الجلسة open إلى أن تنتهي صلاحيتها، فيظل url نفسه يعمل إن عاد.

اعرف متى تم الدفع

نفّذ الطلبية عند أحد هذه الأحداث، لا عند العودة إلى success_url أبدًا:

الحدثمتى
payment_intent.succeededنجحت نية الدفع الخاصة بالجلسة.
checkout.session.completedدُفعت الجلسة: ويذكر الحدث payment_intent الخاص بها.
checkout.session.expiredانتهت الجلسة دون دفع. حرّر الطلبية أو المخزون.

تتلقى أيضًا الأحداث الأخرى لنية الدفع، مثل payment_intent.payment_failed بعد رفض بطاقة. اقرأ إعادة التوجيه وإشعارات webhook لتعرف لماذا لا تثبت العودة شيئًا.

رمز الدفع النقدي الذي حصل عليه عميلك يحتفظ بأجله الخاص، نحو ثلاثة أيام، حتى لو حلّ expires_at الجلسة قبله: يستطيع سداده مع ذلك.

أنهِ صلاحية جلسة

إذا أُلغيت الطلبية أو نفد المخزون، فأنهِ صلاحية الجلسة المفتوحة بنفسك عبر POST /v1/checkout/sessions/{id}/expire. تصبح الجلسة expired وتُلغى نية الدفع غير المدفوعة الخاصة بها: لا يستطيع عميلك دفعها بعد ذلك. لا يمكن إنهاء صلاحية جلسة إلا إذا كانت open.

لقراءة جلسة من جديد، استخدم GET /v1/checkout/sessions/{id}؛ ولعرض قائمة الجلسات، 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(())
}

علامتك التجارية

اضبط مظهر الصفحة مرة واحدة، من لوحة التحكم في الإعدادات ← العلامة التجارية:

  • شعار بصيغة PNG أو JPEG أو WebP، حتى 512 KB؛
  • الاسم المعروض وبريد الدعم الإلكتروني وهاتفه؛
  • لون للزر: إذا كان النص الأبيض صعب القراءة عليه، يُغمَّق اللون حتى يصبح مقروءًا، وتخبرك صفحة الإعدادات بذلك؛
  • خلفية بيضاء، أو خلفية ملوّنة تلوينًا خفيفًا بلونك.

تستخدم صفحة القسيمة في الدفع نقدًا الإعدادات نفسها.

بلا كود إطلاقًا

رابط الدفع، الذي يُنشأ من لوحة التحكم، يفتح الصفحة المستضافة نفسها لكل من لديه الرابط. انظر بلا كود: رابط دفع.