sahilrajput.com

PayPal

PayPal Docs are just awesome to read. ~Sahil

Quick Links:

Get subscription details with axios using the access_token

/* eslint-disable @typescript-eslint/no-unused-vars */
// src: https://gist.github.com/romaad/cc588abf691ba1e29c4a853983de8eb1
const axios = require('axios');
const qs = require('qs');

const paypalApi = 'https://api-m.sandbox.paypal.com';

// PLEASE FILL THESE BEFORE RUNNING THE CODE ####
const clientId = '';
const clientSecret = '';

// We need this line to format the body in the expected way
// for 'application/x-www-form-urlencoded'
const payload = qs.stringify({
  grant_type: 'client_credentials',
  // Note: With `ignoreCache=true` a new token is issued ignoring the previously issued and still not expired token.
  ignoreCache: true, // (default=false)
});
const headers = {
  Accept: 'application/json',
  'Accept-Language': 'en_US',
  'content-type': 'application/x-www-form-urlencoded',
};
const auth = {
  username: clientId,
  password: clientSecret,
};
const config = {
  headers, auth,
};
const main = async () => {
  try {
    const paypalSubscriptionId = 'I-B9YPX4SD1FX3';
    const res1 = await axios.post(`${paypalApi}/v1/oauth2/token`, payload, config);

    const { data } = await axios.get(`${paypalApi}/v1/billing/subscriptions/${paypalSubscriptionId}`, {
      headers: {
        Authorization: `Bearer ${res1.data.access_token}`,
      },
    });
    console.log('data?', data);
  } catch (error) {
    console.log('error?', error.name);
    console.log('error?', error.message);
  }
};

main();

Generate access_token with axios

// src: https://gist.github.com/romaad/cc588abf691ba1e29c4a853983de8eb1
const axios = require('axios');
const qs = require('qs');

const paypalApi = 'https://api-m.sandbox.paypal.com';

// PLEASE FILL THESE BEFORE RUNNING THE CODE ####
const clientId = '';
const clientSecret = '';

// We need this line to format the body in the expected way
// for 'application/x-www-form-urlencoded'
const payload = qs.stringify({
  grant_type: 'client_credentials',
  // Note: With `ignoreCache=true` a new token is issued ignoring the previously issued and still not expired token.
  ignoreCache: true, // (default=false)
});
const headers = {
  Accept: 'application/json',
  'Accept-Language': 'en_US',
  'content-type': 'application/x-www-form-urlencoded',
};
const auth = {
  username: clientId,
  password: clientSecret,
};
const config = {
  headers, auth,
};
const main = async () => {
  try {
    const { data } = await axios.post(`${paypalApi}/v1/oauth2/token`, payload, config);
    console.log('data?', data);
  } catch (error) {
    console.log('error?', error.name);
    console.log('error?', error.message);
  }
};

main();

Important note about transactions in PayPal

image

To get all the transactions of a subscription

We can set start_date and end_date like that -

image

Monthly edge case subscription charge and end date guidance from Eric (Thanks Eric)

Link that may be helpful if you haven’t seen it (about a monthly renewal timing edge case):

Learn Paypal Subscription And Database Schema

Click here

Does paypal changes the subscriptionId when a subsciption is renewed?

No. It keeps the subscriptionId same always (chatGPT).

image

PayPal integration with 1. APIs OR PayPal SDK

We can choose from two options for the PayPal integration i.e,

  1. using a SDK from PayPal i.e,

OR

  1. Using HTTP API via our backend. This basically works because PayPal provides a way to redirect the user to a specific “return-url” for e.g., slasher.tv along with subscriptionId, and thus we can make use of that page to help show the user the status of his payment. How does this work?
  2. User initiates a subscription which is also known as subscription-activation, there are two types:
    • a.) using PaPpal login
    • b.) using Card Details

Users do this by hitting our slasher api, for e.g, /api/v1/podcast/activate-subscription and behind the scenes we’ll call activate-subscription api on paypal server.

  1. We get an “approve-url” as result of the “activate-subscription” request and then we return that url to the user.

  2. Utilising “approve-url” -
    • a.) User navigates to that url and finishes the payment by his PayPal login credentials.
    • b) If the user wants to make payment via card user can send card-details as payload for the API call we did in the 1st step, thus the payment will be done right away! (wow!).
  3. (Note: This step is only for PayPal login payment type only): When user visit the “approve-url”, he/she will be prompted to do the txn and will be redirected to a url like below -

https://example.com/app/podcasts/SUBSCRIPTION-RETURN-URL/return?subscription_id=I-VDA50T7LKCFY&ba_token=BA-1Y6871089W3522241&token=1MM66374W7146800L

Thus we can collect subscription_id and check for that subscription status after every 5 seconds while the user is still on this page (it is generally successful instantly though). And we can let the user know the txn is successful by calling a simple txn status or subscription status API on our backend. That’s all.

