marko001 Posted January 31, 2023 Share Posted January 31, 2023 Hi all, I'm not smart enough to clearly understand how to "translate this code into AutoIt call, so I used what I did in the past but it doesn't work properly. Basically I need to receive the Auth Token in order to place further calls. API docs on Paypal site says: curl -v -X POST "https://api-m.sandbox.paypal.com/v1/oauth2/token" \ -u "<CLIENT_ID>:<CLIENT_SECRET>" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=client_credentials" or api-m.paypal.com if using live server. And this is my code (i just canceled the keys received from PP) #include <Array.au3> #include <string.au3> #include <MsgBoxConstants.au3> #Region Paypal Const Global $sURL = "https://api-m.paypal.com" ; /v1/oauth2/token - https://api-m.sandbox.paypal.com #EndRegion Paypal Const #Region keys Global $ClientID = "****" Global $SecretID = "****" #EndRegion keys _Test() Func _Test() Local $sResult = PayPalGet("/v1/oauth2/token") ConsoleWrite("$sResult: " & $sResult & @CRLF) EndFunc ;==>_Test Func PayPalGet($sMethod) Local $sJsonReq = '-u "' & $ClientID & ':' & $SecretID & '"' & _ '\ -H "Content-Type: application/x-www-form-urlencoded" \' & _ '-d "grant_type=client_credentials"' Local $oHTTP = ObjCreate("winhttp.winhttprequest.5.1") $oHTTP.Open("POST", $sURL & $sMethod, False) $oHTTP.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded") $oHTTP.Send(Binary($sJsonReq)) Local $sReceived = $oHTTP.ResponseText Return $sReceived Return $sReceived EndFunc ;==>PayPalGet When I run it I get: $sResult: {"error":"invalid_client","error_description":"Client Authentication failed"} Can you please help me to sort it out? Thanks in advance Marco Link to comment Share on other sites More sharing options...
genius257 Posted January 31, 2023 Share Posted January 31, 2023 Hi @marko001. This seems to be more of an issue with the PayPal API usage, than with AutoIt? Here is a stackoverflow question with the same issues. The answer I've linked directly to could be why, if you are certain that your client id and secret are 100% correct. My highlighted topics: AutoIt Package Manager, AutoItObject Pure AutoIt, AutoIt extension for Visual Studio Code Github: AutoIt HTTP Server, AutoIt HTML Parser Link to comment Share on other sites More sharing options...
marko001 Posted January 31, 2023 Author Share Posted January 31, 2023 Damn, hmm... I'm 100% outside US and indeed credentials are correct, provided by Paypal. But I did nothing to "approve" my Paypal credentials. I just have my business account. And, obviously, web page is not available from Italy... Shall I consider it a "not feasible" integration? Link to comment Share on other sites More sharing options...
marko001 Posted January 31, 2023 Author Share Posted January 31, 2023 Well, let's make things simpler: I already have a "Buy Now" button available on my product. What I need is to check if/when the transactions has been done. Basically I'd query Paypal to look for last transactions. If there's and easier way to approach that, that is my needing. Link to comment Share on other sites More sharing options...
marko001 Posted January 31, 2023 Author Share Posted January 31, 2023 @genius257 I just realized that my Paypal account is already a business account: That said I should access APIs: So is maybe the .au3 format invalid and need to be improved? Thanks Link to comment Share on other sites More sharing options...
mistersquirrle Posted January 31, 2023 Share Posted January 31, 2023 (edited) I don't think that you're building your request to PayPal correctly, you seem to mostly be copying the CURL code, with -u, -H, and -d, along with the slashes ( \ ), which are just code line breaks in their example. I would recommend using PostMan if you have it (or downloading it) and follow their steps for putting it in there, and you can look at the request/response headers to see how it should be set up. Keep in mind that ClientID and SecretID are Base64 encoded together with a : separating them when you send the authorization yourself. CURL is doing this when you provide that information through the -u param I did a quick test in PostMan, and looking at the code that it generates you likely want to change it to something like this: expandcollapse popup#include <Array.au3> #include <string.au3> #include <MsgBoxConstants.au3> #Region Paypal Const Local $sURL = "https://api-m.sandbox.paypal.com" ; /v1/oauth2/token - https://api-m.sandbox.paypal.com #EndRegion Paypal Const #Region keys ;Make sure that you're using the IDs from https://developer.paypal.com/dashboard/applications/edit Local $ClientID = '****' Local $SecretID = '****' Local $sEncodedAuth = StringStripWS(base64($ClientID & ':' & $SecretID), 8) __CW('$sEncodedAuth: ' & $sEncodedAuth) #EndRegion keys _Test() Func _Test() Local $sResult = PayPalGet("/v1/oauth2/token") __CW("$sResult: " & $sResult) EndFunc ;==>_Test Func PayPalGet($sMethod) Local $oHTTP = ObjCreate("winhttp.winhttprequest.5.1") Local $sParams = 'grant_type=client_credentials' __CW('Url: ' & $sURL & $sMethod) $oHTTP.Open("POST", $sURL & $sMethod, False) $oHTTP.SetRequestHeader("Authorization", 'Basic ' & $sEncodedAuth) __CW('Adding header: Authorization = Basic ' & $sEncodedAuth) $oHTTP.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded") __CW('Adding header: Content-Type = application/x-www-form-urlencoded') $oHTTP.Send($sParams) __CW($oHTTP.Status) Local $sReceived = $oHTTP.ResponseText Return $sReceived Return $sReceived EndFunc ;==>PayPalGet Func __CW($sMsg) ConsoleWrite($sMsg & @CRLF) EndFunc ; https://www.autoitscript.com/forum/topic/192404-base64-autoit-encode-decode-extra-fast/ ;============================================================================================================================== ; Function: base64($vCode [, $bEncode = True [, $bUrl = False]]) ; ; Description: Decode or Encode $vData using Microsoft.XMLDOM to Base64Binary or Base64Url. ; IMPORTANT! Encoded base64url is without @LF after 72 lines. Some websites may require this. ; ; Parameter(s): $vData - string or integer | Data to encode or decode. ; $bEncode - boolean | True - encode, False - decode. ; $bUrl - boolean | True - output is will decoded or encoded using base64url shema. ; ; Return Value(s): On Success - Returns output data ; On Failure - Returns 1 - Failed to create object. ; ; Author (s): (Ghads on Wordpress.com), Ascer ;=============================================================================================================================== Func base64($vCode, $bEncode = True, $bUrl = False) Local $oDM = ObjCreate("Microsoft.XMLDOM") If Not IsObj($oDM) Then Return SetError(1, 0, 1) Local $oEL = $oDM.createElement("Tmp") $oEL.DataType = "bin.base64" If $bEncode Then $oEL.NodeTypedValue = Binary($vCode) If Not $bUrl Then Return $oEL.Text Return StringReplace(StringReplace(StringReplace($oEL.Text, "+", "-"), "/", "_"), @LF, "") Else If $bUrl Then $vCode = StringReplace(StringReplace($vCode, "-", "+"), "_", "/") $oEL.Text = $vCode Return $oEL.NodeTypedValue EndIf EndFunc ;==>base64 I got a successful response like this: $sResult: {"scope":"https://uri.paypal.com/services/invoicing https://uri.paypal.com/services/disputes/read-buyer https://uri.paypal.com/services/payments/realtimepayment https://uri.paypal.com/services/disputes/update-seller https://uri.paypal.com/services/payments/payment/authcapture openid https://uri.paypal.com/services/disputes/read-seller https://uri.paypal.com/services/payments/refund https://api.paypal.com/v1/vault/credit-card https://api.paypal.com/v1/payments/.* https://uri.paypal.com/payments/payouts https://api.paypal.com/v1/vault/credit-card/.* https://uri.paypal.com/services/subscriptions https://uri.paypal.com/services/applications/webhooks","access_token":""} Edit: Also make sure that you're using the provided Client and Secret for your account, NOT your username and password to login. Edited January 31, 2023 by mistersquirrle We ought not to misbehave, but we should look as though we could. Link to comment Share on other sites More sharing options...
marko001 Posted January 31, 2023 Author Share Posted January 31, 2023 (edited) @mistersquirrle let me check it out now. Proably it's as I said before, I made a wrong call but credentials were fine. I'll edit this post $sResult: {"scope":"https://uri.paypal.com/services/checkout/one-click-with-merchant-issued-token https://uri.paypal.com/services/invoicing https://uri.paypal.com/services/vault/payment-tokens/read https://uri.paypal.com/services/disputes/read-buyer https://uri.paypal.com/services/payments/realtimepayment https://uri.paypal.com/services/disputes/update-seller https://uri.paypal.com/services/payments/payment/authcapture openid https://uri.paypal.com/services/disputes/read-seller Braintree:Vault https://uri.paypal.com/services/payments/refund https://api.paypal.com/v1/vault/credit-card https://uri.paypal.com/services/billing-agreements https://api.paypal.com/v1/payments/.* https://uri.paypal.com/services/reporting/search/read https://uri.paypal.com/payments/payouts https://uri.paypal.com/services/vault/payment-tokens/readwrite https://api.paypal.com/v1/vault/credit-card/.* https://uri.paypal.com/services/shipping/trackers/readwrite https://uri.paypal.com/servicessubscriptions https://uri.paypal.com/services/applications/webhooks","access_token":"XXXXXXXXXXXXXXXX","token_type":"Bearer","app_id":"APP-XXXXXXXXXXX","expires_in":32252,"nonce":"2023-01-31T23:19:59Zo_XXXXXXXXXXX"} I believe that's what I was looking for! Let's see now if' I'm able to use that token to make API calls... Should I just JSONDecode() the result and pick the token to use for further calls, right? Edited February 1, 2023 by marko001 Link to comment Share on other sites More sharing options...
mistersquirrle Posted January 31, 2023 Share Posted January 31, 2023 (edited) @marko001 If that is your uneditted/original access_token, I strongly recommend editing and deleting part of it, with the access_token someone else can use your account to do/access anything (aka why I excluded it from my post). Otherwise, correct, decode the JSON and use the access_token in further calls, adding it using something like: $oHTTP.SetRequestHeader("Authorization", 'Bearer ' & $sAccessToken) You may also want to either keep track of the token and renew it when it expires, or you could/should be able to just get a new token each time. Edit: It might also be a good idea to decode the 'token_type' and use it like $sTokenType & ' ' & $sAccessToken, just in case it changes from 'Bearer' at some point, but I HIGHLY doubt that'd happen. Edited January 31, 2023 by mistersquirrle We ought not to misbehave, but we should look as though we could. Link to comment Share on other sites More sharing options...
marko001 Posted January 31, 2023 Author Share Posted January 31, 2023 yeah, I just posted it 'cause anyway it expires soon. but thanks, I removed some chars from the token Link to comment Share on other sites More sharing options...
marko001 Posted February 3, 2023 Author Share Posted February 3, 2023 @mistersquirrle I have an issue when trying to create an order: expandcollapse popupLocal $sEncodedAuth = StringStripWS(base64($ClientID & ':' & $SecretID), 8) Global $token _Test() Func _Test() Local $sResult = PayPalGetToken("/v1/oauth2/token") Local $oJsonReturned = Json_Decode($sResult) $token = Json_Get($oJsonReturned, '["access_token"]') __CW("Token: " & $token) $sResult = PaypalCreateOrder($token,"/v2/checkout/orders") __CW("Result: " & $sResult) EndFunc ;==>_Test Func PayPalGetToken($sMethod) Local $oHTTP = ObjCreate("winhttp.winhttprequest.5.1") Local $sParams = 'grant_type=client_credentials' $oHTTP.Open("POST", $sURL & $sMethod, False) $oHTTP.SetRequestHeader("Authorization", 'Basic ' & $sEncodedAuth) $oHTTP.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded") $oHTTP.Send($sParams) Local $sReceived = $oHTTP.ResponseText Return $sReceived EndFunc ;==>PayPalGet Func PaypalCreateOrder($token,$sMethod) Local $sJsonOrder='{' & _ '"intent" : "CAPTURE",' & _ '"purchase_units" : [' & _ '{' & _ '"reference_id" : ' & _NewGUID() & '",' & _ '"amount": {' & _ '"currency_code": "EUR",' & _ '"value": "1' & _ '}' & _ '}' & _ '],' & _ '}' Local $oHTTP = ObjCreate("winhttp.winhttprequest.5.1") $oHTTP.Open("POST", $sURL & $sMethod, False) $oHTTP.SetRequestHeader("Content-Type", "application/json") $oHTTP.SetRequestHeader("Authorization", 'Bearer ' & $token) $oHTTP.SetRequestHeader("PayPal-Request-Id", _NewGUID()) $oHTTP.Send($sJsonOrder) Local $sReceived = $oHTTP.ResponseText Return $sReceived EndFunc Func _NewGUID() Return StringLower(StringReplace(StringReplace(StringReplace(_WinAPI_CreateGUID(), "-", ""), "{", ""), "}", "")) EndFunc ;==>_NewGUID This is the format as from developer Paypal website: My return is: {"name":"INVALID_REQUEST","message":"Request is not well-formed, syntactically incorrect, or violates schema.","debug_id":"c068984d77db3","details":[{"field":"/purchase_units/0","location":"body","issue":"MALFORMED_REQUEST_JSON","description":"The request JSON is not well formed."}],"links":[{"href":"https://developer.paypal.com/docs/api/orders/v2/#error-MALFORMED_REQUEST_JSON","rel":"information_link","encType":"application/json"}]} So probably there's something in the array containing purchase_units that's not working properly. Thanks in advance, M. Link to comment Share on other sites More sharing options...
TheXman Posted February 3, 2023 Share Posted February 3, 2023 (edited) If you displayed the value of $sJsonOrder, you would see something like this: {"intent" : "CAPTURE","purchase_units" : [{"reference_id" : 0769578d09fe424fa8f776e5001b3a57","amount": {"currency_code": "EUR","value": "1}}],} I see 3 errors: The "reference_id" value is missing a leading double quote. The "value" value is missing a trailing double quote. The comma right before the ending brace should not be there. Assuming everything else is correct, the JSON should look something like this: {"intent" : "CAPTURE","purchase_units" : [{"reference_id" : "99bc9f7ac7934e318ba6c2cd29265af2","amount": {"currency_code": "EUR","value": "1"}}]} Edited February 3, 2023 by TheXman CryptoNG UDF: Cryptography API: Next Gen jq UDF: Powerful and Flexible JSON Processor | jqPlayground: An Interactive JSON Processor Xml2Json UDF: Transform XML to JSON | HttpApi UDF: HTTP Server API | Roku Remote: Example Script About Me How To Ask Good Questions On Technical And Scientific Forums (Detailed) | How to Ask Good Technical Questions (Brief) "Any fool can know. The point is to understand." -Albert Einstein "If you think you're a big fish, it's probably because you only swim in small ponds." ~TheXman Link to comment Share on other sites More sharing options...
marko001 Posted February 3, 2023 Author Share Posted February 3, 2023 (edited) Result1: {"id":"8Y870588JT158264A","status":"CREATED","links":[{"href":"https://api.paypal.com/v2/checkout/orders/XXXXXXXXXX","rel":"self","method":"GET"},{"href":"https://www.paypal.com/checkoutnow?token=XXXXXXXXXX","rel":"approve","method":"GET"},{"href":"https://api.paypal.com/v2/checkout/orders/XXXXXXXXXXXX","rel":"update","method":"PATCH"},{"href":"https://api.paypal.com/v2/checkout/orders/XXXXXXXXXXXXX/capture","rel":"capture","method":"POST"}]} @TheXman You were right! Thanks a lot for the support! I suppose I should then forward my client to https://www.paypal.com/checkoutnow?token=XXXXXXXXXX to proceed with payment. Something is going wrong because I can't complete it but probably is because I didn't set after-purchase page URL. How can I verify if the payment went through? I thought to use /v1/reporting/transactions API call but, as from documentation It takes a maximum of three hours for executed transactions to appear in the list transactions call. So how can I get in real time information when a payment has correctly done? (I can wait on my software with an adlibregister() to check it)? Thanks Edited February 3, 2023 by marko001 Link to comment Share on other sites More sharing options...
marko001 Posted February 4, 2023 Author Share Posted February 4, 2023 @mistersquirrle do you maybe have any suggestion on this? Thanks in advance, Marco Link to comment Share on other sites More sharing options...
mistersquirrle Posted February 4, 2023 Share Posted February 4, 2023 I don't know anything really about PayPal development, certainly not enough to answer Quote How can I verify if the payment went through? I merely know (kind of) how to use the WinHTTP functions. But I think you would want to look at: https://developer.paypal.com/docs/api/orders/v2/#orders_get and check the status for "APPROVED", and then later likely for "COMPLETED" to make sure it went through, and didn't transition into "VOIDED" or "PAYER_ACTION_REQUIRED". I don't know what you're using PayPal to buy/sell, if it's something physical that you have to package up and send out, you could simply wait to do that until the payment is completed. If it for some software that has some kind of license key, provide it as soon as it's "APPROVED", check the status later, and revoke the key (or access with it) if it moves to an incomplete state. Again though I'm not familiar with how this side of PayPal works, this is just a thought. We ought not to misbehave, but we should look as though we could. Link to comment Share on other sites More sharing options...
marko001 Posted February 4, 2023 Author Share Posted February 4, 2023 @mistersquirrleI solved it! I will post soon a complete package including all needed functions to add a "Buy Now" feature in .au3 applications and to manage all activities up to the completion of the payment procedures. mistersquirrle and Danyfirex 2 Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now