i installed the .net sdk of paypal and created an app in sandbox environment
next i picked up the clientId and secret and used the following sample code to make a payment.
static void Main(string[] args)
{
// Get a reference to the config
var config = ConfigManager.Instance.GetProperties();
// Use OAuthTokenCredential to request an access token from PayPal
var accessToken = new OAuthTokenCredential(config["clientId"], config["clientSecret"]);
var apiContext = new APIContext(accessToken.GetAccessToken());
var payment = Payment.Create(apiContext, new Payment
{
intent = "sale",
payer = new Payer
{
payment_method = "paypal"
},
transactions = new List<Transaction>
{
new Transaction
{
description = "Test",
invoice_number = "009",
amount = new Amount
{
currency = "EUR",
total = "41.00",
details = new Details
{
tax = "0",
shipping = "0",
subtotal = "40",
handling_fee = "1"
}
},
item_list = new ItemList
{
items = new List<Item>
{
new Item
{
name = "Room 12",
currency = "EUR",
price = "10",
quantity = "4",
}
}
}
}
},
redirect_urls = new RedirectUrls
{
return_url = "https://google.de/",
cancel_url = "https://google.de/"
}
});
}
in the transaction i have to pass Tax information.
Is there was that i let paypal calculate the tax and i just pass amount information along with address and some other information if required ?
No, you must calculate the tax yourself.
By default the user will be able to select their shipping address at PayPal, which is recommended as this saves them from having to type it manually. Given that their address can change during the PayPal checkout, you may wish to calculate a new tax amount and/or shipping amount based on the selected address. You can do this using the JS SDK's onShippingChange callback.
Firstly, though, it appears you may be using a deprecated SDK and deprecated v1/payments API, and also a redirect away from your site to PayPal, all of which is old. Don't do any of this.
Instead: follow the PayPal Checkout integration guide and make 2 routes on your server, one for 'Create Order' and one for 'Capture Order' (see the optional step 5 in 'Add and modify the code'). Both of these routes should return only JSON data (no HTML or text). There is a Checkout-Java-SDK you can use, or integrate with your own direct HTTPS API calls (obtain an access_token first, it can be cached but expires in 9 hours).
Inside the 2nd capture route on your server, when the capture API call is successful you should store its resulting payment details in your database (particularly purchase_units[0].payments.captures[0].id, which is the PayPal transaction ID) and perform any necessary business logic (such as sending confirmation emails or reserving product) immediately before forwarding your return JSON to the frontend caller.
Pair those 2 routes with the frontend approval flow: https://developer.paypal.com/demo/checkout/#/pattern/server
Related
I created an app on PayPal with sandbox account. Then i picked up its API Client id and Secret.
I created a new console application and added paypal nuget package version 1.9.1.
internal class Program { static void Main(string[] args) { // Get a reference to the config var config = ConfigManager.Instance.GetProperties();
// Use OAuthTokenCredential to request an access token from PayPal
var accessToken = new OAuthTokenCredential(config["clientId"], config["clientSecret"]);
var apiContext = new APIContext(accessToken.GetAccessToken());
try
{
var payment = new Payment()
{
intent = "authorize",
// A resource representing a Payer that funds a payment. Use the List of `FundingInstrument` and the Payment Method as 'credit_card'
payer = new Payer()
{
// The Payment creation API requires a list of
// FundingInstrument; add the created `FundingInstrument`
// to a List
funding_instruments = new List<FundingInstrument>()
{
// A resource representing a Payeer's funding instrument.
// Use a Payer ID (A unique identifier of the payer generated
// and provided by the facilitator. This is required when
// creating or using a tokenized funding instrument)
// and the `CreditCardDetails`
new FundingInstrument()
{
// A resource representing a credit card that can be used to fund a payment.
credit_card = new CreditCard()
{
billing_address = new Address()
{
city = "Johnstown",
country_code = "US",
line1 = "52 N Main ST",
postal_code = "43210",
state = "OH"
},
cvv2 = "874",
expire_month = 11,
expire_year = 2023,
first_name = "Joe",
last_name = "Shopper",
number = "5105105105105100",
type = "visa"
}
}
},
payment_method = "credit_card"
},
// The Payment creation API requires a list of transactions; add the created `Transaction` to a List
transactions = new List<Transaction>()
{
// A transaction defines the contract of a payment - what is the payment for and who is fulfilling it. Transaction is created with a `Payee` and `Amount` types
new Transaction()
{
// Let's you specify a payment amount.
amount = new Amount()
{
currency = "USD",
// Total must be equal to sum of shipping, tax and subtotal.
total = "107.47",
details = new Details()
{
shipping = "0.03",
subtotal = "107.41",
tax = "0.03"
}
},
description = "This is the payment transaction description."
}
},
payee = new Payee { email = "rassmasood#hotmail.com" }
};
var createdPayment = payment.Create(apiContext);
}
catch (Exception ex)
{
throw;
}
}
}
Using the code above i get the error mentioned below.
{"name":"VALIDATION_ERROR","message":"Invalid request - see details","debug_id":"f3c178cb2a17b","details":[{"field":"/payee","location":"body","issue":"MALFORMED_REQUEST_JSON"}],"links":[]}
is there anything i am doing wrong ?
i tried adding more information to Payee for example its account merchand_id and stuff but didnt worked.
i am expecting the exception to be resolved.
The package you are using is 5 years old and deprecated.
Use the current PayPalCheckoutSDK 1.0.4
I am having a difficult time finding halfway descent documentation or examples on how to send money to another Paypal account.
I have installed the Nuget package PaypalSDK version 1.0.4. I have read the documentation at https://developer.paypal.com/home. I have browsed and tried to implement the sample code at https://github.com/paypal/Checkout-NET-SDK.
The problem I am having is that I am having is that I am not seeing notifications of payments sent or received in my sandbox account. I can successfully execute a checkout with the Javascript button in my shopping cart view. But eventually I want to add the capability to send money from my Paypal business account to another Paypal business account, without the other Paypal Business Account owner having to be logged in to my website.
Does the money recipient have to authorize the money I send, or should it just get deposited into their account once I send it?
Here is my code:
namespace MyShoppingCart.Helpers.Paypal
{
public class CaptureOrderSample
{
static string PayPalClientID = Startup.StaticConfig.GetValue<string>("Paypal:ClientID");
static string PayPalClientSecret = Startup.StaticConfig.GetValue<string>("Paypal:ClientSecret");
public static HttpClient client()
{
// Creating a sandbox environment
PayPalEnvironment environment = new SandboxEnvironment(PayPalClientID, PayPalClientSecret);
// Creating a client for the environment
PayPalHttpClient client = new PayPalHttpClient(environment);
return client;
}
public async static Task<HttpResponse> createOrder(string Email)
{
HttpResponse response;
// Construct a request object and set desired parameters
// Here, OrdersCreateRequest() creates a POST request to /v2/checkout/orders
var order = new OrderRequest()
{
CheckoutPaymentIntent = "CAPTURE",
PurchaseUnits = new List<PurchaseUnitRequest>()
{
new PurchaseUnitRequest()
{
AmountWithBreakdown = new AmountWithBreakdown()
{
CurrencyCode = "USD",
Value = "100.00"
},
Payee = new Payee
{
Email = Email // "payee#email.com"
}
}
}
//,
//ApplicationContext = new ApplicationContext()
//{
// ReturnUrl = "https://www.example.com",
// CancelUrl = "https://www.example.com"
//}
};
// Call API with your client and get a response for your call
var request = new OrdersCreateRequest();
request.Prefer("return=representation");
request.RequestBody(order);
response = await client().Execute(request);
var statusCode = response.StatusCode;
Order result = response.Result<Order>();
Debug.WriteLine($"Status: {result.Status}");
Debug.WriteLine($"Order Id: {result.Id}");
Debug.WriteLine($"Intent: {result.CheckoutPaymentIntent}");
Debug.WriteLine("Links:");
foreach (LinkDescription link in result.Links)
{
Debug.WriteLine($"\t{link.Rel}: {link.Href}\tCall Type: { link.Method}");
}
return response;
}
}
}
And this is currently called from my Orders controller when an order is completed. This is just for testing purposes.
[Authorize]
public async Task<IActionResult> CompleteOrder()
{
var items = _shoppingCart.GetShoppingCartItems();
Models.Order order = await _ordersService.StoreOrderAsync(items);
PrepareSellerEmail(items, order, "You Have a New Order!");
PrepareBuyerEmail(items, order, "Thank You for Your Order!");
await _shoppingCart.ClearShoppingCartAsync(_serviceProvider);
DeleteCartIDCookie();
//OrderRequest request = Helpers.CreateOrderSample.BuildRequestBody("USD", "100.00", "sb-r43z1e9186231#business.example.com");
//var client = Helpers.Paypal.CaptureOrderSample.client();
var result = Helpers.Paypal.CaptureOrderSample.createOrder("sb-r43z1e9186231#business.example.com");
//var response = await PayPalClient.client().execute.(request);
return View("OrderCompleted");
}
The output of the result is:
Status: CREATED
Order Id: 51577255GE4475222
Intent: CAPTURE
Links:
self: https://api.sandbox.paypal.com/v2/checkout/orders/51577255GE4475222 Call Type: GET
approve: https://www.sandbox.paypal.com/checkoutnow?token=51577255GE4475222 Call Type: GET
update: https://api.sandbox.paypal.com/v2/checkout/orders/51577255GE4475222 Call Type: PATCH
capture: https://api.sandbox.paypal.com/v2/checkout/orders/51577255GE4475222/capture Call Type: POST
This is a screen capture from my sandbox account:
Am I supposed to do something else to actually execute the transfer?
Edit: I figured out how to use the Paypal Payouts API.
First I installed the Nuget Package. It's simply called PayoutsSdk. I'm using version 1.1.1.
For the payout to execute, you need the client() method that is listed above in this post, and this CreatePayout() method listed below.
public async static Task<HttpResponse> CreatePayout()
{
var body = new CreatePayoutRequest()
{
SenderBatchHeader = new SenderBatchHeader()
{
EmailMessage = "Congrats on recieving 1$",
EmailSubject = "You recieved a payout!!"
},
Items = new List<PayoutItem>()
{
new PayoutItem()
{
RecipientType="EMAIL",
Amount=new Currency()
{
CurrencyCode="USD",
Value="1",
},
Receiver="sb-r43z1e9186231#business.example.com",
}
}
};
PayoutsPostRequest request = new PayoutsPostRequest();
request.RequestBody(body);
var response = await client().Execute(request);
var result = response.Result<CreatePayoutResponse>();
Debug.WriteLine($"Status: {result.BatchHeader.BatchStatus}");
Debug.WriteLine($"Batch Id: {result.BatchHeader.PayoutBatchId}");
Debug.WriteLine("Links:");
foreach (PayoutsSdk.Payouts.LinkDescription link in result.Links)
{
Debug.WriteLine($"\t{link.Rel}: {link.Href}\tCall Type: {link.Method}");
}
return response;
}
Of course I'll add parameters to the method for email, amount, currency code, email message, and subject.
Right now, I am calling this method from the controller method like this: var result = Helpers.Paypal.CaptureOrderSample.CreatePayout(); where Helpers.Paypal are folders that contain a class called CaptureOrderSample, which I will probably rename.
To send money from your account to another account, there are several different options:
Automate the sending with the Payouts API or Payouts Web (spreadsheet upload). For live, payouts can only be used if the live account sending the payment is approved for payouts.
Log into the account that is going to send the money in https://www.paypal.com or https://www.sandbox.paypal.com and click on the menu for Pay & Get Paid -> Send Money .
Use a PayPal Checkout integration, with or without the Orders API, and specify a payee that is to receive the money. You must log in with the paying (sending) account to approve the sending, and finally the order must be captured (via API or client side actions.order.capture()) which is what results in a PayPal transaction. If the final capture step is not performed, no money will be sent and the order will merely remain created or approved and eventually expire (72 hours after creation or 3 hours after approval)
In the sandbox, no actual emails are sent with notifications. Instead, the developer.paypal.com dashboard has a "Notifications" tab on the left, and of course activity will also be visible in each sandbox account by logging into the account. Only captured activity is likely to be visible.
I want to build a webapp where users can pay to another users via their paypal accounts.
What I want is something similar to this:
https://developer.paypal.com/demo/checkout/#/pattern/client
A page where the users can click a button to either pay with Paypal or credit card, to another user.
But I can't see how in this example can I configure the receiver account. Seems that the payment is made to my account, but I want the payment to be made to another user that he selects.
I have also looked to all these APIs:
https://developer.paypal.com/docs/api/rest-sdks/#
but am not able to find an example that allows to build a client where an user pays to another user. And of course, I need to get the confirmation that the payment has been done.
EDIT:
I have tried the code here: https://www.npmjs.com/package/#paypal/checkout-server-sdk
And updated to add the payee field:
exports.pay = function (req, res) {
// 1. Set up your server to make calls to PayPal
// 1a. Import the SDK package
const paypal = require('#paypal/checkout-server-sdk');
// 1b. Add your client ID and secret
const PAYPAL_CLIENT = 'xxx';
const PAYPAL_SECRET = 'yyy';
// 1c. Set up the SDK client
const env = new paypal.core.SandboxEnvironment(PAYPAL_CLIENT, PAYPAL_SECRET);
const client = new paypal.core.PayPalHttpClient(env);
// 2. Set up your server to receive a call from the client
// 3. Call PayPal to set up a transaction with payee
const request = new paypal.orders.OrdersCreateRequest();
request.requestBody({
"intent": "CAPTURE",
"purchase_units": [
{
"amount": {
"currency_code": "USD",
"value": "100.00"
},
"payee": {
"email_address": "payee#gmail.com"
}
}
]
});
const createOrder = async function () {
const response = await client.execute(request);
console.log(`Response: ${JSON.stringify(response)}`);
// If call returns body in response, you can get the deserialized version from the result attribute of the response.
console.log(`Order: ${JSON.stringify(response.result)}`);
return res.status(200).json(response.result);
};
createOrder();
};
This returns a list of 4 links. The second one seems to be the one to redirect the client to (https://www.sandbox.paypal.com/checkoutnow?token=9RM83779YH010823U). But if I go there, I still can't see the payee address (payee#gmail.com) in the "sent to".
What you want is to set a payee object: https://developer.paypal.com/docs/checkout/integration-features/custom-payee/
I trying the new Paypal REST API and want integrate it in sandbox mode into a simple site just to see is it possible to implement one of the following payment flows:
Flow1
1) user fills the payment form, including credit card information
2) user clicks Buy
3) browser stores credit card information in paypal vault via REST API for credit cards (card id used later).
4) browser creates payment for the purchase via REST API call.
5) browser calls app server to ensure that purchase is going on.
5) browser redirects user to url provided by paypal.
6) when user consent/approval received at paypal website, and site redirected back to welcome page,
7) under the hood the IPN callback receives the conformation of payment and marks purchase as paid
8) user obtains access to the service app provides
Flow 2
1) user fills the payment form, including credit card information
2) user clicks Buy
4) browser creates payment for the purchase via REST API call.
5) browser calls app server to ensure that purchase is going on.
5) browser redirects user to url provided by paypal.
6) when user consent/approval received at paypal website, and site redirected back to welcome page,
7) under the hood the IPN callback receives the conformation of payment and marks purchase as paid and uses a bit more pf purchase details like credit card type and last 4 digits to add this info to my purchase object.
8) user obtains the access to services the application provides
8) user obtains access to the service app provides
Reasons to implement all this in such way
Mostly I going this path because i don't want deal with all this PCI compliance, and hones;ty i don't care where customers of my app live, which exactly card numbers they used, or when the card expire, since i don't want use automated subscription like payment, i want use different model:
user gets some pats of service for free, but to use rest of service, user buys time intervals of improved access (e. g. X months or 1 year).
This is what i trying to implement without storing credit cards information or storing as less as possible (paypal credit card id is enough i guess).
Question
Can i implement all this with Paypal REST API?
What i trying to do:
PaypalAdapter.prototype.sendCreditCardPayment = function (amount, description, creditCard, success, failure) {
var ccNumberResult = this.impl.validator.validateCardNumber(creditCard.number);
if (!ccNumberResult.success) {
return this.impl.$q.reject(ccNumberResult);
}
var cardInfo = {
number: ccNumberResult.number,
type: ccNumberResult.type,
expire_month: creditCard.expireMonth,
expire_year: String(creditCard.expireYear),
cvv2: creditCard.securityCode,
first_name: creditCard.firstName,
last_name: creditCard.lastName
};
var self = this;
var defer = self.impl.$q.defer();
this.impl.storeCardAPI(cardInfo,
function cardTokenCreated(cardTokenReply) {
var paymentSettings = {
intent: self.PaymentIntents.Sale,
redirect_urls: {
return_url: self.urls.returnUrl,
cancel_url: self.urls.cancelUrl
},
payer: {
payment_method: self.PayMethods.CreditCard,
funding_instruments: [
{
credit_card_token: {
credit_card_id: cardTokenReply.id
}
}
]
},
transactions: [
{
amount: {
total: String(amount.toFixed(2)),
currency: self.currencyCode
},
description: description
}
]
};
self.impl.createPaymentAPI(paymentSettings, function paymentCreated(payment) {
defer.resolve(payment);
}, function failedToCreatePayment(pcErr) {
defer.reject(pcErr);
});
},
function failedToStoreCard(ctErr) {
defer.reject(ctErr);
});
return defer.promise.then(success, failure);
};
To keep context more clean, here some more pieces of code:
var defaultHeaders = {
Authorization: 'Bearer ' + securityContext.tokens.paypal.access_token,
Accept: 'application/json'
};
var createPaymentResource = $resource(securityContext.configuration.paypal.endPoint + 'payments/payment', {}, {
sendPayment : {
method:'POST',
headers: defaultHeaders
}
});
var saveCreditCardResource = $resource(securityContext.configuration.paypal.endPoint + "vault/credit-cards", {}, {
storeCreditCard: {
method: 'POST',
headers: defaultHeaders
}
});
function storeCardFunc(cardInfo, success, failure) {
return saveCreditCardResource.storeCreditCard(null, cardInfo, success, failure);
}
function createPaymentFunc(paymentInformation, success, failure) {
return createPaymentResource.sendPayment(null, paymentInformation, success, failure);
}
var adapter = new PaypalAdapter($q, securityContext, creditCardValidator, storeCardFunc, createPaymentFunc);
return adapter;
Current "Results"
What i getting:
1) I can store credit card into vault via REST API.
2) i getting error 500 on try to create payment whether i use plain credit card properties to fill credit card funding instrument or try to use credit card token instead.
What i'm doing wrong?
Update
My mistake is a sort of logical with a lack of knowledge.
1) The direct credit cards payments (weather user approves them manually (with intent 'order' and payment_method = 'credit_card'), or not ('sale' intent and payment method 'credit_card') are not available for my country (Republic of Georgia). This is a single reason for the error i see.
Discovered this via Paypal account pages at developer.paypal.com website... It is a frustrating thing. Especially with all this too cryptic "internal server error". I t would be VERY helpful if Paypal would provide at least an informative message "Requested feature not available for your account" with info link to that page with available/enabled features.
Also documentation s a bit broken - some fields like first_name or last_name of payer object of order/payment request are NOT expected by the /payments/payment endpoint...
I create recurring payment profile with regular payments. But I want to create profile with one-off payment which will occurs immediately after profile created. How I can do it?
I create profile in follow way:
var currency = CurrencyCodeType.USD;
var startBillingDate = DateTime.Now;
var rpProfileDetails =
new RecurringPaymentsProfileDetailsType(startBillingDate.ToString("yyyy-MM-ddThh:mm:ss"))
{
SubscriberName = "John Smith"
};
var scheduleDetails = new ScheduleDetailsType
{
Description = "Application Licenses",
AutoBillOutstandingAmount = AutoBillType.ADDTONEXTBILLING,
PaymentPeriod = new BillingPeriodDetailsType(BillingPeriodType.MONTH, pLicence.BillingPeriodAmount,
new BasicAmountType(currency,
"10.00"))
{
TotalBillingCycles = 12,
TaxAmount = new BasicAmountType(currency, "2.00")
}
};
You need to include the INITAMT parameter in your CreateRecurringPaymentsProfile request. You can find more details about it in PayPal's CreateRecurringPaymentsProfile API reference.