Pi SDK Express

This package, pi-sdk-express, helps you quickly scaffold, configure, and integrate all necessary components for using Pi Network payments, authentication, and user flows with a Next.js project. It is designed for modern Express apps that want a working, idiomatic Pi payment and authentication experience with minimal boilerplate.

The pi-sdk-express package is part of the “Ten Minutes to Transactions” effort described in this video.

If you are planning to use the Express framework for your app, it is highly suggested that you use this package rather than implement transaction processing by hand with the core Pi SDK. The three way handshake between client, server, and the Pi servers required is provded for you.


Express Quick Start

Register your application with Pi Network

While this process is covered in the Getting Started Guide, here is a brief reminder of the steps you need to take. Application registration is also discussed in the video.

  • Open your Pi Mining app.
  • Click the hamburger (☰).
  • Select “Pi Utilities”.
  • Click the “Develop” icon followed by the “New App” icon.
  • Provide name and description of your app and submit.
  • Then click the “Configuration” icon.
  • Set the app URL to something valid, but does not necessarily exist.
  • Set the development URL to be http://localhost:3000. The actual port is between you and your development server.
  • Submit your changes.
  • Get your API key.
  • Register a wallet for your app.

Add pi-sdk-express as a dependency in your Express project

npm install pi-sdk-express
yarn add pi-sdk-express

Run the Pi component and API scaffolder

npx pi-sdk-express-install
yarn pi-sdk-express-install

This will generate:

  • routes/pi_payment/ directory with individual route handlers
  • routes/pi_payment/index.ts - Router that exports all routes
  • app.example.ts - Example Express app setup

Basic Express Setup

Option A: Use the Router Factory (Quick Start)

import express from 'express';
import { createPiPaymentRouter } from 'pi-sdk-express';

const app = express();

// Required: JSON body parser middleware
app.use(express.json());

// Mount Pi payment routes
app.use('/pi_payment', createPiPaymentRouter());

app.listen(3000, () => {
  console.log('Server running on http://localhost:3000');
});

Option B: Use Generated Routes (More Control)

import express from 'express';
import piPaymentRoutes from './routes/pi_payment';

const app = express();

app.use(express.json());
app.use('/pi_payment', piPaymentRoutes);

app.listen(3000);

Frontend Integration

Use pi-sdk-js on your frontend to initiate payments. The frontend SDK will automatically call these endpoints.

For package docs and examples, see:

Set Environment Variables

export PI_API_KEY="your-api-key-here"
export PI_API_URL_BASE="https://api.minepi.com"  # Optional, defaults to this
export PI_API_VERSION="v2"                       # Optional, defaults to v2
export PI_API_CONTROLLER="payments"              # Optional, defaults to payments

API Endpoints

The router creates the following endpoints:

  • POST /pi_payment/approve - Approve a payment
  • POST /pi_payment/complete - Complete a payment
  • POST /pi_payment/cancel - Cancel a payment
  • POST /pi_payment/error - Handle payment errors
  • POST /pi_payment/incomplete - Handle incomplete payments

Express With React Quick Start

The process is similar to the one described above with the following differences.

Since there are two servers for providing Express and React functionality, we will need to create a frontend directory for the React service and a backend directory for Express. Create an empty directory for your app. We will fill it with these two directories.

Setting Up The React Frontend

First, lets create the frontend directory.

yarn create vite frontend -- --template react-ts --no-interactive
npm create vite frontend -- --template react-ts --no-interactive

Next, cd frontend so we can start modifying the basic React app.

yarn add pi-sdk-react
yarn pi-sdk-react-install --dest components
npm add pi-sdk-react
npx pi-sdk-react-install --dest components

We will need to let React know how to proxy Express requests. Add the following to vite.config.ts. It will also eliminate React version issues between the app and it’s packages.

// Place inside defineConfig. The "server" key should be at
// the same level as the existing "plugins" key.
server: {
  port: 3000,
  proxy: {
    // Forward /pi_payment to Express so requests don't stay on Vite's port
    '/pi_payment': {
      target: backendTarget,
      changeOrigin: true,
      configure(proxy) {
        proxy.on('error', (err, _req, _res) => {
          console.error(
            `[vite] pi_payment proxy error: backend not reachable at ${backendTarget}. Is the Express server running? (e.g. PORT=${backendPort} yarn start)`
          );
          console.error(err.message);
        });
      },
    },
  },
},
resolve: {
  // Single React instance so pi-sdk-react hooks use the apps React (avoids "useState of null")
  dedupe: ["react", "react-dom"],
},