Let me know what your and Damon’s preferences are, if possible please try communicating with Damon as these are minute details and don’t make much difference after the process is complete.

What are actual differences though in my view in the above two ways?

  1. (API > SDK) I think with controlled API requests, we would have more control.
  2. (SDK > API) The npm library seems to be from official PayPal so it can be trusted too.
  3. (SDK > API) If we go with API requests then we would need to manage card details handling in frontend and which may be a one time thing but it would be reusable for future dating subscriptions too. (high effort task)
  4. (API > SDK) We would have more control on our frontend UI if we follow the API requests way.

PayPal personal (buyer) vs. business account (seller)

Login @ https://www.sandbox.paypal.com/signin

return url with PayPal

Note - You should:

  1. Go to Account Settings > Website payments > Website Preferences and enable both Auto return and Payment data transfer. For return url you may give https://slasher.tv/app/paypal/return-url but it isn’t useful as you must definte the return url in each create-subscription (POST /v1//billing/subscriptions) API call.
  2. You may also definte cancel_url as well as that would be helpful to know when the payment is failed.
- return url = https://example.com/return
https://example.com/return?subscription_id=I-VDA50T7LKCFY&ba_token=BA-1Y6871089W3522241&token=1MM66374W7146800L
- cancel_url =https://example.com/cancel
https://example.com/cancel?subscription_id=I-7M0U6C9DWEL3&ba_token=BA-0WY1453654212191G&token=4CJ88294AB124721F

- return url = https://example.com/page/subpage
https://example.com/page/subpage?subscription_id=I-7M0U6C9DWEL3&ba_token=BA-0WY1453654212191G&token=8Y12132035380693N
- "cancel_url": "https://example.com/page/subpage"
https://example.com/page/subpage?subscription_id=I-7M0U6C9DWEL3&ba_token=BA-0WY1453654212191G&token=4CJ88294AB124721F

Payment Data Transfer

Docs - Payment Data Transfer: Click here

We get nextBillingTime on showSubscription api

image

onApprove on paypal-react compponent function is only called when txn is approved (i.e., successful)

So, we have either of two options:

  1. use Transaction Search > List Transaction in postman PayPal api collection.
  2. use Subscriptions > Show subscriptions details in postman PayPal api collection.

image

You can browser subscriptions and plans in Selller Account (sandbox) like that

image

Now, you can use that button to toggle b/w group by product or group by plan view

image

image

image

ClientId and ClientSecret by Postman’s Public API Collection

Date: 29 August, 2023

Clientid:
AUv8rrc_P-EbP2E0mpb49BV7rFt3Usr-vdUZO8VGOnjRehGHBXkSzchr37SYF2GNdQFYSp72jh5QUhzG

ClientSecret:
EMnAWe06ioGtouJs7gLYT9chK9-2jJ--7MKRXpI8FesmY_2Kp-d_7aCqff7M9moEJBvuXoBO4clKtY0v

image

Get subscription details

image

Customize the PayPal Buttons

Click here

Tax Calcuation on items

image

Getting client id and secret

Account Settings > Account access > API access > Update > Manage REST API apps credentials

Image: 1/2

image

Image: 2/2

image

Enable Fetch Transaction permission

To be able to fetch transaction from my seller account I had to change this setting using my PayPal sandbox developer account**

image

Geting list of payments processed for a given subscription_id

We can get a list of transactions made for a given subscription by using List transactions for subscription API (we pass a subscription_id as param) in postman. We can use this showing all the payment history for a given person if we store a subscription_id for each user in the database.

Fetching transactions and especially subscription txns?

Getting the subscription txns and their respective ids from the list of transactions we get by List transactions REST API of postman collection

Source - API DOCS: Click here

image

image

image

Paypal Doesn’t support proration automatically

Source - Docs: Click here

Other links to help you prorate:

image

When creating a subscription

When creating a subscription you can give the start_date to set the start date and time for this subscription. Also, if you just want the subscription to start immeditely you can simply delete that field from the payload of the request and in the response you’ll see the current time automatically set by the paypal server.

image

There is no way to un-cancel a request

image

PayPal Webhook Simulator

Please use this site to generate a free url which you can use to test webhook on paypal.

More on cards

Credit Card Generator, How to use Failed Cards, More 3DS Payments and More Test Accounts.

image

image

image

image

Sandbox Details

// Sahil Personal Account (Sandbox Details)
// const clientId =  'AZxr-cT_Indgclkxvqr_yUgFqWiYUJpHLmOKwrucdOseQsFzSrfsCRLaBNZKH9rT5RGCAFK4QgppxKGS'
// const planIds = {
// 	one: 'P-1U585596S70968643MONXJHI',
// 	three: 'P-3J697311GS257702PMONXJIQ',
// 	six: 'P-81C6483981287853TMONXJJQ',
// }

Error: Things don't appear to be working at the moment. Please try again later.

Click here