Paypal .Net SDK implementation - c#

Dear StackOverflow Community,
We have started to implement the PayPal .Net SDK in our project.
We create a Payment with the following Code:
var payment = Payment.Create(GetDefaultApiContext(), 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/"
}
});
The payment is also created and a corresponding link is generated. If we now pay with our test account, the money is not debited and nothing more happens, the forwarding also works normally. However, no transaction is reported to PayPal.
It would be very nice if someone could help us with this Problem.
Thank you!

After the redirect back to the return_url you provided, you are expected to present an order review page and then when the user confirms the order you must do a payment Execute API call, which will result in the PayPal transaction. If you do not do the Execute API call, there will be no transaction.
Do not worry about money being debited from the payer account, since payer accounts have funding sources with infinite funds in sandbox.
Note also that the v1/payments SDK you are using is deprecated, you should upgrade to the current v2/checkout/orders Checkout-NET-SDK and use it to create two routes on your server, one for 'Create Transaction' and one for 'Capture Transaction', documented here.
The best approval flow to pair with your two new routes is https://developer.paypal.com/demo/checkout/#/pattern/server

Related

How to use SMS-Authentication in DocuSign

I'm trying to implement the SMS authentication with the aid of the DocuSign-SDK library.
var signer = new Signer {...};
signer.RequireIdLookup = "true";
signer.IdCheckConfigurationName = "SMS Auth $";
signer.SmsAuthentication = new RecipientSMSAuthentication {
SenderProvidedNumbers = new List<string> {
"0171*******"
}
};
When I try to send this envelope to the DocuSign API it will reply with the following error message:
Error calling CreateEnvelope:
{"errorCode":"INVALIDAUTHENTICATIONSETUP","message":"Recipient phone
number is invalid. Phone number for SMS Authentication: provided is
invalid. }
INVALIDAUTHENTICATIONSETUP: Authentication is not setup correctly for the recipient.
Is there something I have to enable on the DocuSign Admin page? I couldn't find any feature or something like that I need to enable.
Did I implement it the wrong way? Maybe someone can give me some suggestions.
Thanks
BTW: The given phone number should be valid.
EDIT:
When I'm using the new method as #Inbar wrote, I can't get the needed workflowId from the AccountsApi.
var client = new ApiClient(ApiClient.Demo_REST_BasePath);
var token = "eyJ1...";
client.Configuration.DefaultHeader.Add("Authorization", "Bearer " + token);
var accountsApi = new AccountsApi(client);
var response = accountsApi.GetAccountIdentityVerification(accountId);
var result = response.IdentityVerification; // Is empty. Why?
It seems that I have no IdentityVerification options which I can use for the authentication.
How can I enable such IdentityVerification options?
Or what else do I need to pay attention to?
Your code is using the older method, the new method code is provided in GitHub, I'll post it here too. You can find the article on Dev Center.
string workflowId = phoneAuthWorkflow.WorkflowId;
EnvelopeDefinition env = new EnvelopeDefinition()
{
EnvelopeIdStamping = "true",
EmailSubject = "Please Sign",
EmailBlurb = "Sample text for email body",
Status = "Sent"
};
byte[] buffer = System.IO.File.ReadAllBytes(docPdf);
// Add a document
Document doc1 = new Document()
{
DocumentId = "1",
FileExtension = "pdf",
Name = "Lorem",
DocumentBase64 = Convert.ToBase64String(buffer)
};
// Create your signature tab
env.Documents = new List<Document> { doc1 };
SignHere signHere1 = new SignHere
{
AnchorString = "/sn1/",
AnchorUnits = "pixels",
AnchorXOffset = "10",
AnchorYOffset = "20"
};
// Tabs are set per recipient/signer
Tabs signer1Tabs = new Tabs
{
SignHereTabs = new List<SignHere> { signHere1 }
};
string workflowId = workflowId;
RecipientIdentityVerification workflow = new RecipientIdentityVerification()
{
WorkflowId = workflowId,
InputOptions = new List<RecipientIdentityInputOption> {
new RecipientIdentityInputOption
{
Name = "phone_number_list",
ValueType = "PhoneNumberList",
PhoneNumberList = new List<RecipientIdentityPhoneNumber>
{
new RecipientIdentityPhoneNumber
{
Number = phoneNumber,
CountryCode = countryAreaCode,
}
}
}
}
};
Signer signer1 = new Signer()
{
Name = signerName,
Email = signerEmail,
RoutingOrder = "1",
Status = "Created",
DeliveryMethod = "Email",
RecipientId = "1", //represents your {RECIPIENT_ID},
Tabs = signer1Tabs,
IdentityVerification = workflow,
};
Recipients recipients = new Recipients();
recipients.Signers = new List<Signer> { signer1 };
env.Recipients = recipients;
I've created a new developer account on DocuSign and created a small test app in order to request identity verification options. Fortunately, that was working now and I got all available options but I do not understand why this is not working for my other developer account ("old").
When I compare both accounts I don't see the "Identity Verification" setting in the "old" account.
It is possible to activate this "Identity Verification" setting for my "old" dev account?
I guess that enabling this feature would solve the problem.
EDIT:
Ok, I've solved the problem.
I figured out that no IDV was configured for my developer account. In that case, the identity_verification call will return an empty array.
see: https://developers.docusign.com/docs/esign-rest-api/how-to/id-verification/
Also, I have read the following note in the DocuSign documentation:
Note: Phone authentication may not be enabled for some older developer
accounts. If you cannot choose to use phone authentication for your
account, contact support to request access. see:
https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/recipients/auth/#id-verification-idv
So I contacted DocuSign support and they give me access to the IDV accordingly.
Now it is working fine.

