Tìm hiểu cổng thanh toán điện từ PAY.JP (Phần I)
Bài đăng này đã không được cập nhật trong 6 năm
Giới thiệu chung
PAY.JP là một cổng thanh toán điện tử sử dụng API được xây dựng trên cơ sở RESTFULL, PAY.JP cung cấp rất nhiều phương thức thanh toán hữu ích và mềm dẻo trong hoạt động kinh doanh như:
- Có thể thanh toán mọi lúc mọi nơi
- Hỗ trợ rất nhiều ngôn ngữ lập trình.
- Có thể tạo plan dùng để thanh toán lặp lại nhiều lần
- Quản lý thông tin khách hàng
Xác thực
Để sử dụng API của PAY.JP bước đầu tiên bạn cần phải đăng ký một tài khoản developer trên trang chủ PAY.JP và lấy khóa API gồm:
- Public key: Khóa công khai tạo ra các mã thông báo được nhúng trong HTML
- Private key: Khóa bí mật có tác dụng như là xác thực người dùng từ các reuqest tới từ phía server.
Việc xác thực sẽ được thực hiện liên tục thông qua các xác thực cơ bản, lưu ý rằng Khóa bí mật là một chìa khóa quan trọng và cần được bảo mật tuyệt đối. Một sameple của private key sau khi đăng ký tài khoản
require "payjp"
Payjp.api_key = "sk_test_c62fade9d045b54cd76d7036"
Giao thức
Vì lý do bảo mật tất cả API đến từ PAY.JP đều được thực hiển bới giao thức HTTPS
Method
Khi thực hiện thanh tóan sử dụng API của PAY.JP bạn có thể sử dụng những method HTTP: GET, POST, DELETE
Response Format
Tất cả dữ liệu trả về của API đều sử dụng kiểu dữ liệu JSON
Thời gian
Thời gian được sử dụng trên PAY.JP là giờ UTC, đơn vị nhỏ nhất là giây.
Errors
Tất cả xử lý nếu gây lỗi đều sẽ được bắt, errors sẽ được trả về gôm mã lỗi dạng 4xx cho tới 5xx cùng với lý do gây lôi. Thông thường mã lỗi này chỉ phục vụ doanh nghiệp phát triển ứng dụng không nên show ra cho người dùng cuối. Danh sách mã lỗi đầy đủ bạn có thể tham khảo tại đây
Dưới đây là một ví dụ để bắt mã lỗi trong ruby
begin
# Use Payjp's library to make requests...
rescue Payjp::CardError => e
# Since it's a decline, Payjp::CardError will be caught
body = e.json_body
err = body[:error]
puts "Status is: #{e.http_status}"
puts "Type is: #{err[:type]}"
puts "Code is: #{err[:code]}"
# param is '' in this case
puts "Param is: #{err[:param]}"
puts "Message is: #{err[:message]}"
rescue Payjp::InvalidRequestError => e
# Invalid parameters were supplied to Payjp's API
rescue Payjp::AuthenticationError => e
# Authentication with Payjp's API failed
# (maybe you changed API keys recently)
rescue Payjp::APIConnectionError => e
# Network communication with Payjp failed
rescue Payjp::PayjpError => e
# Display a very generic error to the user, and maybe send
# yourself an email
rescue => e
# Something else happened, completely unrelated to Payjp
end
Phân trang
Trong dữ liệu trả về của PAY.JP cũng hỗ trợ việc phân trang nếu lượng dữ liệu quá lớn.
require 'payjp'
Payjp.api_key = 'sk_test_c62fade9d045b54cd76d7036'
customer = Payjp::Customer.retrieve('cus_4df4b5ed720933f4fb9e2857517')
customer.subscriptions.all(limit: 3, offset: 10)
Trong đó:
- Limit: Số lượng item lấy ra trên 1 trang, thường có giá trị từ 1 tới 100
- Offset: Vị trí bắt đầu lấy dữ liệu.
Charge (payment)
Create payment
Mỗi một giao dịch thanh toán được gắn với Token ID được sinh ra từ thẻ của khách hàng. Bạn cũng có thể sử dụng đối tượng Customer để thực hiện thanh toán, trong trường hợp đó thẻ được gán là mặc định của Customer sẽ được sử dụng.
Một lưu ý nhỏ là số tiền thanh toán bạn có thể giữ nó trong thẻ của khách hàng trong một khoảng thời gian nhất định bằng thuộc tính capture
, thời gian giữ tiền có thể kéo dài từ 1 tới 60 ngày, sau khi thời gian này kết thúc mà không được thanh toán thì số tiền trên sẽ được giải phóng cho chủ tài khoản.
Ví dụ:
require 'payjp'
Payjp.api_key = 'sk_test_c62fade9d045b54cd76d7036'
charge = Payjp::Charge.create(
:amount => 3500,
:card => 'tok_76e202b409f3da51a0706605ac81',
:currency => 'jpy',
)
Dữ liệu trả về tương ứng.
{
"amount": 3500,
"amount_refunded": 0,
"captured": true,
"captured_at": 1433127983,
"card": {
"address_city": null,
"address_line1": null,
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": "unchecked",
"brand": "Visa",
"country": null,
"created": 1433127983,
"customer": null,
"cvc_check": "unchecked",
"exp_month": 2,
"exp_year": 2020,
"fingerprint": "e1d8225886e3a7211127df751c86787f",
"id": "car_d0e44730f83b0a19ba6caee04160",
"last4": "4242",
"name": null,
"object": "card"
},
"created": 1433127983,
"currency": "jpy",
"customer": null,
"description": null,
"expired_at": null,
"failure_code": null,
"failure_message": null,
"id": "ch_fa990a4c10672a93053a774730b0a",
"livemode": false,
"metadata": null,
"object": "charge",
"paid": true,
"refund_reason": null,
"refunded": false,
"subscription": null
}
Trong trường hợp thanh toán xảy ra lỗi sẽ trả về errors theo format sau:
{
"error": {
"code": "invalid_number",
"message": "Your card number is invalid.",
"param": "card[number]",
"status": 400,
"type": "card_error"
}
}
Các thuộc tính trả về cụ thể sẽ được giải thích tại đây
Payment information
Để xem thông tin payments bạn chỉ cần sử dụng method retrieve
với id của payment
require 'payjp'
Payjp.api_key = 'sk_test_c62fade9d045b54cd76d7036'
Payjp::Charge.retrieve('ch_fa990a4c10672a93053a774730b0a')
Tương ứng kết quả trả về:
{
"amount": 3500,
"amount_refunded": 0,
"captured": true,
"captured_at": 1433127983,
"card": {
"address_city": null,
"address_line1": null,
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": "unchecked",
"brand": "Visa",
"country": null,
"created": 1433127983,
"customer": null,
"cvc_check": "unchecked",
"exp_month": 2,
"exp_year": 2020,
"fingerprint": "e1d8225886e3a7211127df751c86787f",
"id": "car_d0e44730f83b0a19ba6caee04160",
"last4": "4242",
"name": null,
"object": "card"
},
"created": 1433127983,
"currency": "jpy",
"customer": null,
"description": null,
"expired_at": null,
"failure_code": null,
"failure_message": null,
"id": "ch_fa990a4c10672a93053a774730b0a",
"livemode": false,
"metadata": null,
"object": "charge",
"paid": true,
"refund_reason": null,
"refunded": false,
"subscription": null
}
Nếu có errors trong quá trình lấy thông tin errors trả về dưới dạng sau:
{
"error": {
"message": "There is no charge with ID: dummy",
"param": "id",
"status": 404,
"type": "client_error"
}
}
Update payments infomation
Bạn cũng có thể update một số thông tin của payments bằng cách sau:
require 'payjp'
Payjp.api_key = 'sk_test_c62fade9d045b54cd7d7036'
charge = Payjp::Charge.retrieve('ch_fa990a4c10672a93053a774730b0a')
charge.description='Updated'
charge.save
Dữ liệu trả về và errors khi có cũng tương tự như trên.
Refund
PAY.JP cũng cung cấp một phương thức khá hữu ích là trả lại số tiền đã thanh toán trước đó cho chủ tài khoản nếu có yêu cầu, số tiền trả lại sẽ là số tiền được khai báo khi thanh toán.
require 'payjp'
Payjp.api_key = 'sk_test_c62fade9d045b54cd76d7036'
charge = Payjp::Charge.retrieve('ch_fa990a4c10672a93053a774730b0a')
charge.refund
Dữ liệu trả về dạng.
{
"amount": 3500,
"amount_refunded": 3500,
"captured": true,
"captured_at": 1433127983,
"card": {
"address_city": null,
"address_line1": null,
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": "unchecked",
"brand": "Visa",
"country": null,
"created": 1433127983,
"customer": null,
"cvc_check": "unchecked",
"exp_month": 2,
"exp_year": 2020,
"fingerprint": "e1d8225886e3a7211127df751c86787f",
"id": "car_d0e44730f83b0a19ba6caee04160",
"last4": "4242",
"name": null,
"object": "card"
},
"created": 1433127983,
"currency": "jpy",
"customer": null,
"description": "Updated",
"expired_at": null,
"failure_code": null,
"failure_message": null,
"id": "ch_fa990a4c10672a93053a774730b0a",
"livemode": false,
"metadata": null,
"object": "charge",
"paid": true,
"refund_reason": null,
"refunded": true,
"subscription": null
}
Payments list
Bạn cũng có thể lấy ra thông tin của thất cả các yêu cầu thanh toán đang có trong hệ thống bằng cách:
require 'payjp'
Payjp.api_key = 'sk_test_c62fade9d045b54cd76d7036'
Payjp::Charge.all(limit: 3, offset: 10)
Dữ liệu trả về dạng.
{
"count": 3,
"data": [
{
"amount": 1000,
"amount_refunded": 0,
"captured": true,
"captured_at": 1432965397,
"card": {
"address_city": "\u8d64\u5742",
"address_line1": "7-4",
"address_line2": "203",
"address_state": "\u6e2f\u533a",
"address_zip": "1070050",
"address_zip_check": "passed",
"brand": "Visa",
"country": "JP",
"created": 1432965397,
"cvc_check": "passed",
"customer": null,
"exp_month": 12,
"exp_year": 2016,
"fingerprint": "e1d8225886e3a7211127df751c86787f",
"id": "car_7a79b41fed704317ec0deb4ebf93",
"last4": "4242",
"name": "Test Hodler",
"object": "card"
},
"created": 1432965397,
"currency": "jpy",
"customer": "cus_67fab69c14d8888bba941ae2009b",
"description": "test charge",
"expired_at": null,
"failure_code": null,
"failure_message": null,
"id": "ch_6421ddf0e12a5e5641d7426f2a2c9",
"livemode": false,
"metadata": null,
"object": "charge",
"paid": true,
"refund_reason": null,
"refunded": false,
"subscription": null
},
{...},
{...}
],
"has_more": true,
"object": "list",
"url": "/v1/charges"
}
Định dạng errors trả về nếu có cũng tương tự như trên.
Kết luận
Thật đơn giản phải không? Trong phần này mình chỉ đề cập một số phương thức cơ bản của PAY.JP các phần còn lại như Customer, Plan, Token, Events .... mình xin viết tiếp ở phần sau. Thanks for reading !!!
All rights reserved