Skip to content

Commit e24b784

Browse files
Add create paypal token and create paypal transaction
1 parent cd43559 commit e24b784

File tree

3 files changed

+193
-0
lines changed

3 files changed

+193
-0
lines changed

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@
2525
"paypal-sdk"
2626
],
2727
"devDependencies": {
28+
"@types/node": "^17.0.18",
2829
"ts-node": "^10.5.0",
2930
"typescript": "^4.5.5"
31+
},
32+
"dependencies": {
33+
"axios": "^0.26.0"
3034
}
3135
}

src/index.ts

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
import axios from 'axios'
2+
3+
type AuthProps = {
4+
username: string
5+
password: string
6+
}
7+
8+
type PaypalEnvironment = 'LIVE' | 'SANDBOX'
9+
10+
type Currencies =
11+
| 'USD'
12+
| 'NZD'
13+
| 'NOK'
14+
| 'PHP'
15+
| 'PLN'
16+
| 'GBP'
17+
| 'RUB'
18+
| 'SGD'
19+
| 'SEK'
20+
| 'CHF'
21+
| 'THB'
22+
| 'CZK'
23+
| 'DKK'
24+
| 'EUR'
25+
| 'HKD'
26+
| 'HUF'
27+
| 'ILS'
28+
| 'JPY'
29+
| 'MYR'
30+
| 'MXN'
31+
| 'TWD'
32+
| 'AUD'
33+
| 'BRL'
34+
| 'CAD'
35+
| 'CNY'
36+
37+
type TransactionConfig = {
38+
PAYPAL_ENVIRONMENT: PaypalEnvironment
39+
PAYPAL_CLIENT_ID: string
40+
PAYPAL_SECRET_ID: string
41+
}
42+
43+
type CreateTokenOptions = TransactionConfig
44+
45+
type TransactionOptions = {
46+
amount: number
47+
payment_description: string
48+
return_url?: string
49+
cancel_url?: string
50+
currency?: Currencies
51+
}
52+
53+
type TransactionData = {
54+
intent: 'sale'
55+
payer: {
56+
payment_method: 'paypal'
57+
}
58+
transactions: {
59+
amount: {
60+
total: number
61+
currency: Currencies
62+
}
63+
description: string
64+
}[]
65+
redirect_urls: {
66+
return_url: string
67+
cancel_url: string
68+
}
69+
}
70+
71+
type CreateTokenResponse = {
72+
access_token: string
73+
}
74+
75+
type CreateTransactionResponse = {
76+
orderId?: string
77+
}
78+
79+
module Paypal {
80+
const getUrl = (env: PaypalEnvironment): string => {
81+
return env === 'LIVE'
82+
? 'https://api-m.paypal.com'
83+
: 'https://api-m.sandbox.paypal.com'
84+
}
85+
86+
export const createToken = async (
87+
options: CreateTokenOptions
88+
): Promise<CreateTokenResponse> => {
89+
try {
90+
const PAYPAL_API = getUrl(options.PAYPAL_ENVIRONMENT)
91+
const url: string = `${PAYPAL_API}/v1/oauth2/token`
92+
93+
const auth: AuthProps = {
94+
username: options.PAYPAL_CLIENT_ID,
95+
password: options.PAYPAL_SECRET_ID
96+
}
97+
98+
const response = await axios({
99+
method: 'post',
100+
url,
101+
data: 'grant_type=client_credentials', // => this is mandatory x-www-form-urlencoded. DO NOT USE json format for this
102+
headers: {
103+
Accept: 'application/json',
104+
'Content-Type': 'application/x-www-form-urlencoded', // => needed to handle data parameter
105+
'Accept-Language': 'en_US',
106+
'Access-Control-Allow-Origin': '*'
107+
},
108+
auth
109+
})
110+
111+
return {
112+
access_token: response.data.access_token
113+
}
114+
} catch (err: any) {
115+
throw Error(err)
116+
}
117+
}
118+
119+
export const createTransaction = async (
120+
transaction: TransactionOptions,
121+
configs: TransactionConfig
122+
): Promise<CreateTransactionResponse> => {
123+
try {
124+
const PAYPAL_API: string = getUrl(configs.PAYPAL_ENVIRONMENT)
125+
const url: string = `${PAYPAL_API}/v1/payments/payment`
126+
127+
const token = await createToken(configs)
128+
129+
const data: TransactionData = {
130+
intent: 'sale',
131+
payer: {
132+
payment_method: 'paypal'
133+
},
134+
transactions: [
135+
{
136+
amount: {
137+
total: transaction.amount,
138+
currency: transaction.currency ?? 'USD'
139+
},
140+
description: transaction.payment_description
141+
}
142+
],
143+
redirect_urls: {
144+
return_url: transaction.return_url ?? 'https://example.com',
145+
cancel_url: transaction.cancel_url ?? 'https://example.com'
146+
}
147+
}
148+
149+
const response = await axios.post(url, data, {
150+
headers: {
151+
Authorization: 'Bearer ' + token,
152+
'Content-Type': 'application/json'
153+
}
154+
})
155+
156+
let orderId: undefined | string
157+
158+
for (let link of response.data.links) {
159+
if (link.rel === 'approval_url') {
160+
orderId = link.href.match(/EC-\w+/)[0]
161+
}
162+
}
163+
164+
return { orderId }
165+
} catch (err: any) {
166+
throw Error(err)
167+
}
168+
}
169+
}
170+
171+
const paypal = Paypal
172+
export default paypal

yarn.lock

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@
3434
resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e"
3535
integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==
3636

37+
"@types/node@^17.0.18":
38+
version "17.0.18"
39+
resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.18.tgz#3b4fed5cfb58010e3a2be4b6e74615e4847f1074"
40+
integrity sha512-eKj4f/BsN/qcculZiRSujogjvp5O/k4lOW5m35NopjZM/QwLOR075a8pJW5hD+Rtdm2DaCVPENS6KtSQnUD6BA==
41+
3742
acorn-walk@^8.1.1:
3843
version "8.2.0"
3944
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
@@ -49,6 +54,13 @@ arg@^4.1.0:
4954
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
5055
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
5156

57+
axios@^0.26.0:
58+
version "0.26.0"
59+
resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.0.tgz#9a318f1c69ec108f8cd5f3c3d390366635e13928"
60+
integrity sha512-lKoGLMYtHvFrPVt3r+RBMp9nh34N0M8zEfCWqdWZx6phynIEhQqAdydpyBAAG211zlhX9Rgu08cOamy6XjE5Og==
61+
dependencies:
62+
follow-redirects "^1.14.8"
63+
5264
create-require@^1.1.0:
5365
version "1.1.1"
5466
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
@@ -59,6 +71,11 @@ diff@^4.0.1:
5971
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
6072
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
6173

74+
follow-redirects@^1.14.8:
75+
version "1.14.9"
76+
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7"
77+
integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==
78+
6279
make-error@^1.1.1:
6380
version "1.3.6"
6481
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"

0 commit comments

Comments
 (0)