Add a description to a stripe product at checkout

I am working on a C# application where the app users will purchase a subscription for their clients. Since they will buy multiple subscriptions, I need to add a description (client name) to a product so it shows up in the billing portal along with the price. My current checkout code works fine and the relevant part is here:
var options = new Stripe.Checkout.SessionCreateOptions
{
LineItems = new List<SessionLineItemOptions>
{
new SessionLineItemOptions
{
Price = priceId,
Quantity = 1
},
},
PaymentMethodTypes = new List<string>
{
"card",
},
Mode = "subscription",
SuccessUrl = string.Concat("https://", domain, "/success/", hhid, "?session_id={CHECKOUT_SESSION_ID}"),
CancelUrl = string.Concat("https://", domain),
Customer = customerId,
SubscriptionData = new SessionSubscriptionDataOptions()
{
Metadata = new Dictionary<string, string>()
{
{ "userId", userId.ToString() }
}
}
};
if (!string.IsNullOrEmpty(user.PaymentCustomerId))
options.Customer = user.PaymentCustomerId;
var service = new Stripe.Checkout.SessionService();
Stripe.Checkout.Session session = await service.CreateAsync(options);
Response.Headers.Add("Location", session.Url);
I contacted Stripe support and their response was
In this particular case we do not have an option that allow you to add a description, but you are able to add the name with price_data parameter into the Checkout, Invoice Items, and Subscription Schedule APIs.
https://stripe.com/docs/api/subscription_items/create
https://stripe.com/docs/billing/prices-guide
They provided links to the two articles which I have read and re-read and don't understand how to implement it. If anyone can help it would be greatly appreciated.
Unfortunately, the Billing Portal does not show a description for the Product.
If you want to use the Billing Portal, then you would need to specify the client name in the name for the Product e.g. [client name] Product #1, and this would require you to create a new Product and Price for every client.
You can do it in the Checkout Session creation :
https://stripe.com/docs/api/checkout/sessions/create#create_checkout_session-line_items-price_data-product_data-name
https://stripe.com/docs/api/checkout/sessions/create#create_checkout_session-line_items-price_data
Or, create the Product and Price separately :
https://stripe.com/docs/api/products/create
https://stripe.com/docs/api/prices/create

Stripe - How to get billing address information in Checkout.Session

