I'm trying to perform a super-simple call to the PayPal Payments API.
{
"intent":"sale",
"payer": {
"payment_method":"credit_card",
"funding_instruments": {
"credit_card_token": {
"credit_card_id":"CARD-XXXXXXXXXXXXXXXXXXXXXXXX"
}
}
}
}
I've tried adding/removing various parts of the request, and I've had minimal success, but inevitably, I come across an error of "Incoming JSON request does not map to API request MALFORMED_REQUEST".
According to the documentation, these are the only required parameters, but I've tried different funding_instruments, adding payer_info, adding transactions, using credit_card_token and credit_card... nothing seems to work, and the documentation is useless for troubleshooting.
Is there a way to be able to determine WHY this is a malformed request? Most of the documentation I am coming across uses payment_method: paypal instead of credit_card. What are better ways for me to troubleshoot why this request is failing?
There are a few things to consider first. Are you in the US?
if not you will need to consider if your country can use the API. You can find Information of which countries can use the API here https://developer.paypal.com/docs/integration/direct/rest/country-codes/
You might also need to validate your json. I've tested what you have posted here, but you might not be generating the information properly in your app. check the output and make sure that it is valid json--MALFORMED_REQUEST is an indicator that required key/value pairs are missing or that the json is not valid... this website will help you validate the json output https://jsonlint.com/
check your headers carefully to ensure that you have a properly formatted header request header. you can check your headers against the api requirements here https://developer.paypal.com/docs/api/overview/#http-request-headers
paypal notes that they provide an error code as a json string for errors arising in this manner, and that details may or may not be provided in the response. error response codes are in the 400 and 500 ranges and correspond to error messages (these are listed on the headers page given above)
However, given your error message which is not listed i'm going to guess that you are missing required key/value pairs in your json...
paypal says that INTENT AND PAYER OBJECTS ARE REQUIRED, but the example payment that they give lists a great deal of information that your sample json is missing--
among those items are the transaction details which are required...
per paypal's api docs "Include payer, transaction details...
paypal api documentation gives examples of of the required payer and intent objects here https://developer.paypal.com/docs/api/payments/
restrictions are further placed on direct credit card payments: they may only be accepted from the UK or US, and only if the account is payment pro enabled...
options for avoiding this issue are:
1) paypal classic api direct payments--https://developer.paypal.com/docs/classic/paypal-payments-pro/integration-guide/direct-payment/
2) braintree direct: https://www.braintreepayments.com/products/braintree-direct
3) or payflow pro: https://developer.paypal.com/docs/classic/products/payflow
Funding instruments in an array so the request should be something like below.
Transaction is required as that's the only way you will be able to specify what amount you are capturing.
{
"intent":"sale",
"payer": {
"payment_method":"credit_card",
"funding_instruments": [ {
"credit_card_token": {
"credit_card_id":"CARD-27V22453CF057824JLLDIA7Q"
} }
]
},
"transactions": [
{
"amount": {
"total": "30.11",
"currency": "GBP",
"details": {
"subtotal": "30",
"tax": "0.07",
"shipping": "0.03",
"handling_fee": "1.00",
"shipping_discount": "-1.00",
"insurance": "0.01"
}
}
}]
}
Related
I am trying to connect to the paypal but i have some questions with regards to the form data i need to pass, paypal expects it like this
"purchase_units": [
{
"amount": {
"currency_code": "USD",
"value": "100.00"
}
}
]
but the form just passes the amount > currencycode > value
so how can i convert the form scope to this type of data which paypal expects, same is the case with other data if i need to send, this is driving me nuts
What PayPal expects is JSON, which is one of the most common formats for sending data between systems in today's web.
You mentioned a form scope, which must be a coldfusion thing. Are you doing a server or "client-side only" integration? Client-side only is very basic, just spit this HTML/JS out to the browser: https://developer.paypal.com/demo/checkout/#/pattern/client
The server-based version is more involved, you will need to communicate with the PayPal API endpoints directly from your server. There are SDKs and guides for a number of more common server-side languages, which you might find adaptable to your purposes -- see 'Set Up Transaction' and 'Capture Transaction' here: https://developer.paypal.com/docs/checkout/reference/server-integration/
This is a more a long comment than an answer, but here goes. Are you trying to do something like this?
<cfscript>
form.value =4
data = { "purchase_units" : [
{
"amount": {
"currency_code": "USD",
"value": "#form.value#"
}
}
]
}
writedump(serializeJSON(data))
</cfscript>
Live version: https://cffiddle.org/app/file?filepath=c5a0ae3e-e24e-462c-8828-a46da98b9ace/2cea5311-965d-4f9c-af0f-7a0a29563e26/20e07958-06f1-41b2-937c-2c98c819a7a2.cfm
We have a web application (AngularJS and Web API) which has quite a simple functionality - displays a list of jobs and allows users to select and cancel selected jobs.
We are trying to follow RESTful approach with our API, but that's where it gets confusing.
Getting jobs is easy - simple GET: /jobs
How shall we cancel the selected jobs? Bearing in mind that this is the only operation on jobs we need to implement. The easiest and most logical approach (to me) is to send the list of selected jobs IDs to the API (server) and do necessary procedures. But that's not RESTful way.
If we are to do it following RESTful approach it seams that we need to send PATCH request to jobs, with json similar to this:
PATCH: /jobs
[
{
"op": "replace",
"path": "/jobs/123",
"status": "cancelled"
},
{
"op": "replace",
"path": "/jobs/321",
"status": "cancelled"
},
]
That will require generating this json on client, then mapping it to some the model on server, parsing "path" property to get the job ID and then do actual cancellation. This seems very convoluted and artificial to me.
What is the general advice on this kind of operation? I'm curious what people do in real life when a lot of operations can't be simply mapped to RESTful resource paradigm.
Thanks!
If by cancelling a job you mean deleting it then you could use the DELETE verb:
DELETE /jobs?ids=123,321,...
If by cancelling a job you mean setting some status field to cancelled then you could use the PATCH verb:
PATCH /jobs
Content-Type: application/json
[ { "id": 123, "status": "cancelled" }, { "id": 321, "status": "cancelled" } ]
POST for Business Process
POST is often an overlooked solution in this situation. Treating resources as nouns is a useful and common practice in REST, and as such, POST is often mapped to the "CREATE" operation from CRUD semantics - however the HTTP Spec for POST mandates no such thing:
The POST method requests that the target resource process the representation enclosed in the request according to the resource's own specific semantics. For example, POST is used for the following functions (among others):
Providing a block of data, such as the fields entered into an HTML form, to a data-handling process;
Posting a message to a bulletin board, newsgroup, mailing list, blog, or similar group of articles;
Creating a new resource that has yet to be identified by the origin server; and
Appending data to a resource's existing representation(s).
In your case, you could use:
POST /jobs/123/cancel
and consider it an example of the first option - providing a block of data to a data handling process - and is analogous to html forms using POST to submit the form.
With this technique, you could return the job representation in the body and/or return a 303 See Other status code with the Location set to /jobs/123
Some people complain that this looks 'too RPC' - but there is nothing that is not RESTful about it if you read the spec - and personally I find it much clearer than trying to find an arbitrary mapping from CRUD operations to real business processes.
Ideally, if you are concerned with following the REST spec, the URI for the cancel operation should be provided to the client via a hypermedia link in your job representation. e.g. if you were using HAL, you'd have:
GET /jobs/123
{
"id": 123,
"name": "some job name",
"_links" : {
"cancel" : {
"href" : "/jobs/123/cancel"
},
"self" : {
"href" : "/jobs/123"
}
}
}
The client could then obtain the href of the "cancel" rel link, and POST to it to effect the cancellation.
Treat Processes as Resources
Another option is, depending on if it makes sense in your domain, to make a 'cancellation' a noun and associate data with it, such as who cancelled it, when it was cancelled etc. - this is especially useful if a job may be cancelled, reopened and cancelled again, as the history of changes could be useful business data, or if the act of cancelling is an asynchronous process that requires tracking the state of the cancellation request over time. With this approach, you could use:
POST /jobs/123/cancellations
which would "create" a job cancellation - you could then have operations like:
GET /jobs/123/cancellations/1
to return the data associated with the cancellation, e.g.
{
"cancelledBy": "Joe Smith",
"requestedAt": "2016-09-01T12:43:22Z",
"status": "in process"
"completedAt": null
}
and:
GET /jobs/123/cancellations
to return a collection of cancellations that have been applied to the job and their current status.
Example 1: Let’s compare it with a real-world example: You go to a restaurant you sit at your table and you choose that you need ABC. You will have your waiter coming up and taking a note of what you want. You tell him that you want ABC. So, you are requesting ABC, the waiter responds back with ABC he gets in the kitchen and serves you the food. In this case, who is your interface in between you and the kitchen is your waiter. It’s his responsibility to carry the request from you to the kitchen, make sure it’s getting done, and you know once it is ready he gets back to you as a response.
Example 2: Another important example that we can relate is travel booking systems. For instance, take Kayak the biggest online site for booking tickets. You enter your destination, once you select dates and click on search, what you get back are the results from different airlines. How is Kayak communicating with all these airlines? There must be some ways that these airlines are actually exposing some level of information to Kayak. That’s all the talking, it’s through API’s
Example 3: Now open UBER and see. Once the site is loaded, it gives you an ability to log in or continue with Facebook and Google. In this case, Google and Facebook are also exposing some level of users’ information. There is an agreement between UBER and Google/Facebook that has already happened. That’s the reason it is letting you sign up with Google/ Facebook.
PUT /jobs{/ids}/status "cancelled"
so for example
PUT /jobs/123,321/status "cancelled"
if you want to cancel multiple jobs. Be aware, that the job id must not contain the comma character.
https://www.rfc-editor.org/rfc/rfc6570#page-25
I am attempting an implicit Pay API operation. I keep receiving a "Invalid request parameter: receiver cannot be null" error though I am sending along the receiver as specified in the paypal api docs. I include the API credentials as request headers.
Here is the request payload
request['payload']={
'actionType' : 'PAY',
'senderEmail': 'sender#company.com',
'receiverList' : {'receiver': [{ 'amount': '10.0', 'email':'recepient#company.com' }]},
'currencyCode' : 'SGD',
'requestEnvelope' : {
"errorLanguage":"en_US", # Language used to display errors
"detailLevel":"ReturnAll" # Error detail level
},
'ipnNotificationUrl': 'http://xxxxxxxx',
'cancelUrl': 'http://xxxxxxxxx',
'returnUrl': 'http://xxxxxxxxxx'
}
The error was on my side - though paypal's error message didn't help much. I did
not encode the python dict object to json before sending the request to paypal.
import json
payload = json.dumps(request['payload'])
Hope this helps someone.
I'd like to use this endpoint to display the calculated fees on my site before taking the user to the paypal site; however, when I query the endpoint with a valid payKey, I receive an internal error.
Endpoint: https://developer.paypal.com/docs/classic/api/adaptive-payments/GetPrePaymentDisclosure_API_Operation/
To generate the payKey, I'm POSTing to svcs.sandbox.paypal.com/AdapativePayments/Pay with the following request body:
{
"actionType":"PAY",
"currencyCode":"USD",
"feesPayer":"SENDER",
"requestEnvelope": { "errorLanguage": "en_US" },
"cancelUrl":"test.com/cancel",
"returnUrl":"test.com/return",
"receiverList": {
"receiver": [
{ "email": "someguy#email.com", "amount": "80.00" }
]
}
}
Any ideas as to what's going on?
Note: I had to edit out the valid URLs because I don't have enough reputation.
For GetPrePaymentDisclosure you must supply senderEmail in the PAY request for it to function.
This is because GetPrePaymentDisclosure is supposed to be used to determine the status of the transaction and see if it is covered by the Remittance Transfer Rule.
From the Documentation: This API is specific for merchants who must support the Consumer Financial Protection Bureau's Remittance Transfer Rule.
It does not work to determine the fees beforehand if it does not hit these rules. As all you will get back is [status] => NON_RTR with no information.
If you would like this functionality outside of RTR transactions you should submit a feature request on PayPal's Technical Support Site
I'm trying to test refunds in the Paypal Sandbox, but I'm getting a confusing response; The transaction id is not valid.
I've managed to confirm the following:
I'm passing in the transaction ID that I get from the PAYMENTREQUEST_n_TRANSACTIONID of GetExpressCheckoutDetails.
The Transaction ID is not being modified in between getting it from GetExpressCheckoutDetails and passing it in RefundTransaction.
This happens regardless of whether or not I pass INVOICEID.
The PAYMENTACTION of DoExpressCheckoutPayment for this was Sale.
Am I making any obviously incorrect assumptions here? Does it have anything to do with this being a Sandbox order (Doubtful)? Am I getting the Transaction ID from the wrong source?
Just in case any details are needed, I'll leave the full response...
{
"TIMESTAMP": "2014-01-06T18:15:35Z",
"CORRELATIONID": "cb90afac455c",
"ACK": "Failure",
"VERSION": "109",
"BUILD": "9138168",
"L_ERRORCODE0": "10004",
"L_SHORTMESSAGE0": "Transaction refused because of an invalid argument. See
additional error messages for details.",
"L_LONGMESSAGE0": "The transaction id is not valid",
"L_SEVERITYCODE0": "Error",
"REFUNDSTATUS": "None",
"PENDINGREASON": "None"
}
And the fields/values of the RefundTransaction call itself... (Redacting credentials even though it's sandbox)
{
"METHOD": "RefundTransaction",
"TRANSACTIONID": "30888131YM063371A",
"USER": "[redacted]",
"REFUNDTYPE": "Partial",
"CURRENCYCODE": "USD",
"REFUNDSOURCE": "any",
"AMT": 57.21,
"PWD": "[redacted]",
"SIGNATURE": "[redacted]",
"VERSION": 109
}
EDIT: (May post as an answer if Robert doesn't update his answer after a while, since he deserves credit for this)
PayPal_Robert noted that in my SetExpressCheckout call, I was setting the recipient to the actual account that payments would be going to with the live API when - since this is Sandbox - I should have been sending it to the -facilitator account.
I can't find any transactions with that transactionID in the sandbox environment - across all accounts either. I suspect it's getting mangled somewhere.
The only thing I found for the same API caller is an order with transactionID O-072365850X147461B, created on the 2nd of January.
Can you re-create the entire flow, including creating a fresh transaction and try with that?
If you still run into issues, please file a ticket with us at https://paypal.com/mts (24x7) or shoot me an email (address in profile, I only work GMT however.)