Skip to content

Commit d03fb88

Browse files
author
skansal-plaid
authored
Implements UK payment initiation client library (#89)
1 parent a540b19 commit d03fb88

File tree

3 files changed

+342
-0
lines changed

3 files changed

+342
-0
lines changed

main.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,37 @@ func main() {
8484
handleError(err)
8585
}
8686
fmt.Println("Number of transactions:", len(transactionsResp.Transactions))
87+
88+
// POST /payment_initiation/recipient/create
89+
paymentRecipientCreateResp, err := client.CreatePaymentRecipient("John Doe", "GB33BUKB20201555555555", plaid.PaymentRecipientAddress{
90+
Street: []string{"Street Name 999"},
91+
City: "City",
92+
PostalCode: "99999",
93+
Country: "GB",
94+
})
95+
handleError(err)
96+
fmt.Println("Recipient ID:", paymentRecipientCreateResp.RecipientID)
97+
98+
// POST /payment_initiation/recipient/get
99+
paymentRecipientGetResp, err := client.GetPaymentRecipient(paymentRecipientCreateResp.RecipientID)
100+
handleError(err)
101+
fmt.Println("Recipient get response:", paymentRecipientGetResp)
102+
103+
// POST /payment_initiation/payment/create
104+
paymentCreateResp, err := client.CreatePayment(paymentRecipientCreateResp.RecipientID, "TestPayment", plaid.PaymentAmount{
105+
Currency: "GBP",
106+
Value: 100.0,
107+
})
108+
handleError(err)
109+
fmt.Println("Payment ID:", paymentCreateResp.PaymentID)
110+
111+
// POST /payment_initiation/payment/token/create
112+
paymentTokenCreateResp, err := client.CreatePaymentToken(paymentCreateResp.PaymentID)
113+
handleError(err)
114+
fmt.Println("Payment Token:", paymentTokenCreateResp.PaymentToken)
115+
116+
// POST /payment_initiation/payment/get
117+
paymentGetResp, err := client.GetPayment(paymentCreateResp.PaymentID)
118+
handleError(err)
119+
fmt.Println("Payment get response:", paymentGetResp)
87120
}

