Sinh viên vào trang https://www.paypal.com/ để thực hiện đăng ký tài khoản. Vui lòng điền đầy đủ các thông tin cần thiết theo yêu cầu, bao gồm loại tài khoản, quốc gia, email và số điện thoại. Lưu ý: Không nên cung cấp thông tin thẻ tín dụng ABC XYZ cho trang PayPal nếu không thực sự cần thiết.
[Nên] Chọn tài khoản loại Personal.
Điền thông tin số phone hợp lệ ứng với quốc gia đã chọn ở trên.
Bước 0: Chuẩn bị
Truy cập trang https://developer.paypal.com/ thực hiện đăng nhập bằng thông tin đăng nhập bằng thông tin đã tạo ở mục A. Sau đó, thực hiện lần lượt Bước 1 và Bước 2 dưới đây.
Bước 1: Tạo tài khoản buyer và seller dạng sanbox:
Truy cập trang https://developer.paypal.com/dashboard/accounts
Tạo các tài khoản Sandbox gồm:
01 tài khoản người bán (Business/Merchant Account)
01 hoặc nhiều tài khoản người mua (Personal/Buyer Account)
Ví dụ về tạo tài khoản người mua (Personal) như các bước phía dưới:
Sau khi bấm nút Create Account, hệ thống tự sinh một account với thông tin tùy ý. Để chỉnh sửa thông tin cho dễ nhó, cuối dòng chứa account, bấm nút ba chấm và View/Edit account để thay đổi thông tin email, password, Paypal balance (số dư).
Màn hình edit một account cụ thể.
Chỉnh sửa email.
Chỉnh số dư tối đa 100000 USD.
Sau khi tạo xong ta được 2 (hay nhiều) account sandbox:
Truy cập https://sandbox.paypal.com và đăng nhập bằng tài khoản Sandbox vừa tạo để kiểm tra thông tin và lịch sử giao dịch.
P/s: Pass dễ nhớ Abcdef@123
Giao diện sandbox Business account (Merchant)
Bước 2: Tạo API Key để tích hợp vào website
Truy cập mục Apps & Credentials tại: https://developer.paypal.com/dashboard/applications/sandbox
Chọn Create App, nhập:
App Name (tên ứng dụng)
Chọn loại tài khoản: Business (Merchant / người bán)
Liên kết với tài khoản người bán đã tạo ở Bước 1
Sau khi tạo xong, hệ thống sẽ cung cấp:
App Name
Client ID
Secret Key
Dùng các thông tin này để cấu hình tích hợp vào ứng dụng web (.NET Core) hoặc tương đương.
JavaScript SDK reference (https://developer.paypal.com/sdk/js/reference)
Quy trình thanh toán đơn hàng:
Chọn nút thanh toán ==> Create Order
Đăng nhập tài khoản Buyer/người mua ==> Authenticate)
Phê duyệt giao dịch trên paypal: OnApprove ==> Capture (thực hiện transaction trên paypal)
Xử lý kết quả trả về
https://developer.paypal.com/docs/checkout/standard/upgrade-integration/
Bước 1: Nhúng thư viện paypal JS SDK
<script src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID">
// Replace YOUR_CLIENT_ID with your sandbox client ID
Bước 2: Chèn chỗ đặt button thanh toán
<!-- Set up a container element for the button -->
<div id="paypal-button-container"></div>
Bước 3: Chèn đoạn mã gọi các thao tác
<script>
paypal.Buttons({
style: {
layout: 'vertical',
color: 'silver',
tagline: 'false'
},
async createOrder() {
const response = await fetch("/payment/create-paypal-order", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"value": "1234", //Lấy từ giỏ hàng của bạn (client)
"currency_code": "USD"
})
});
const order = await response.json();
return order.id;
},
async onApprove(data) {
// Capture the funds from the transaction.
const response = await fetch(`/payment/capture-paypal-order?orderId=${data.orderID}`, {
method: "POST"
});
const details = await response.json();
// Show success message to buyer
window.location.href = "/payment/PaymentSuccess";
},
onCancel(data) {
// Show a cancel page, or return to cart
window.location.assign("/your-cancel-page");
}
}).render('#paypal-button-container');
</script>
Xem thêm một số hướng dẫn [chi tiết] bằng ASP.NET Core ở đây: https://bit.ly/ecommerce-mvc
Định nghĩa lớp PaypalClient (thao tác kiểm tra tài khoản, tạo order, ghi nhận order) và các lớp liên quan.
public sealed class PaypalClient
{
public string Mode { get; }
public string ClientId { get; }
public string ClientSecret { get; }
public string BaseUrl => Mode == "Live"
? "https://api-m.paypal.com"
: "https://api-m.sandbox.paypal.com";
public PaypalClient(string clientId, string clientSecret, string mode)
{
ClientId = clientId;
ClientSecret = clientSecret;
Mode = mode;
}
private async Task<AuthResponse> Authenticate()
{
var auth = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{ClientId}:{ClientSecret}"));
var content = new List<KeyValuePair<string, string>>
{
new("grant_type", "client_credentials")
};
var request = new HttpRequestMessage
{
RequestUri = new Uri($"{BaseUrl}/v1/oauth2/token"),
Method = HttpMethod.Post,
Headers =
{
{ "Authorization", $"Basic {auth}" }
},
Content = new FormUrlEncodedContent(content)
};
var httpClient = new HttpClient();
var httpResponse = await httpClient.SendAsync(request);
var jsonResponse = await httpResponse.Content.ReadAsStringAsync();
var response = JsonSerializer.Deserialize<AuthResponse>(jsonResponse);
return response;
}
public async Task<CreateOrderResponse> CreateOrder(string value, string currency, string reference)
{
var auth = await Authenticate();
var request = new CreateOrderRequest
{
intent = "CAPTURE",
purchase_units = new List<PurchaseUnit>
{
new()
{
reference_id = reference,
amount = new Amount
{
currency_code = currency,
value = value
}
}
}
};
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = AuthenticationHeaderValue.Parse($"Bearer {auth.access_token}");
var httpResponse = await httpClient.PostAsJsonAsync($"{BaseUrl}/v2/checkout/orders", request);
var jsonResponse = await httpResponse.Content.ReadAsStringAsync();
var response = JsonSerializer.Deserialize<CreateOrderResponse>(jsonResponse);
return response;
}
public async Task<CaptureOrderResponse> CaptureOrder(string orderId)
{
var auth = await Authenticate();
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = AuthenticationHeaderValue.Parse($"Bearer {auth.access_token}");
var httpContent = new StringContent("", Encoding.Default, "application/json");
var httpResponse = await httpClient.PostAsync($"{BaseUrl}/v2/checkout/orders/{orderId}/capture", httpContent);
var jsonResponse = await httpResponse.Content.ReadAsStringAsync();
var response = JsonSerializer.Deserialize<CaptureOrderResponse>(jsonResponse);
return response;
}
}
public sealed class AuthResponse
{
public string scope { get; set; }
public string access_token { get; set; }
public string token_type { get; set; }
public string app_id { get; set; }
public int expires_in { get; set; }
public string nonce { get; set; }
}
public sealed class CreateOrderRequest
{
public string intent { get; set; }
public List<PurchaseUnit> purchase_units { get; set; } = new();
}
public sealed class CreateOrderResponse
{
public string id { get; set; }
public string status { get; set; }
public List<Link> links { get; set; }
}
public sealed class CaptureOrderResponse
{
public string id { get; set; }
public string status { get; set; }
public PaymentSource payment_source { get; set; }
public List<PurchaseUnit> purchase_units { get; set; }
public Payer payer { get; set; }
public List<Link> links { get; set; }
}
public sealed class PurchaseUnit
{
public Amount amount { get; set; }
public string reference_id { get; set; }
public Shipping shipping { get; set; }
public Payments payments { get; set; }
}
public sealed class Payments
{
public List<Capture> captures { get; set; }
}
public sealed class Shipping
{
public Address address { get; set; }
}
public class Capture
{
public string id { get; set; }
public string status { get; set; }
public Amount amount { get; set; }
public SellerProtection seller_protection { get; set; }
public bool final_capture { get; set; }
public string disbursement_mode { get; set; }
public SellerReceivableBreakdown seller_receivable_breakdown { get; set; }
public DateTime create_time { get; set; }
public DateTime update_time { get; set; }
public List<Link> links { get; set; }
}
public class Amount
{
public string currency_code { get; set; }
public string value { get; set; }
}
public sealed class Link
{
public string href { get; set; }
public string rel { get; set; }
public string method { get; set; }
}
public sealed class Name
{
public string given_name { get; set; }
public string surname { get; set; }
}
public sealed class SellerProtection
{
public string status { get; set; }
public List<string> dispute_categories { get; set; }
}
public sealed class SellerReceivableBreakdown
{
public Amount gross_amount { get; set; }
public PaypalFee paypal_fee { get; set; }
public Amount net_amount { get; set; }
}
public sealed class Paypal
{
public Name name { get; set; }
public string email_address { get; set; }
public string account_id { get; set; }
}
public sealed class PaypalFee
{
public string currency_code { get; set; }
public string value { get; set; }
}
public class Address
{
public string address_line_1 { get; set; }
public string address_line_2 { get; set; }
public string admin_area_2 { get; set; }
public string admin_area_1 { get; set; }
public string postal_code { get; set; }
public string country_code { get; set; }
}
public sealed class Payer
{
public Name name { get; set; }
public string email_address { get; set; }
public string payer_id { get; set; }
}
public sealed class PaymentSource
{
public Paypal paypal { get; set; }
}
Phần appsettings.json thêm phần config dành cho Paypal:
"PaypalOptions": {
"Mode": "Sandbox",
"ClientId": "id",
"ClientSecret": "secret"
},
Đăng ký PaypalClient dạng Singleton ở Program.cs
builder.Services.AddSingleton<PaypalClient>(x =>
new PaypalClient(
builder.Configuration["PayPalOptions:ClientId"],
builder.Configuration["PayPalOptions:ClientSecret"],
builder.Configuration["PayPalOptions:Mode"]
)
);
Viết code cho controller payment
public class PaymentController : Controller
{
private readonly PaypalClient _paypalClient;
public PaymentController(PaypalClient paypalClient)
{
_paypalClient = paypalClient;
}
[HttpPost("/payment/create-paypal-order")]
public async Task<IActionResult> CreateOrder([FromBody] Amount amount)
{
//số tiền có thể lấy từ Session hoặc dưới client gửi lên
var value = "1234";
var currency_code = "USD";
var refId = DateTime.Now.Ticks.ToString();
try
{
var response = await _paypalClient.CreateOrder(value, currency_code, refId);
return Ok(response);
}
catch (Exception ex)
{
var error = new { ex.GetBaseException().Message };
return BadRequest(error);
}
}
[HttpPost("/payment/capture-paypal-order")]
public IActionResult CaptureOrder(string orderID)
{
try
{
var response = _paypalClient.CaptureOrder(orderID);
//Lưu đơn hàng vô database
return Ok(response);
}
catch (Exception ex)
{
var error = new { ex.GetBaseException().Message };
return BadRequest(error);
}
}
}