【发布时间】:2021-02-08 14:01:38
【问题描述】:
注意:我认为我遇到的问题与一般的 PayPal API 问题有关,但无论如何我都会包含我的 R 代码:
我使用 PayPal Transaction Search API 在 R 中编写了一些代码。它只是抓取事务并将它们显示在数据框(表)中。
这与我的 Sandbox 凭据一起工作正常(它显示了我在那里的一项交易)。但是,当我更改为实时凭据时,即使关联的真实账户中有更多交易,也没有数据返回。
为了“上线”,我的代码将请求 URL 更改为“https://api.paypal.com”,并将用户名和密码更改为实时凭据。它没有做任何其他事情。
我想知道是否需要采取其他措施?我已经确保在 Live App 设置下勾选了相关框(因此为 Live App 勾选了 Transaction API)。我还假设开发人员帐户/实时应用程序与其列出的 PayPal 帐户电子邮件相关联,因此将从该(真实)帐户中提取交易。
library(curl)
library(lubridate)
library(rjson)
library(magrittr)
library(dplyr)
# https://cran.r-project.org/web/packages/curl/vignettes/intro.html
# https://developer.paypal.com/docs/integration/direct/transaction-search/
# https://developer.paypal.com/docs/integration/direct/payments/paypal-payments/#
sandbox.creds <- list(username = "sandbox_username",
password = "sandbox_password")
live.creds <- list(username = "live_username",
password = "live_password")
# instantiate vars
api_url <- " "
user_pwd <- " "
access.token <<- NA
access.token.expires <<- NA
live.or.sandbox <- function(live) {
# set these vars to NA whenever this function is called
# otherwise the live vs. sandbox API will not find the access token
access.token <<- NA
access.token.expires <<- NA
if (live == TRUE) {
print("setting to live credentials")
api_url <<- "https://api.paypal.com"
user_pwd <<- paste0(live.creds[[1]],":",live.creds[[2]])
}
else {
print("setting to sandbox credentials")
api_url <<- "https://api.sandbox.paypal.com"
user_pwd <<- paste0(sandbox.creds[[1]],":",sandbox.creds[[2]])
}
}
# set live or sandbox
live.or.sandbox(live = TRUE)
# body --------------------------------------------------------------------
get.access.token <- function() {
req_access_token <- curl::new_handle() %>%
handle_setopt(copypostfields = "grant_type=client_credentials", userpwd = user_pwd, verbose=TRUE, httpauth = 1L) %>%
handle_setheaders("Accept" = "application/json",
"Accept-Language" = "en_US") %>%
curl_fetch_memory(url = paste0(api_url, "/v1/oauth2/token")) %$% content %>%
rawToChar %>% rjson::fromJSON()
access.token.expires <<- lubridate::as_datetime(lubridate::as_datetime(Sys.time()) + lubridate::dseconds(req_access_token$expires_in))
access.token <<- req_access_token$access_token
}
get.access.token.if.current.not.expired <- function() {
current_time <- lubridate::as_datetime(Sys.time())
cat("access token state: ", access.token)
# only request a new access token if one hasn't been generated yet and if previous requests haven't expired
if (is.na(access.token)) {
print("no access token")
get.access.token()
}
else {
print("already access token")
if(access.token.expires < as_date(Sys.time())) {
print("last access token has expired")
print("get new access token")
get.access.token()
}
else {
print("use old access token")
cat("time left is ",
as.integer(difftime(access.token.expires,
as_datetime(Sys.time()),
units = "secs")))
}
}
}
make.transaction.request <- function(start_date, end_date) {
# check if new access token required
get.access.token.if.current.not.expired()
bearer.access.token <- paste0("Bearer ", access.token)
req_transactions <- new_handle() %>%
handle_setheaders("Accept" = "application/json",
"Authorization" = bearer.access.token) %>%
curl_fetch_memory(url = paste0(api_url,"/v1/reporting/transactions?fields=all&start_date=",start_date,"&end_date=", end_date, "&fields=all")) %$% content %>%
rawToChar %>% rjson::fromJSON()
print("transaction request")
print(req_transactions)
# just return transaction details
req_transactions$transaction_details
}
format.date.rfc339 <- function(date) {
format(lubridate::as_datetime(date), "%Y-%m-%dT%H:%M:%SZ")
}
# current date in required rfc 339 format
# the maximum date range is 30, so several requests must be made to go beyond this
return.transactions <- function(number_months, tidy_transactions, live) {
if(live == TRUE) {
live.or.sandbox(live = TRUE)
}
else {
live.or.sandbox(live = FALSE)
}
# a month here really means 30 days.
# thus this function returns number_months * 30 days backwards from the present
current_date <- lubridate::as_datetime(Sys.time())
# convert dates to rfc339 format
dates <- lapply(1:number_months, function(x) format.date.rfc339(current_date - ddays((x*30))) )
# get a transaction request for each date range
res <- list()
for (i in 1:number_months) {
if (i < number_months) {
start_date <- dates[[i+1]]
end_date <- dates[[i]]
res[[i]] <- make.transaction.request(start_date, end_date)
}
}
if (tidy_transactions == TRUE) {
transactions <- bind_cols(res)
names(transactions) <- c("transaction_id", "transaction_event_code",
"date", "transaction_updated_date",
"currency_code", "value", "transaction_status",
"transaction_subject", "currency_code", "value",
"currency_code", "value2", "protection_eligibility")
transactions <- transactions[, c("transaction_id", "date", "value")]
transactions <- transactions %>% mutate(value = sapply(value, function(x) paste0("£", x)),
date = sapply(date, function(x) format(as_date(x), format="%B %d %Y"))
)
}
else {
res
}
}
transactions_live <- return.transactions(4, tidy_transactions = FALSE, live = TRUE)
# empty
transactions_sandbox <- return.transactions(4, tidy_transactions = FALSE, live = FALSE)
这是我在实时模式下得到的响应:
* Connection 90 seems to be dead!
* Closing connection 90
* Trying 66.211.168.123...
* TCP_NODELAY set
* Connected to api.paypal.com (66.211.168.123) port 443 (#91)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/cert.pem
CApath: none
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use http/1.1
* Server certificate:
* subject: C=US; ST=California; L=San Jose; O=PayPal, Inc.; OU=PayPal Production; CN=api.paypal.com
* start date: Jul 28 00:00:00 2020 GMT
* expire date: Aug 2 12:00:00 2022 GMT
* subjectAltName: host "api.paypal.com" matched cert's "api.paypal.com"
* issuer: C=US; O=DigiCert Inc; OU=www.digicert.com; CN=DigiCert SHA2 High Assurance Server CA
* SSL certificate verify ok.
* Server auth using Basic with user 'my_username'
> POST /v1/oauth2/token HTTP/1.1
Host: api.paypal.com
Authorization: Basic blahblahQVZtUWtXlcasdklsdS3VTME93sadjksdjpYlRSXzE2Si11LTVBS19DYnFVX1BlWlBQREcwT25OeTVSTHdQOTVyV0F4WUasdjasdoOUM4bzluQmN6MGg5ckFzbWQ=
User-Agent: RStudio Desktop (1.2.5033); R (3.6.3 x86_64-apple-darwin15.6.0 x86_64 darwin15.6.0)
Accept-Encoding: deflate, gzip
Accept: application/json
Accept-Language: en_US
Content-Length: 29
Content-Type: application/x-www-form-urlencoded
* upload completely sent off: 29 out of 29 bytes
< HTTP/1.1 200 OK
< Content-Type: application/json
< Content-Length: 972
< Connection: keep-alive
< Date: Mon, 26 Oct 2020 13:05:54 GMT
< Cache-Control: max-age=0, no-cache, no-store, must-revalidate
< Paypal-Debug-Id: 431a3fb2c4f43
< X-Paypal-Token-Service: IAAS
< Strict-Transport-Security: max-age=31536000; includeSubDomains
<
* Connection #91 to host api.paypal.com left intact
除了“Strict-Transport-Security”标头外,这似乎与沙盒模式相同:
* Connection 91 seems to be dead!
* Closing connection 91
* Connection 92 seems to be dead!
* Closing connection 92
* Trying 173.0.82.78...
* TCP_NODELAY set
* Connected to api.sandbox.paypal.com (173.0.82.78) port 443 (#93)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/cert.pem
CApath: none
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server did not agree to a protocol
* Server certificate:
* subject: C=US; ST=California; L=San Jose; O=PayPal, Inc.; OU=PayPal Production; CN=api.sandbox.paypal.com
* start date: Jul 27 00:00:00 2020 GMT
* expire date: Aug 1 12:00:00 2022 GMT
* subjectAltName: host "api.sandbox.paypal.com" matched cert's "api.sandbox.paypal.com"
* issuer: C=US; O=DigiCert Inc; OU=www.digicert.com; CN=DigiCert SHA2 High Assurance Server CA
* SSL certificate verify ok.
* Server auth using Basic with user 'sandbox_username'
> POST /v1/oauth2/token HTTP/1.1
Host: api.sandbox.paypal.com
Authorization: Basic blahblahT1I3MmJrSk5asjdkasjdkasjdksajkdjaskjdksajdkjsakdadkpasdUDF6cDBscjlnTWxaMXBScnl2WmR2YU91cGM=
User-Agent: RStudio Desktop (1.2.5033); R (3.6.3 x86_64-apple-darwin15.6.0 x86_64 darwin15.6.0)
Accept-Encoding: deflate, gzip
Accept: application/json
Accept-Language: en_US
Content-Length: 29
Content-Type: application/x-www-form-urlencoded
* upload completely sent off: 29 out of 29 bytes
< HTTP/1.1 200 OK
< Cache-Control: max-age=0, no-cache, no-store, must-revalidate
< Content-Length: 972
< Content-Type: application/json
< Date: Mon, 26 Oct 2020 15:07:46 GMT
< Paypal-Debug-Id: 89a06d70502df
< X-Paypal-Token-Service: IAAS
<
* Connection #93 to host api.sandbox.paypal.com left intact
交易调用:
* Found bundle for host api.paypal.com: 0x7f835d4f5810 [can pipeline]
* Could pipeline, but not asked to!
* Re-using existing connection! (#3) with host api.paypal.com
* Connected to api.paypal.com (66.211.168.123) port 443 (#3)
> GET /v1/reporting/transactions?fields=all&start_date=2020-06-28T19:49:23Z&end_date=2020-07-28T19:49:23Z&fields=all HTTP/1.1
Host: api.paypal.com
User-Agent: RStudio Desktop (1.2.5033); R (3.6.3 x86_64-apple-darwin15.6.0 x86_64 darwin15.6.0)
Accept-Encoding: deflate, gzip
Accept: application/json
Authorization: Bearer blahsduas9fuyiwjwf_vX1d_p8n3keJy8ZSvyjZasdkfdkdsfdsLL8MgQf3RN0R9sEHAXystT7EXqlgasdjasdasosCsxjtBotQ
< HTTP/1.1 200 OK
< Content-Type: application/json
< Content-Length: 442
< Connection: keep-alive
< Date: Mon, 26 Oct 2020 19:49:25 GMT
< Application_id: APP-09E52asjdasd0071E
< Cache-Control: max-age=0, no-cache, no-store, must-revalidate
< Caller_acct_num: YXGDSFU9DSFBU7TUE
< Paypal-Debug-Id: aadd1bcasduasd239
< Strict-Transport-Security: max-age=31536000; includeSubDomains
<
* Connection #3 to host api.paypal.com left intact
【问题讨论】:
标签: r curl paypal paypal-sandbox