---
# System prepended metadata

title: PayNow Implementation
tags: [paynow, work]

---

# PayNow Implementation

### Sequence of payment with PayNow

```sequence
User->Give.asia: Fill email, phone or NRIC
Note right of Give.asia: Validating
Give.asia-->User: Show page with payment methods
Note left of User: Select a PayNow
User->Give.asia: Pay with PayNow
Give.asia->PayNow: Send enquiry API request 
Note right of PayNow: Checking possibility for pay\n by phone or NRIC
PayNow-->Give.asia: Success
Give.asia->PayNow: Send request for QR code API
Note right of PayNow: Generating QR code
PayNow-->Give.asia: Base64 QR code
Note left of Give.asia: (maybe) Extract an account number\nfrom QR code
Note left of Give.asia: Create draft transaction
Give.asia-->User: Show the QR code for payment
Note left of User: Pay with mobile phone
User->PayNow: Payment via PayNow
Note right of PayNow: Payment complete
PayNow-->Give.asia: Send a webhook
Note left of Give.asia: Create transaction from draft
Give.asia-->User: Show a success page
Note left of Give.asia: Worker for finish transaction
```

#### The `draft_paynow_transactions` Table

| column                       | type      |
| ---------------------------- | --------- |
| id                           | Long      |
| amount                       | Long      |
| tip_amount                   | Long      |
| currency                     | String    |
| donor_is_anonymous           | Boolean   |
| donor_name                   | String    |
| donor_email                  | String    |
| donor_phone_number_opt       | String    |
| **donor_nric_opt**           | String    |
| donor_user_id_opt            | Long      |
| donor_utm_source_opt         | Text      |
| donor_utm_medium_opt         | Text      |
| donor_ip_address             | Text      |
| donor_tax_deduction_info     | Key-Value |
| donor_info                   | Key-Value |
| recipient_charity_id         | Long      |
| recipient_campaign_id_opt    | Long      |
| donation_package_summary     | Text      |
| donation_package_description | Text      |
| agent_user_id_opt            | Long      |
| agent_commission_opt         | Long      |
| agent_check_in_id_opt        | Long      |
| giviki_id                    | Long      |
| give_fee                     | Long      |
| ads_budget                   | Long      |
| lang                         | String    |
| suggested_tip_version_opt    | String    |
| suggested_tip_amount_opt     | String    |
| **qr_code_size**             | Int       |
| **qr_code_base64**           | Text      |
| **qr_code_expired_at**       | Long      |
| **paynow_account_number**    | Text      |
| **paynow_reference_text**    | Text      |
| **paynow_amount**            | Long      |
| **paynow_currency**          | String    |
| **exchange_rate**            | Float     | 
| created_at                   | Long      |

#### The `paynow_transactions` Table

| column                               | type      |
| ------------------------------------ | --------- |
| id                                   | Long      |
| public_key                           | String    |
| secret_key                           | String    |
| amount                               | Long      |
| tip_amount                           | Long      |
| currency                             | String    |
| donor_is_anonymous                   | Boolean   |
| donor_name                           | String    |
| donor_email                          | String    |
| donor_phone_number_opt               | String    |
| **donor_nric_opt**                   | String    |
| donor_user_id_opt                    | Long      |
| donor_utm_source_opt                 | Text      |
| donor_utm_medium_opt                 | Text      |
| donor_ip_address                     | Text      |
| donor_tax_deduction_info             | Key-Value |
| donor_info                           | Key-Value |
| ==donor_answers==                    | Key-Value |
| ==comment (WhyIGave)==               | Text      |
| recipient_charity_id                 | Long      |
| recipient_campaign_id_opt            | Long      |
| status                               | String    |
| donation_package_summary             | Text      |
| donation_package_description         | Text      |
| agent_user_id_opt                    | Long      |
| agent_commission_opt                 | Long      |
| agent_check_in_id_opt                | Long      |
| giviki_id                            | Long      |
| give_fee                             | Long      |
| ads_budget                           | Long      |
| lang                                 | String    |
| suggested_tip_version_opt            | String    |
| suggested_tip_amount_opt             | String    |
| **qr_code_size**                     | Int       |
| **qr_code_base64**                   | Text      |
| **qr_code_expired_at**               | Long      |
| **paynow_account_number**            | Text      |
| **==paynow_bank_reference_number==** | Text      |
| **paynow_reference_text**            | Text      |
| **paynow_amount**                    | Long      |
| **paynow_currency**                  | String    |
| **==paynow_fee==**                   | Long      |
| **==paynow_fee_currency==**          | String    |
| **exchange_rate**                    | Float     |
| created_at                           | Long      |
| ==refunded_at_opt==                  | Long      |

*\* **Specific** for PayNow*
*\* ==Specific== for transactions table*

I suppose we can pay only in SGD via PayNow so we need to store an exchange rate for the charge.

#### Recurring Transactions (postponed)

According PayNow API we can pay without an QR code via their `PayNow Payment API` but we need Sender's Account Number. I suppose that this account number we can extract from QR code because in their docs has note with link to Account Number field:

> There are 25 characters in QR Code. OCBC will reserve the first 3 characters. Customer can only use 22 characters. The report will extract those client reference that starts with QR Tracker Digit.

So it might be require to decode a QR code for extract `Account Number`.

Or maybe we can get it from the webhook. Actually I don't know yet which webhook returns in the request.

###### tags: `paynow` `work`