In the same file, add these lines near the begining of the file.

const backendPort = process.env.BACKEND_PORT || 3001
const backendTarget = `http://127.0.0.1:${backendPort}

Now we are ready to add the Pi Button to the default app. In the src/App.tsx file add the import near the top and the tag where you wish.

import { PiButton } from "../components/PiButton"
// ...
<PiButton/>

Don’t forget to add the pi-sdk.js library to the page header in index.html.

<head>
  <!-- ... other <head> content (meta, title, styles, etc.) ... -->
  <script src="https://sdk.minepi.com/pi-sdk.js"></script>
</head>

Setting Up The Express Backend

Now, let’s create the backend directory.

npx express-generator backend --view=react

Next, cd backend so we can start modifying the basic Express app.

yarn add pi-sdk-express
yarn pi-sdk-react-express-install
npm add pi-sdk-react
npx pi-sdk-react-express-install

Finally, Express needs to know about the payment paths. Add these two lines to the app.js file.

// This should be near the top
var { createPiPaymentRouter } = require("pi-sdk-express");\
// This one should be placed with similar ```app.use``` lines
app.use("/pi_payment", createPiPaymentRouter());

Putting Them Together

These two servers need to be running in order to process transaction requests. You will need two terminal windows. Running one or both in the background of a terminal will mixup the server logs.

yarn dev             // in the app/frontend directory
PORT=3001 dev server // in the app/backend directory

Advanced Usage

Custom Incomplete Payment Handling

By default, incomplete payments are automatically completed. You can customize this behavior:

import { createPiPaymentRouter, IncompletePaymentDecision } from 'pi-sdk-express';

const router = createPiPaymentRouter({
  incompleteCallback: async (paymentId: string, transactionId: string): Promise<IncompletePaymentDecision> => {
    // Your custom logic here
    // Check database, review payment, etc.

    if (shouldComplete(paymentId)) {
      return 'complete';
    } else {
      return 'cancel';
    }
  }
});

Custom Middleware

Add authentication, logging, or other middleware:

import { createPiPaymentRouter } from 'pi-sdk-express';

const router = createPiPaymentRouter({
  middleware: [
    // Custom authentication middleware
    (req, res, next) => {
      const token = req.headers.authorization;
      if (!token) {
        return res.status(401).json({ error: 'Unauthorized' });
      }
      next();
    },
    // Custom logging middleware
    (req, res, next) => {
      console.log(`[${new Date().toISOString()}] ${req.method} ${req.path}`);
      next();
    }
  ]
});

Custom Route Mounting

Mount the router at a different path:

app.use('/api/payments/pi', createPiPaymentRouter());

Note: If you change the mount path, you’ll need to configure the frontend SDK accordingly.

Payment Flow

The complete payment flow involves three parties:

  1. Client (Browser) - Uses pi-sdk-js or pi-sdk-react
  2. Your Server (This SDK) - Processes payment requests
  3. Pi API - Final payment processing

Flow Steps:

  1. User clicks “Buy” button in your app
  2. Frontend SDK authenticates with Pi Network
  3. Frontend SDK creates payment: Pi.createPayment()
  4. User approves payment in Pi app
  5. Frontend calls POST /pi_payment/approve → Your server → Pi API
  6. Pi API processes payment
  7. Frontend calls POST /pi_payment/complete → Your server → Pi API
  8. Payment completed ✅

Error Handling

All endpoints return appropriate HTTP status codes:

  • 200 - Success
  • 400 - Bad Request (missing/invalid parameters)
  • 500 - Internal Server Error

Errors are logged to the console with [PiSDK] prefix for easy filtering.

Integration with Database

The SDK provides hooks for database integration. Example:

import { approveHandler } from 'pi-sdk-express';

// Custom approve handler with database
async function customApproveHandler(req: Request, res: Response) {
  const { accessToken, paymentId } = req.body;

  // Find or create user
  const user = await findOrCreateUser(accessToken);

  // Create transaction record
  const transaction = await Transaction.create({
    paymentId,
    userId: user.id,
    state: 'approval_pending'
  });

  // Call default handler (or implement your own Pi API call)
  // ... your implementation
}

License

PiOS License - See LICENSE file for details.