Skip to content

Commit a904a4a

Browse files
committed
Merge branch 'master' of github.com:paystackhq/paystack-ios
2 parents 0e6cc8b + d4c0905 commit a904a4a

2 files changed

Lines changed: 81 additions & 217 deletions

File tree

GUIDE.md

Lines changed: 67 additions & 214 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,37 @@
11
# Guide
22

3-
If you want to build a mobile app like [Afro](http://www.getafrocab.com) and enable people to make purchases directly in your app, our iOS and [Android](https://github.com/PaystackHQ/paystack-android) libraries can help.
3+
If you want to build mobile apps like [Taxify](http://www.taxify.eu), [Afro](http://www.getafrocab.com), [Okada Books](https://www.okadabooks.com) and enable people to make purchases directly in your app, our iOS and [Android](https://github.com/PaystackHQ/paystack-android) libraries can help.
44

5-
Accepting payments in your app after collecting card information can be acieved in either of two ways, which we'll cover in this guide. The `authorization code` from either option can be used on your server in future to charge the cards.
5+
Accepting payments in your app after collecting card information can be achieved by charging the card with our SDK. Reusable `authorization code`s from such transaction from can be used from your backend to charge the cards directly.
66

7-
#### Option 1 - Charge the card directly from App
8-
- Charging the credit card and get the transaction `reference`
9-
- Verifying the transaction on your server which provides an `authorizaton code` if successful
7+
## Summarized flow
108

11-
or
9+
Once it's time to pay, and the user has provided card details on your app,
10+
11+
#### OPTION 1: Backend starts transaction (recommended)
12+
13+
a. App prompts backend to initialize a transaction, backend returns `access_code`.
14+
15+
b. Provide `access_code` and card details to our SDK's `chargeCard` function.
16+
17+
#### OPTION 2: App starts transaction
18+
19+
a. Provide transaction parameters and card params to our SDK's `chargeCard` function.
20+
21+
#### SDK will prompt user for PIN, OTP or Bank authentication as required
22+
23+
#### Once successful, we will send event to your webhook url and call the didTransactionSuccess callback
1224

13-
#### Option 2 - Tokenize on App, charge on server
14-
- Converting the credit card information to a _**single-use**_ `token`
15-
- Sending this token to your server to create a charge which provides an `authorizaton code` if successful
1625

1726
## Getting Started
1827

28+
### Step 0: Add Keychain Sharing entitlements to your app
29+
1930
### Step 1: Install the library
2031

2132
#### Manual installation
2233

23-
We also publish our SDK as a static framework that you can copy directly into your app without any additional tools:
34+
We publish our SDK as a static framework that you can copy directly into your app without any additional tools:
2435

2536
- Head to our [releases page](https://github.com/PaystackHQ/paystack-ios/releases/) and download the framework that's right for you.
2637
- Unzip the file you downloaded.
@@ -44,7 +55,7 @@ We also support installing our SDK using Carthage. You can simply add github "pa
4455

4556
### Step 2: Configure API keys
4657

47-
First, you'll want to configure Paystack with your public API key. We recommend doing this in your `AppDelegate`'s `application:didFinishLaunchingWithOptions:` method so that it'll be set for the entire lifecycle of your app.
58+
First, you'll want to configure Paystack with your public API key. We recommend doing this in your `AppDelegate`'s `application:didFinishLaunchingWithOptions:` method so that it will be set for the entire lifecycle of your app.
4859

4960
```Swift
5061
// AppDelegate.swift
@@ -85,7 +96,12 @@ We've placed a test public API key as the PaystackPublicKey constant in the abov
8596
8697
When you're using your test public key, our libraries give you the ability to test your payment flow without having to charge real credit cards.
8798
88-
If you're building your own form or using `PSTCKPaymentCardTextField`, using the card number `4123450131001381` with CVC `883` (along with any future expiration date) will accomplish the same effect.
99+
If you're building your own form or using `PSTCKPaymentCardTextField`, using any of:
100+
101+
1. card number `4084084084084081` with CVC `408` (along with any future expiration date); or;
102+
2. card number `5060666666666666666` with CVC `123` and any future expiration date, PIN `1234`, OTP `123456`
103+
104+
will accomplish the same effect.
89105
90106
At some point in the flow of your app, you'll want to obtain payment details from the user. There are two ways to do this. You can (in increasing order of complexity):
91107
@@ -208,18 +224,42 @@ cardParams.expMonth = 9;
208224

209225
### Step 4: Getting payments
210226

211-
Our libraries shoulder the burden of PCI compliance by helping you avoid the need to send card data directly to your server. Instead, our libraries send credit card data directly to our servers, where we can charge them or create tokens which you charge on your server.
227+
Our libraries shoulder the burden of PCI compliance by helping you avoid the need to send card data directly to your server. Instead, our libraries send credit card data directly to our servers, where we can charge them or create authorizations which you charge on your server.
228+
229+
We charge cards you send using parameters provided in your `PSTCKTransactionParams`. Assemble Transaction parameters into `PSTCKTransactionParams`, and send them along with the `cardParams` from the previous step to get a charge.
230+
231+
- **CardParams** - As gathered in [Step 3](#step-4-assembling-card-information-into-pstckcardparams)
232+
233+
- **TransactionParams** - This object allows you provide information about the transaction to be made. This can be used in either of 2 ways:
234+
- **Resume an initialized transaction**: If employing this flow, you would send all required parameters
235+
for the transaction from your backend to the Paystack API via the `transaction/initialize` call -
236+
documented [here](https://developers.paystack.co/reference#initialize-a-transaction).. The
237+
response of the call includes an `access_code`. This can be used to charge the card by doing
238+
`transactionParams.access_code = {value from backend});`. Once an access code is set, others will be ignored.
239+
- **Initiate a fresh transaction on Paystack**: By setting the parameters: `amount`, `email`, `currency`, `plan`,
240+
`subaccount`, `transactionCharge`, `reference`, `bearer`. And calling the `setCustomFieldValue` and `setMetadataValue`
241+
you can set up a fresh transaction directly from the SDK.
242+
Documentation for these parameters are same as for `transaction/initialize`.
243+
244+
- **ViewController** - A view controller to be used when presenting dialogs. The currently open ViewController is perfect.
245+
246+
You will need to specify callbacks too. Each will be called depending on how the transaction went.
212247

248+
- **didTransactionSuccess** will be called once the charge succeeds.
213249

214-
#### Step 4 Option 1: Charge Card
250+
- **didRequestValidation** is called every time the SDK needs to request user input. This function currently only allows the app know that the SDK is requesting further user input.
251+
252+
- **didEndWithError** is called if an error occurred during processing. Some types that you should watch include
253+
- *PSTCKErrorCode.PSTCKExpiredAccessCodeError*: This would be thrown if the access code has already been used to attempt a charge.
254+
- *PSTCKErrorCode.PSTCKConflictError*: This would be thrown if another transaction is currently being processed by the SDK
215255

216-
If you choose the `chargeCard` route, we charge cards you send using parameters provided in your `PSTCKTransactionParams`. Assemble Transaction parameters into `PSTCKTransactionParams`, and send them along with the `cardParams` to get a charge.
217256

218257
```Swift
219258
@IBAction func charge(sender: UIButton) {
220259
// cardParams already fetched from our view or assembled by you
221260
let transactionParams = PSTCKTransactionParams.init();
222261

262+
// building new Paystack Transaction
223263
transactionParams.amount = 1390;
224264
do {
225265
try transactionParams.setCustomFieldValue("iOS SDK", displayedAs: "Paid Via");
@@ -244,7 +284,7 @@ If you choose the `chargeCard` route, we charge cards you send using parameters
244284
}, didRequestValidation: { (reference) -> Void in
245285
// an OTP was requested, transaction has not yet succeeded
246286
}, didTransactionSuccess: { (reference) -> Void in
247-
// transaction may have succeeded, please verify on server
287+
// transaction may have succeeded, please verify on backend
248288
})
249289
}
250290
```
@@ -255,76 +295,28 @@ If you choose the `chargeCard` route, we charge cards you send using parameters
255295

256296
PSTCKTransactionParams transactionParams = [[PSTCKTransactionParams alloc] init];
257297

258-
transactionParams.amount = 1390;
259-
transactionParams.email = @"e@ma.il";
260-
261-
// check https://developers.paystack.co/docs/split-payments-overview for details on how these work
262-
// transactionParams.subaccount = @"ACCT_80d907euhish8d";
263-
// transactionParams.bearer = @"subaccount";
264-
// transactionParams.transaction_charge = 280;
265-
266-
// if a reference is not supplied, we will give one
267-
// transactionParams.reference = "ChargedFromiOSSDK@"
298+
// resuming a transaction initialized by backend
299+
transactionParams.access_code = '{access code from server}';
268300

269301
[[PSTCKAPIClient sharedClient] chargeCard:cardParams
270302
forTransaction:transactionParams
271303
onViewController: viewController,
272-
didEndWithError:^(NSError *error){
304+
didEndWithError:^(NSError *error, NSString *reference){
273305
[self handleError:error];
274306
}
275307
didRequestValidation: ^(NSString *reference){
276308
// an OTP was requested, transaction has not yet succeeded
277309
}
278310
didTransactionSuccess: ^(NSString *reference){
279-
// transaction may have succeeded, please verify on server
311+
// transaction may have succeeded, please verify on backend
280312
}];
281313

282314
}
283315
```
284316

285-
#### Step 4 Option 2: Using Tokens
286-
287-
If you choose the `createToken` route, we convert cards sent to tokens. You should charge these tokens later in your server-side code to get an authorization code.
288-
289-
```Swift
290-
@IBAction func save(sender: UIButton) {
291-
// cardParams Fetched from our view or built by you
292-
if let card = cardParams as? PSTCKCardParams {
293-
PSTCKAPIClient.sharedClient().createTokenWithCard(card) { (token, error) -> Void in
294-
if let error = error {
295-
handleError(error)
296-
}
297-
else if let token = token {
298-
...
299-
}
300-
}
301-
}
302-
}
303-
```
304-
305-
```Objective-C
306-
- (IBAction)save:(UIButton *)sender {
307-
// cardParams Fetched from our view or built by you
308-
[[PSTCKAPIClient sharedClient]
309-
createTokenWithCard:cardParams
310-
completion:^(PSTCKToken *token, NSError *error) {
311-
if (error) {
312-
[self handleError:error];
313-
} else {
314-
// call your createBackendChargeWithToken function
315-
// A sample is presented in step 6
316-
}
317-
}];
318-
}
319-
```
320-
321-
In the example above, we're calling `createTokenWithCard:` when a save button is tapped. The important thing to ensure is the createToken isn't called before the user has finished entering their card details.
322-
323-
Handling error messages and showing activity indicators while we're creating the token is up to you.
317+
### Step 5: Send the reference to your backend
324318

325-
### Step 6 Option 1: Sending the reference to your server
326-
327-
The blocks you gave to `chargeCard` will be called whenever Paystack returns with a reference (or error). You'll need to send the reference off to your server so you can verify the transactions.
319+
The blocks you gave to `chargeCard` will be called whenever Paystack returns with a reference (or error). You'll need to send the `reference` off to your backend so you can verify the transactions.
328320

329321
Here's how it looks:
330322

@@ -385,79 +377,11 @@ func verifyCharge(reference: String) {
385377

386378
```
387379

388-
On the server, you just need to implement an endpoint that will accept the parameter: `reference`. Make sure any communication with your server is SSL secured to prevent eavesdropping.
380+
On the server, you just need to implement an endpoint that will accept the parameter: `reference`. Make sure any communication with your backend is SSL secured to prevent eavesdropping.
389381

390-
### Step 6 Option 2: Sending the token to your server
391382

392-
The block you gave to `createToken` will be called whenever Paystack returns with a token (or error). You'll need to send the token off to your server so you can, for example, charge the card.
393-
394-
Here's how it looks:
395-
396-
```Swift
397-
// ViewController.swift
398-
399-
func createBackendChargeWithToken(token: PSTCKToken, amountinkobo: Int, emailAddress: String) {
400-
let url = NSURL(string: "https://example.com/token")!
401-
let request = NSMutableURLRequest(URL: url)
402-
request.HTTPMethod = "POST"
403-
let postBody = "token=\(token.tokenId!)&amountinkobo=\(amountinkobo)&email=\(emailAddress!)"
404-
let postData = postBody.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
405-
session.uploadTaskWithRequest(request, fromData: postData, completionHandler: { data, response, error in
406-
let successfulResponse = (response as? NSHTTPURLResponse)?.statusCode == 200
407-
if successfulResponse && error == nil && data != nil{
408-
// All was well
409-
let newStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
410-
print(newStr) // All we did here is log it to the output window
411-
} else {
412-
if let e=error {
413-
print(e.description)
414-
} else {
415-
// There was no error returned though status code was not 200
416-
print("There was an error communicating with your payment backend.")
417-
// All we did here is log it to the output window
418-
}
419-
420-
}
421-
}).resume()
422-
}
423-
```
424-
425-
```Objective-C
426-
// ViewController.m
427-
428-
- (void)createBackendChargeWithToken:(PSTCKToken *)token,
429-
(NSInt *) amountinkobo,
430-
(NSString *) emailAddress
431-
{
432-
NSURL *url = [NSURL URLWithString:@"https://example.com/token"];
433-
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
434-
request.HTTPMethod = @"POST";
435-
NSString *body = [NSString stringWithFormat:@"token=%@&amountinkobo=%@&email=%@", token.tokenId, amountinkobo, emailAddress];
436-
request.HTTPBody = [body dataUsingEncoding:NSUTF8StringEncoding];
437-
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
438-
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
439-
NSURLSessionDataTask *task =
440-
[session dataTaskWithRequest:request
441-
completionHandler:^(NSData *data,
442-
NSURLResponse *response,
443-
NSError *error) {
444-
if (error) {
445-
...
446-
} else {
447-
...
448-
}
449-
}];
450-
[task resume];
451-
}
452-
453-
```
454-
455-
On the server, you just need to implement an endpoint that will accept the parameters `token`, `email` and `amountinkobo`. Make sure any communication with your server is SSL secured to prevent eavesdropping.
456-
457-
--------------------
458-
459-
### Step 6 Option 1: Implement verification on your server
460-
Verify a charge by calling our REST API. An `authorization_code` will be returned once the card has been charged successfully. You can learn more about our API [here](https://developers.paystack.co/docs/getting-started).
383+
### Step 6: Implement verification on your server
384+
Verify a charge by calling our REST API. An active `authorization_code` will be returned once the card has been charged successfully. You can learn more about our API [here](https://developers.paystack.co/docs/getting-started).
461385

462386
**Endpoint:** GET: https://api.paystack.co/transaction/verify
463387

@@ -470,83 +394,12 @@ Verify a charge by calling our REST API. An `authorization_code` will be returne
470394
**Example**
471395

472396
```bash
473-
$ curl https://api.paystack.co/transaction/verify/ChargedFromiOSSDK%40 \
397+
$ curl https://api.paystack.co/transaction/verify/trx_sjdhf2987hb \
474398
-H "Authorization: Bearer SECRET_KEY" \
475399
-H "Content-Type: application/json" \
476400
-X GET
477401

478402
```
479-
### Step 6 Option 2: Implement payment on your server
480-
Create a charge by calling our REST API. An `authorization_code` will be returned once the _single-use_ token has been charged successfully. You can learn more about our API [here](https://developers.paystack.co/docs/getting-started).
481-
482-
**Endpoint:** POST: https://api.paystack.co/transaction/charge_token
483-
484-
**Documentation:** https://developers.paystack.co/docs/charge-token
485-
486-
**Parameters:**
487-
488-
- token - the token you want to charge (required)
489-
- reference - unique reference
490-
- email - customer's email address (required)
491-
- amount - Amount in Kobo (required)
492-
493-
**Example**
494-
495-
```bash
496-
$ curl https://api.paystack.co/transaction/charge_token \
497-
-H "Authorization: Bearer SECRET_KEY" \
498-
-H "Content-Type: application/json" \
499-
-d '{"token": "PSTK_r4ec2m75mrgsd8n9", "email": "customer@email.com", "amount": 10000, "reference": "amutaJHSYGWakinlade256"}' \
500-
-X POST
501-
502-
```
503-
### Using the [Paystack-PHP library](https://github.com/yabacon/paystack-php) or [Paystack PHP class](https://github.com/yabacon/paystack-class)
504-
```php
505-
list($headers, $body, $code) = $paystack->transaction->chargeToken([
506-
'reference'=>'amutaJHSYGWakinlade256',
507-
'token'=>'PSTK_r4ec2m75mrgsd8n9',
508-
'email'=>'customer@email.com',
509-
'amount'=>10000 // in kobo
510-
]);
511-
512-
// check if authorization code was generated
513-
if ((intval($code) === 200) && array_key_exists('status', $body) && $body['status']) {
514-
// body contains Array with data similar to result below
515-
$authorization_code = $body['authorization']['authorization_code'];
516-
// save the authorization_code so you may charge in future
517-
} else {
518-
// invalid body was returned
519-
// handle this or troubleshoot
520-
throw new \Exception('Transaction Initialise returned non-true status');
521-
}
522-
523-
```
524-
525-
**Result**
526-
```json
527-
{
528-
"status": true,
529-
"message": "Charge successful",
530-
"data": {
531-
"amount": 10000,
532-
"transaction_date": "2016-01-26T15:34:02.000Z",
533-
"status": "success",
534-
"reference": "amutaJHSYGWakinlade256",
535-
"domain": "test",
536-
"authorization": {
537-
"authorization_code": "AUTH_d47nbp3x",
538-
"card_type": "visa",
539-
"last4": "1111",
540-
"bank": null
541-
},
542-
"customer": {
543-
"first_name": "John",
544-
"last_name": "Doe",
545-
"email": "customer@email.com"
546-
},
547-
"plan": 0
548-
}
549-
```
550403

551404
### Charging Returning Customers
552-
See details for charging returning customers [here](https://developers.paystack.co/docs/charging-returning-customers).
405+
See details for charging returning customers [here](https://developers.paystack.co/docs/charging-returning-customers). Note that only `reusable` authorizations can be charged with this endpoint.

0 commit comments

Comments
 (0)