plaid/payment.go

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
package plaid
2+
3+
import (
4+
"encoding/json"
5+
"time"
6+
)
7+
8+
type PaymentRecipientAddress struct {
9+
// Street is an array with length in range [1, 4].
10+
Street []string `json:"street"`
11+
City string `json:"city"`
12+
PostalCode string `json:"postal_code"`
13+
// Country is an uppercase ISO 3166-1 alpha-2 country code.
14+
Country string `json:"country"`
15+
}
16+
17+
type createPaymentRecipientRequest struct {
18+
ClientID string `json:"client_id"`
19+
Secret string `json:"secret"`
20+
Name string `json:"name"`
21+
IBAN string `json:"iban"`
22+
Address PaymentRecipientAddress `json:"address"`
23+
}
24+
25+
type CreatePaymentRecipientResponse struct {
26+
APIResponse
27+
RecipientID string `json:"recipient_id"`
28+
}
29+
30+
func (c *Client) CreatePaymentRecipient(
31+
name string,
32+
iban string,
33+
address PaymentRecipientAddress,
34+
) (resp CreatePaymentRecipientResponse, err error) {
35+
jsonBody, err := json.Marshal(createPaymentRecipientRequest{
36+
ClientID: c.clientID,
37+
Secret: c.secret,
38+
Name: name,
39+
IBAN: iban,
40+
Address: address,
41+
})
42+
43+
if err != nil {
44+
return resp, err
45+
}
46+
47+
err = c.Call("/payment_initiation/recipient/create", jsonBody, &resp)
48+
return resp, err
49+
}
50+
51+
type getPaymentRecipientRequest struct {
52+
ClientID string `json:"client_id"`
53+
Secret string `json:"secret"`
54+
RecipientID string `json:"recipient_id"`
55+
}
56+
57+
type Recipient struct {
58+
RecipientID string `json:"recipient_id"`
59+
Name string `json:"name"`
60+
IBAN string `json:"iban"`
61+
Address PaymentRecipientAddress `json:"address"`
62+
}
63+
64+
type GetPaymentRecipientResponse struct {
65+
APIResponse
66+
Recipient
67+
}
68+
69+
func (c *Client) GetPaymentRecipient(recipientID string) (resp GetPaymentRecipientResponse, err error) {
70+
jsonBody, err := json.Marshal(getPaymentRecipientRequest{
71+
ClientID: c.clientID,
72+
Secret: c.secret,
73+
RecipientID: recipientID,
74+
})
75+
76+
if err != nil {
77+
return resp, err
78+
}
79+
80+
err = c.Call("/payment_initiation/recipient/get", jsonBody, &resp)
81+
return resp, err
82+
}
83+
84+
type listPaymentRecipientsRequest struct {
85+
ClientID string `json:"client_id"`
86+
Secret string `json:"secret"`
87+
}
88+
89+
type ListPaymentRecipientsResponse struct {
90+
APIResponse
91+
Recipients []Recipient `json:"recipients"`
92+
}
93+
94+
func (c *Client) ListPaymentRecipients() (resp ListPaymentRecipientsResponse, err error) {
95+
jsonBody, err := json.Marshal(listPaymentRecipientsRequest{
96+
ClientID: c.clientID,
97+
Secret: c.secret,
98+
})
99+
100+
if err != nil {
101+
return resp, err
102+
}
103+
104+
err = c.Call("/payment_initiation/recipient/list", jsonBody, &resp)
105+
return resp, err
106+
}
107+
108+
type PaymentAmount struct {
109+
Currency string `json:"currency"`
110+
Value float64 `json:"value"`
111+
}
112+
113+
type createPaymentRequest struct {
114+
ClientID string `json:"client_id"`
115+
Secret string `json:"secret"`
116+
RecipientID string `json:"recipient_id"`
117+
Reference string `json:"reference"`
118+
Amount PaymentAmount `json:"amount"`
119+
}
120+
121+
type CreatePaymentResponse struct {
122+
APIResponse
123+
PaymentID string `json:"payment_id"`
124+
Status string `json:"status"`
125+
}
126+
127+
func (c *Client) CreatePayment(
128+
recipientID string,
129+
reference string,
130+
amount PaymentAmount,
131+
) (resp CreatePaymentResponse, err error) {
132+
jsonBody, err := json.Marshal(createPaymentRequest{
133+
ClientID: c.clientID,
134+
Secret: c.secret,
135+
RecipientID: recipientID,
136+
Reference: reference,
137+
Amount: amount,
138+
})
139+
if err != nil {
140+
return resp, err
141+
}
142+
143+
err = c.Call("/payment_initiation/payment/create", jsonBody, &resp)
144+
return resp, err
145+
}
146+
147+
type createPaymentTokenRequest struct {
148+
ClientID string `json:"client_id"`
149+
Secret string `json:"secret"`
150+
PaymentID string `json:"payment_id"`
151+
}
152+
153+
type CreatePaymentTokenResponse struct {
154+
APIResponse
155+
PaymentToken string `json:"payment_token"`
156+
PaymentTokenExpirationTime time.Time `json:"payment_token_expiration_time"`
157+
}
158+
159+
func (c *Client) CreatePaymentToken(
160+
paymentID string,
161+
) (resp CreatePaymentTokenResponse, err error) {
162+
jsonBody, err := json.Marshal(createPaymentTokenRequest{
163+
ClientID: c.clientID,
164+
Secret: c.secret,
165+
PaymentID: paymentID,
166+
})
167+
if err != nil {
168+
return resp, err
169+
}
170+
171+
err = c.Call("/payment_initiation/payment/token/create", jsonBody, &resp)
172+
return resp, err
173+
}
174+
175+
type getPaymentRequest struct {
176+
ClientID string `json:"client_id"`
177+
Secret string `json:"secret"`
178+
PaymentID string `json:"payment_id"`
179+
}
180+
181+
type Payment struct {
182+
PaymentID string `json:"payment_id"`
183+
PaymentToken *string `json:"payment_token"`
184+
Reference string `json:"reference"`
185+
Amount PaymentAmount `json:"amount"`
186+
Status string `json:"status"`
187+
LastStatusUpdate time.Time `json:"last_status_update"`
188+
PaymentTokenExpirationTime *time.Time `json:"payment_token_expiration_time"`
189+
RecipientID string `json:"recipient_id"`
190+
}
191+
192+
type GetPaymentResponse struct {
193+
APIResponse
194+
Payment
195+
}
196+
197+
func (c *Client) GetPayment(paymentID string) (resp GetPaymentResponse, err error) {
198+
jsonBody, err := json.Marshal(getPaymentRequest{
199+
ClientID: c.clientID,
200+
Secret: c.secret,
201+
PaymentID: paymentID,
202+
})
203+
if err != nil {
204+
return resp, err
205+
}
206+
207+
err = c.Call("/payment_initiation/payment/get", jsonBody, &resp)
208+
return resp, err
209+
}
210+
211+
type listPaymentsRequest struct {
212+
ClientID string `json:"client_id"`
213+
Secret string `json:"secret"`
214+
Count *int `json:"count"`
215+
Cursor *string `json:"cursor"`
216+
}
217+
218+
type ListPaymentsResponse struct {
219+
APIResponse
220+
Payments []Payment `json:"payments"`
221+
NextCursor string `json:"next_cursor"`
222+
}
223+
224+
type ListPaymentsOptions struct {
225+
Count *int
226+
Cursor *string
227+
}
228+
229+
func (c *Client) ListPayments(options ListPaymentsOptions) (resp ListPaymentsResponse, err error) {
230+
jsonBody, err := json.Marshal(listPaymentsRequest{
231+
ClientID: c.clientID,
232+
Secret: c.secret,
233+
Count: options.Count,
234+
Cursor: options.Cursor,
235+
})
236+
237+
if err != nil {
238+
return resp, err
239+
}
240+
241+
err = c.Call("/payment_initiation/payment/list", jsonBody, &resp)
242+
return resp, err
243+
}

