forked from pi-apps/pi-platform-docs
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 3e64b8b
Showing
5 changed files
with
422 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
# Javascript SDK | ||
|
||
The JS SDK is the frontend SDK, designed to be used in your HTML pages or Single-Page Apps, served in the Pi Browser. | ||
|
||
In order to enable the SDK to function correctly, you need to declare your apps on the Developer Portal (open | ||
develop.pi in the Pi Browser to access the Developer Portal). | ||
|
||
This SDK is **not** for a server-side NodeJS app. | ||
|
||
|
||
## Installation | ||
|
||
Add the following `script` tag to all pages where you need the SDK to be available: | ||
|
||
```html | ||
<script src="https://sdk.minepi.com/pi-sdk.js"></script> | ||
``` | ||
|
||
This will load the Pi Network JS SDK as a global `window.Pi` object. | ||
|
||
## Usage | ||
|
||
### Authenticate a user | ||
|
||
You cannot perform any user-related operations (e.g read the user's info, request a payment from them) until you | ||
have successfully authenticated the user. The first time, they will be presented with a dialog asking for | ||
their consent to share their data with your app. | ||
|
||
```javascript | ||
// Identify the user with their username / unique network-wide ID, and get permission to request payments from them. | ||
const scopes = ['username', 'payments']; | ||
function onOpenPaymentFound(payment) { /* ... */ }; // Read more about this in the SDK reference | ||
|
||
Pi.authenticate(scopes, onOpenPaymentFound).then(function(auth) { | ||
console.log(`Hello ${auth.user.username}. Your unique ID is ${auth.user.pi_id}`); | ||
}).catch(function(error) { | ||
console.error(error); | ||
}); | ||
``` | ||
|
||
### Request a payment | ||
|
||
The `createPayment` method enables you to request a payment from the current user to your app's account. | ||
|
||
The user will be prompted with a modal provided by the Pi Wallet, enabling them to sign the | ||
transaction and submit it to the Pi blockchain. | ||
|
||
```javascript | ||
|
||
const payment = Pi.createPayment({ | ||
amount: 3.14, // Amount of π to be paid | ||
reason: "Please pay for your order #1234", // User-facing explanation of the payment | ||
metadata: { orderId: 1234, itemIds: [11, 42, 314] }, // Developer-facing metadata | ||
}, { // Read more about those callbacks in the details docs linked below. | ||
onPaymentIdReceived: onPaymentIdReceived, | ||
onTransactionSubmitted: onTransactionSubmitted, | ||
onPaymentCancelled: onPaymentCancelled, | ||
onPaymentError: onPaymentError, | ||
}); | ||
|
||
``` | ||
|
||
This code block is a **simplified example** to give you a sense of how it works. | ||
|
||
In order to make sure that all involved parties (your app, your server, the Pi servers, and the Pi blockchain) are in sync, | ||
the payment needs to go through a **Server-Side Approval** flow and a **Server-Side Completion** flow. | ||
|
||
Please refer to: | ||
* [the full Payments documentation](./payments.md) to learn about the complete payment flow | ||
* [the Platform API documentation](./platform_API.md) to learn how to confirm the payment and acknowledge it from your | ||
server | ||
* the Demo App (coming soon!) to view an example of how you can implement the various required flows in your app's code. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
# Client SDK reference: | ||
|
||
## Authentication | ||
|
||
```typescript | ||
Pi.authenticate(scopes: Array<string>, onIncompletePaymentFound: Function<PaymentDTO>): Promise<PiAuth> | ||
``` | ||
|
||
Return value: | ||
|
||
```typescript | ||
type AuthResult { | ||
accessToken: string, | ||
user: { | ||
uid: string, | ||
pi_id: string, | ||
username: string | ||
} | ||
} | ||
``` | ||
|
||
### `scopes` | ||
|
||
> **Not yet implemented** | ||
> | ||
> Currently, all calls to the `authenticate` method will assume all scopes have been requested. | ||
Here is a breakdown of various keys available on the `PiAuth['user']` object, and the scopes required for those keys | ||
to be present: | ||
|
||
| Field | Description | Required Scope | | ||
| -------------: | ------------- | :-------------: | | ||
| `uid` | An app-local identifier for the user. This is specific to this user, and this app. It will change if the user revokes the permissions they granted to your app. | (none) | | ||
| `username` | The user's Pi username. | `username` | | ||
| `pi_id` | A network-wide identifier for this user. This will stay the same across all apps used by this user. | `username` | | ||
|
||
|
||
### `onIncompletePaymentFound` | ||
|
||
Signature: `(payment: PaymentDTO) => void` | ||
|
||
Every time the user is authenticated, and when they try to start a new payment flow, the SDK checks that there is no incomplete payment for this user. An incomplete payment, in this context, is a payment which has been submitted to the Pi blockchain, but where `status.developer_completed` is still `false` (i.e. the developer has not called the `/complete` endpoint on this payment). | ||
|
||
If an incomplete payment is found, this callback will be invoked with the payment's `PaymentDTO`. | ||
|
||
When this callback is invoked, it is your responsibility to complete the corresponding payment (you should most likely send the payment DTO to your server, and process it according to your business logic). You'll need to do so before you can request a new payment from the user. | ||
|
||
|
||
## Payments | ||
|
||
Create a new payment: | ||
|
||
```typescript | ||
type PaymentData = { | ||
amount: number, | ||
reason: string, | ||
metadata: Object, | ||
}; | ||
|
||
type PaymentCallbacks = { | ||
onPaymentIdReceived: (paymentId: string) => void, | ||
onTransactionSubmitted: (paymentId: string, txid: string) => void, | ||
onPaymentCancelled: (paymentId: string) => void, | ||
onPaymentError: (error: Error, payment?: PaymentDTO) => void, | ||
}; | ||
|
||
Pi.createPayment(paymentData: PaymentData, callbacks: PaymentCallbacks): void; | ||
``` | ||
|
||
The `createPayment` method takes two argument: `paymentData` and `callbacks`. | ||
|
||
It will immediately start the payment flow, which will open on top of your app, enabling the user to review | ||
the payment and submit the blockchain transaction, or reject it. | ||
|
||
> **Warning: concurrent payments:** | ||
> | ||
> When creating a new payment, if there is already an open payment with your app for the current user: | ||
> * If the user has not yet made the blockchain transaction, the open payment will be cancelled. | ||
> * If the user has already made the blockchain transaction, the new payment will be rejected | ||
> (`onPaymentError` will be called) and the `onOpenPaymentFound` method will be called with the | ||
> existing payment (use this callback to resolve the situation, e.g by completing the previous | ||
> payment from your backend). | ||
|
||
|
||
## `paymentData` keys: | ||
|
||
### `amount` | ||
|
||
This is the amount that the user is requested to pay to your app. | ||
|
||
Example: `3.1415`. | ||
|
||
### `reason` | ||
|
||
The reason for this payment. This will be visible to the user. | ||
|
||
Example: `Please pay for order #1234`. | ||
|
||
### `metadata` | ||
|
||
An arbitrary object that you can attach to this payment. This is for your own use, and it won't | ||
be shown to the user. You should use this object as a way to link this payment with your internal | ||
business logic. | ||
|
||
Example: `{ orderId: 1234, itemIds: [11, 42, 314] }` | ||
|
||
## `callbacks` keys: | ||
|
||
### `onPaymentIdReceived` | ||
|
||
Signature: `(paymentId: string) => void` | ||
|
||
This is called when the payment identifier (paymentId) is obtained from Pi Servers. | ||
|
||
Use this callback to send the paymentId to your backend for **Server-Side Approval**. | ||
Read more about Server-Side Approval and the full payment flow in the dedicated | ||
[Payments](payments.md) page. | ||
|
||
### `onTransactionSubmitted` | ||
|
||
Signature: `(paymentId: string, txid: string) => void` | ||
|
||
This is called when the user has submitted the transaction to the Pi blockchain. | ||
|
||
Use this callback to send the blockchain transaction identifier (txid), along with the paymentId | ||
to your backend for **Server-Side Completion**. | ||
Read more about Server-Side Completion and the full payment flow in the dedicated | ||
[Payments](payments.md) page. | ||
|
||
### `onPaymentCancelled` | ||
|
||
Signature: `(paymentId: string) => void` | ||
|
||
This is called when the payment is cancelled (by a user action, or programmatically). | ||
|
||
The payment may be cancelled either because the user manually rejected it, or because | ||
of some other blocking situation: the user doesn't have enough funds on their account | ||
to make the payment, another payment has been created concurrently... | ||
|
||
### `onPaymentError` | ||
|
||
Signature: `(error: Error, payment?: PaymentDTO) => void` | ||
|
||
This is called when an error occurs and the payment cannot be made. If the payment has been | ||
created, the second argument will be present and you may use it to investigate the error. | ||
Otherwise, only the first argument will be provided. | ||
|
||
|
||
## Share dialog | ||
|
||
Open a native share dialog: | ||
|
||
```typescript | ||
Pi.openShareDialog(title: string, message: string): void; | ||
``` | ||
|
||
Use this method to open a native Share dialog (provided by the phone's OS), enabling your users to share | ||
content from your app with their friends. | ||
|
||
* `title`: the title of the message being shared | ||
* `message`: the message that will be sent when the user picks a target app in the Share flow |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# Payments | ||
|
||
Payments are wrappers around blockchain transactions, which enable your app, | ||
the Pi blockchain, and the Pi Servers to be all synchronized when the user | ||
submits a blockchain transaction to pay for something in your app. | ||
|
||
They enable you, the developer of the app, to have full confidence that the | ||
user has actually made the transaction, while not having to | ||
bother with the technicalities involved when interacting with the Pi blockchain. | ||
|
||
|
||
## The Payment flow | ||
|
||
After they're created, payments go through 3 major phases: | ||
|
||
1. Payment creation and Server-Side Approval | ||
2. User interaction and blockchain transaction | ||
3. Server-Side Completion | ||
|
||
|
||
![Payment flow](./img/payment_flow.jpg) | ||
|
||
**Phase I - Payment creation and Server-Side Approval** | ||
|
||
1. `createPayment`: Your app's frontend creates the payment. The Payment Flow UI opens, but cannot be interacted with until the payment is approved by your server. | ||
|
||
2. `onPaymentIdReceived`: The JS SDK has obtained the payment identifier (PaymentID) and is passing it to your app for Server-Side approval. | ||
|
||
3. Your app's frontend sends the PaymentID to your app's server. This implementation is your responsibility. | ||
|
||
4. Server-Side Approval: Your app's server approves the payment with Pi Servers through the `/approve` API call. This enables the user to submit the blockchain transaction. | ||
|
||
**Phase II - User interaction and blockchain transaction** | ||
|
||
At this stage, the payment dialog becomes interactive and enables the | ||
user to confirm the transaction, sign it, and submit it to the Pi blockchain. | ||
|
||
You do not have anything to do at this stage, everything is handled by the Pi | ||
Apps Platform and the Pi Wallet. | ||
|
||
After the blockchain transaction is submitted, the payment flow will not close. | ||
You need to acknowledge the payment through Server-Side completion before your | ||
app is visible again. | ||
|
||
|
||
**Phase III - Server-Side Completion** | ||
|
||
5. `onTransactionSubmitted`: The JS SDK passes the blockchain transaction identifier (TxID) to your app's frontend. You need this value for the Server-Side Completion flow. | ||
|
||
6. Your app's frontend sends the TxID to your app's server. This implementation is your responsibility. | ||
|
||
7. Server-Side Completion: Your app's server acknowledges the payment with Pi Servers through the `/complete` API call. This enables you to check whether the blockchain transaction has actually happened, and to let Pi know that | ||
you're aware of it. | ||
|
||
8. The payment flow closes. Your app is now visible to the user again. | ||
Your app's server and your app's frontend can exchange data, and | ||
update the app interface to show a confirmation screen to the user. | ||
This implementation is your responsibility. | ||
|
||
|
||
> **The user might be lying to your app!** | ||
> | ||
> Users might be running a hacked version of the SDK, pretending that they | ||
> have made a payment. If the API call for Server-Side completion | ||
> returns a non-200 error code, **do not** mark the payment as complete on your | ||
> side, and **do not** deliver whatever the user was trying to buy. |
Oops, something went wrong.