I'm trying to get the billing address from Stripe Checkout from a Webhook call.
What I'm trying to achieve is to get the information from the form in the yellow rectangle.
This is my Checkout configuration :
var options = new SessionCreateOptions()
{
CustomerEmail = user.Email,
BillingAddressCollection = "required",
ShippingAddressCollection = new SessionShippingAddressCollectionOptions
{
AllowedCountries = new List<string>
{
"FR",
},
},
PaymentMethodTypes = new List<string>() {
result.Payment.Type
},
LineItems = new List<SessionLineItemOptions>{
new SessionLineItemOptions
{
PriceData = new SessionLineItemPriceDataOptions
{
UnitAmountDecimal = result.Payment.Amount * 100,
Currency = result.Payment.Currency,
ProductData = new SessionLineItemPriceDataProductDataOptions
{
Name = _stringLocalizer.GetString("StripeProductLabel"),
},
},
Quantity = 1,
},
},
Mode = result.Payment.Mode,
SuccessUrl = $"{request.Scheme}://{request.Host}" + "/payment/complete",
CancelUrl = $"{request.Scheme}://{request.Host}" + "/payment/cancel",
Metadata = new Dictionary<string, string>()
{
{ Constants.StripeMetaDataOrderId, result.Id }
}
};
and when I receive the session objet in the completed event : session = stripeEvent.Data.Object as Stripe.Checkout.Session;
I can't get the information because the paymentIntent object is null ( information from : Retrieve Billing Address from Stripe checkout session? ).
This is an important feature from Sripe because the application is a B2B application to help professionals to create orders for their B2C business. It will avoid making custom code from something that exits in Stripe API :)
Thanks in advance
The answer you linked to is the correct way to get this information, from the payment_method on the payment_intent. I'm not sure how/why your payment_intent value would not be populated, as my testing indicates this to be initialized upon creating the session, even if I never redirect to it.
Are you certain you're creating a mode=payment session? I see that in the code you shared, but things will change a bit if you're actually doing setup or subscription mode.

Delayed Payment in Stripe Connect to unknown user