plaid/payment_test.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package plaid
2+
3+
import (
4+
"testing"
5+
6+
assert "github.com/stretchr/testify/require"
7+
)
8+
9+
func TestPayment(t *testing.T) {
10+
paymentRecipientCreateResp, err := testClient.CreatePaymentRecipient("John Doe", "GB33BUKB20201555555555", PaymentRecipientAddress{
11+
Street: []string{"Street Name 999"},
12+
City: "City",
13+
PostalCode: "99999",
14+
Country: "GB",
15+
})
16+
assert.Nil(t, err)
17+
assert.NotNil(t, paymentRecipientCreateResp.RecipientID)
18+
recipientID := paymentRecipientCreateResp.RecipientID
19+
20+
paymentRecipientGetResp, err := testClient.GetPaymentRecipient(paymentRecipientCreateResp.RecipientID)
21+
assert.Nil(t, err)
22+
assert.NotNil(t, paymentRecipientGetResp.RecipientID)
23+
assert.NotNil(t, paymentRecipientGetResp.Name)
24+
assert.NotNil(t, paymentRecipientGetResp.IBAN)
25+
assert.NotNil(t, paymentRecipientGetResp.Address)
26+
27+
paymentRecipientListResp, err := testClient.ListPaymentRecipients()
28+
assert.Nil(t, err)
29+
assert.True(t, len(paymentRecipientListResp.Recipients) > 0)
30+
31+
paymentCreateResp, err := testClient.CreatePayment(recipientID, "TestPayment", PaymentAmount{
32+
Currency: "GBP",
33+
Value: 100.0,
34+
})
35+
assert.Nil(t, err)
36+
assert.NotNil(t, paymentCreateResp.PaymentID)
37+
assert.NotNil(t, paymentCreateResp.Status)
38+
paymentID := paymentCreateResp.PaymentID
39+
40+
paymentTokenCreateResp, err := testClient.CreatePaymentToken(paymentID)
41+
assert.Nil(t, err)
42+
assert.NotNil(t, paymentTokenCreateResp.PaymentToken)
43+
assert.NotNil(t, paymentTokenCreateResp.PaymentTokenExpirationTime)
44+
45+
paymentGetResp, err := testClient.GetPayment(paymentCreateResp.PaymentID)
46+
assert.Nil(t, err)
47+
assert.NotNil(t, paymentGetResp.PaymentID)
48+
assert.NotNil(t, paymentGetResp.PaymentToken)
49+
assert.NotNil(t, paymentGetResp.Reference)
50+
assert.NotNil(t, paymentGetResp.Amount)
51+
assert.NotNil(t, paymentGetResp.Status)
52+
assert.NotNil(t, paymentGetResp.LastStatusUpdate)
53+
assert.NotNil(t, paymentGetResp.PaymentTokenExpirationTime)
54+
assert.NotNil(t, paymentGetResp.RecipientID)
55+
56+
count := 10
57+
paymentListResp, err := testClient.ListPayments(ListPaymentsOptions{Count: &count})
58+
assert.Nil(t, err)
59+
assert.True(t, len(paymentListResp.Payments) > 0)
60+
61+
cursor := paymentListResp.NextCursor
62+
if cursor != "" {
63+
_, err = testClient.ListPayments(ListPaymentsOptions{Cursor: &cursor})
64+
assert.Nil(t, err)
65+
}
66+
}

0 commit comments

Comments
 (0)