I'm writing a service which allows users to sign up for classes, at the time of sign up the class instructor may not be known, but I need to create a pending charge to assure that the instructor will be paid. Later I want to update the pending and set a finalization date, e.g update the instructors account Id and 24 hours after the class ends pay the instructor
I'm trying to understand the work flow of how to do it, but the API Doc's don't seem to be helpful.
I have a service to create Payment Intents like so:
var paymentIntentService = new PaymentIntentService();
var paymentIntentTransferDataOptions = new PaymentIntentTransferDataOptions();
var options = new PaymentIntentCreateOptions
{
Amount = paymentIntentTransactionOptions.AmountInCents,
Currency = DEFAULT_TRANSACTION_CURRENCY,
ApplicationFeeAmount = this.CalculateApplicationFee(paymentIntentTransactionOptions),
ReceiptEmail = "", // TODO Obtain this from the Logged in user
PaymentMethodTypes = new List<string> { "card" },
};
var requestOptions = new RequestOptions();
requestOptions.IdempotencyKey = INTENT_IDEM_PREFIX + paymentIntentTransactionOptions.TransactionId;
var paymentIntent = await paymentIntentService.CreateAsync(options, requestOptions);
I would like to create a pending charge with no destination at first and before completion I will update the user to send it to.
The update process I would assume to just, call Get on the PaymentIntent and Update the Sender.
My confusion lays around 3 areas.
How does the API Know what user I'm allowed to send on behalf of a user?
e.g I just provide an accountId. Does the api have full control of other accounts after registration?
How can I Create a pending charge, to assure the instructor gets paid, does that happen when I create the payment intent?
How do I finalize the transaction (Now, or preferable with a future date)
I recently created an entire sharing economy platform with Stripe Connect, so I'm fairly familiar with it.
Charging the User: You'll need to create a regular charge for the user after they schedule the class. Read this on creating charges. This will charge the user $X and hold it in the platforms account without yet transferring it.
Paying the Instructor: You'll need to create a separate transfer using source_transaction to send the money to the instructor's account. source_transaction will basically just make the transfer from the charge you made earlier from the customer. You can read more about that here.
Regarding holding the funds for 24hrs, if you use source_transaction, the money won't become available for payout until after 2 days due to processing. You can read more about that here. If you want it to become available faster, you have 2 options. Either you can enable Instant Payout (which I don't recommend) or you can have a reserve balance in your platform stripe balance to cover the one-day layover and then you can make the transfers without source_transaction.
Okay, so after asking a few more questions and reading api docs. There are a few ways of doing this. #nachshonf answer will get the job done. However if I use transfers and seperate charges, The platform will be responsible for the Stripe fees and refund.
Instead I've come up with a more complex way of doing this, but will assure less of a headache for me in the long run. Basically I create a hold via the platform, and then when the instructor is resolved will request to issue another charge for the instructor. This way all disputes go through the instructor.
First off I'll create a hold via the platform, This is pretty simple
public Task<PaymentIntent>CreatePlatformHoldAsync(long amountInCents, string customerId,
string paymentMethodId, string idem = null, string currency = DEFAULT_TRANSACTION_CURRENCY)
{
var paymentIntentService = new PaymentIntentService();
var options = new PaymentIntentCreateOptions
{
Amount = amountInCents,
Currency = currency,
//ReceiptEmail = "", // TODO Obtain this from the Logged in user
PaymentMethodTypes = new List<string> { "card" },
CustomerId = customerId,
PaymentMethodId = paymentMethodId,
CaptureMethod = "manual",
};
var requestOptions = new RequestOptions { IdempotencyKey = idem };
return paymentIntentService.CreateAsync(options, requestOptions);
}
/// <summary>
/// Confirm a payment intent, on the platform or sellerAccount
/// </summary>
/// <param name="sellerStripeAccountId">optional, omit for the platform confirm</param>
public Task<PaymentIntent> ConfirmPaymentAsync(string paymentIntentId,
string sellerStripeAccountId = null)
{
var paymentIntentService = new PaymentIntentService();
var paymentIntentConfirmOptions = new PaymentIntentConfirmOptions();
var options = new RequestOptions
{
StripeAccount = sellerStripeAccountId
};
return paymentIntentService.ConfirmAsync(paymentIntentId,
paymentIntentConfirmOptions, options);
}
First create a hold, Then confirm it to authorize the charges. Then I'll create another charge for the instructor
public Task<PaymentIntent> CreateDestinationChargeAsync(long amountInCents, long applicationFeeInCents,
string paymentMethodId, string destinationAccountId, string idem = null,
string currency = DEFAULT_TRANSACTION_CURRENCY)
{
var paymentIntentService = new PaymentIntentService();
var options = new PaymentIntentCreateOptions
{
Amount = amountInCents,
Currency = currency,
ApplicationFeeAmount = applicationFeeInCents,
//ReceiptEmail = "", // TODO Obtain this from the Logged in user
PaymentMethodTypes = new List<string> { "card" },
PaymentMethodId = paymentMethodId,
};
var requestOptions = new RequestOptions
{
IdempotencyKey = idem,
StripeAccount = destinationAccountId
};
return paymentIntentService.CreateAsync(options, requestOptions);
}
After this is paid you can cancel the platform hold or wait 7 days for the hold to age away.
Edit For Usages
public async Task<Customer> CreateCustomerAsync(string email, string sourceToken)
{
var options = new CustomerCreateOptions
{
Email = email, // "paying.user#example.com",
Source = sourceToken,
};
var service = new CustomerService();
return await service.CreateAsync(options);
}
/// <summary>
/// Creates a payment method for a customer on the sellers stripe account
/// </summary>
/// <returns></returns>
public async Task<PaymentMethod> CreatePaymentMethodAsync(string customerId, string paymentMethodId,
string stripeConnectAccountId)
{
var paymentMethodService = new PaymentMethodService();
var paymentMethodOptions = new PaymentMethodCreateOptions
{
CustomerId = customerId,
PaymentMethodId = paymentMethodId
};
var requestOptions = new RequestOptions()
{
StripeAccount = stripeConnectAccountId
};
return await paymentMethodService.CreateAsync(paymentMethodOptions, requestOptions);
}
Usage:
//set destination here
var destinationAccountId = "";
var configuration = this.GetConfiguration();
StripeConfiguration.ApiKey = configuration["Stripe:ClientSecret"];
//This is the name of the service which I define the methods above
var stripeService = new StripeConnectService(configuration);
//"tok_mastercard" is a test value to represent a paymentToken
var customer = await stripeService.CreateCustomerAsync("CustomerEmail#gmail.com", "tok_mastercard");
var sharedPaymentMethod = await stripeService.CreatePaymentMethodAsync(customer.Id,
customer.DefaultSourceId, destinationAccount.AccountId);
var paymentIntent = await stripeService.CreateDestinationChargeAsync(1000, 100,
sharedPaymentMethod.Id, destinationAccountId);
await stripeService.ConfirmPaymentAsync(paymentIntent.Id, destinationAccountId);
These are examples and are not meant for production I'm only using them to test the flow.
Note: the payment token represents a customer. I haven't implemented a way to obtain the payment token but it looks like you will need stripe.js so they can enter there card information to create a token.

C# PayPal REST Api (.NET SDK)

I am using the .NET PayPal SDK (github.com/paypal/PayPal-NET-SDK) and am able to successfully create a paypal request, redirect the user, the user completes payment and all is well.
For the life of me, I can't figure out how to show the "Credit Card / No Paypal Account" screen instead of the "Login with paypal ... or click here if you don't have paypal to pay with credit card" screen.
Most of my users don't have paypal and just want to pay with a credit card (and I'd like to process it all through paypal, directly through their site so that users never give me their credit card number).
Here is the code I have that work for paying with paypal, but how can I tell it to show the "credit card/guest checkout" on paypal's landing page?
string PaypalRedirectURL(string returnURL, string cancelURL)
{
// create the transaction list
var trans = new List<Transaction>();
// make the actual transaction
var t = new Transaction()
{
description = "Payment For Something",
invoice_number = "inv1234",
amount = new Amount()
{
currency = "USD",
total = "2.00",
details = new Details
{
tax = "0",
shipping = "0",
subtotal = "2.00"
}
}
};
t.item_list = new ItemList();
t.item_list.items = new List<Item>();
Item i = new Item();
i.name = "Something I charge for";
i.quantity = "1";
i.sku = "item0001";
i.currency = "USD";
i.price = "2.00";
// Add item to item list
t.item_list.items.Add(i);
//add transaction to transaction list
trans.Add(t);
// create the payment
var payment = Payment.Create(GetAPIContext(), new Payment
{
intent = "sale",
payer = new Payer
{
payment_method = "paypal"
},
transactions = trans,
redirect_urls = new RedirectUrls
{
return_url = returnURL,
cancel_url = cancelURL
}
});
var links = payment.links.GetEnumerator();
string paypalRedirectUrl = null;
while (links.MoveNext())
{
Links lnk = links.Current;
// get the payment redirect link
if (lnk.rel.ToLower().Trim().Equals("approval_url"))
{
//saving the payapalredirect URL to which user will be redirected for payment
paypalRedirectUrl = lnk.href;
}
}
return paypalRedirectUrl;
}
I've tried numerous variations of [payment_method = "paypal"] (like (="credit_card", etc) but nothing seems to work. Again, I don't want to provide the credit card to this, I want the credit card "guest checkout" on paypal's site to show by default.
This is the screen the user gets on paypal (they can click the "pay with credit card" but I want to know if I can send them directly to the credit card screen without them having to click anything.
Current Page they are sent to:
Default paypal screen
Page I'd like the user to see by default (with the credit card fields displayed):
Desired default paypal page
Any help would be greatly appreciated .. thanks in advance

Categories

Resources