Getting Started
Welcome to the Payparse Developer Documentation. This guide walks you through integrating Interac e-Transfer payments into your application.
For production cutover (LXC, secrets, Cloudflare Tunnel, Email Worker), see deploy/production.md in the repository.
Local stack (optional)
docker compose up -d --build
App: http://localhost:3000 · Docs: http://localhost:3001. Compose runs migrations (and seeds demo data locally). Do not use seed against production.
1. Obtain API Credentials
Log into your Payparse Dashboard (app.payparse.ca), navigate to the API Credentials tab, and generate a new pair of keys:
- Publishable Key (
pp_pub_test_...): Client-side operations only. Safe to expose publicly in code. - Secret Key (
pp_live_test_...): Server-side operations only. Keep this secure.
2. Create a Checkout Session
From your backend server, execute an idempotent POST call to initialize the checkout window.
curl -X POST https://api.payparse.ca/v1/checkout/sessions \
-H "Authorization: Bearer pp_live_test_your_secret_key" \
-H "Idempotency-Key: a4b12c8d-eef9-41a4-92c2-7b192837bcde" \
-H "Content-Type: application/json" \
-d '{
"amount": 25000,
"currency": "cad",
"reference": "INV-2026-001",
"success_url": "https://yoursite.com/success",
"cancel_url": "https://yoursite.com/cancel"
}'
Response
{
"id": "cuid_session_id",
"checkout_url": "https://checkout.payparse.ca/sessions/cuid_session_id",
"client_secret": "cs_client_secret_token",
"status": "PENDING",
"reference": "INV-2026-001",
"memo": "PP-7K2M9Q",
"expires_at": "2026-07-15T17:30:00.000Z"
}
Parameter Constraints
| Field | Type | Constraints |
|---|---|---|
amount | Integer | Positive value strictly in cents (e.g., 25000 = $250.00 CAD) |
currency | String | Must be exactly "cad" (lowercase) |
reference | String | Non-empty, unique per merchant, max 255 characters |
success_url | String | Fully qualified URL (https://...) |
cancel_url | String | Fully qualified URL (https://...) |
metadata | Object | Optional — arbitrary key-value pairs attached to the session |
Idempotency
The Idempotency-Key header is required on every POST request. If a request with the same key was made within the last 24 hours, the cached response is returned with a X-Cache-Lookup: HIT header — no duplicate database row is created.
3. Redirect to Hosted Checkout
Use the checkout_url from the response to redirect your customer to the Payparse-hosted payment page:
// Server-side redirect
res.redirect(303, session.checkout_url);
The hosted checkout page displays the transaction details, bank selector, and copyable reference code.
4. Embed Checkout in an Iframe
For a seamless on-site experience, embed the checkout directly using the Payparse Client SDK:
<script src="https://js.payparse.ca/v1/payparse.js"></script>
<div id="payparse-container"></div>
<script>
const pp = Payparse('pp_pub_test_your_publishable_key');
pp.embedCheckout('#payparse-container', {
clientSecret: 'cs_client_secret_token',
onComplete: (result) => {
console.log('Payment status:', result.status);
},
onError: (error) => {
console.error('Checkout failed:', error.message);
}
});
</script>
The iframe is sandboxed with strict security attributes (allow-scripts allow-same-origin allow-forms allow-popups) and communicates via postMessage.
5. Listen for Webhook Events
Register a webhook endpoint to receive real-time payment status updates. Payparse signs every payload with HMAC-SHA256.
const crypto = require('crypto');
const express = require('express');
const app = express();
app.post('/webhooks/payparse', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-payparse-signature'];
const secret = process.env.PAYPARSE_WEBHOOK_SECRET;
const expected = crypto
.createHmac('sha256', secret)
.update(req.body)
.digest('hex');
const isValid = crypto.timingSafeEqual(
Buffer.from(signature, 'utf8'),
Buffer.from(expected, 'utf8')
);
if (!isValid) return res.status(401).json({ error: 'Invalid signature' });
const event = JSON.parse(req.body);
switch (event.type) {
case 'checkout.session.completed':
// Fulfill the order
break;
case 'payment.confirmed':
// Mark as paid in your database
break;
case 'payment.failed':
// Handle failure
break;
}
res.status(200).json({ received: true });
});
See Webhook Integrations for the full event catalog and verification details.
6. Retrieve Transaction Status
Query the transaction ledger to check payment status:
curl -X GET "https://api.payparse.ca/v1/payments?reference=INV-2026-001" \
-H "Authorization: Bearer pp_live_test_your_secret_key"
See the API Reference for all query parameters and response schemas.
Local Development Setup
For running the Payparse stack locally on your machine.
Prerequisites
| Requirement | Version | Purpose |
|---|---|---|
| Node.js | >= 24.0 | Runtime for gateway-app and SDK |
| npm | >= 10.0 | Workspace and dependency management |
| Docker | >= 24.0 | Container orchestration for services |
| Docker Compose | >= 2.20 | Multi-container orchestration |
| PostgreSQL | 18.4 | Primary database (via Docker) |
| Redis | 8.8 | Caching and job queues (via Docker) |
Clone and Install
git clone https://github.com/your-org/payparse.git
cd payparse
npm install
Environment Configuration
cp .env.example .env
Edit .env and generate secure keys:
# JWT Secret (256-bit hex)
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
# Encryption Key (256-bit hex for AES-256-GCM)
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
# API Key Salt (256-bit hex for HMAC-SHA256)
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
Start Infrastructure Services
docker compose up -d
docker compose ps # verify all containers are healthy
Initialize the Database
npm run db:generate
npm run db:migrate
Start the Development Server
npm run dev:api
The API server starts at http://localhost:3000.
Run Tests
npm run test
Project Structure
payparse/
├── gateway-app/ # Express.js + Next.js application
│ ├── prisma/ # Prisma schema and migrations
│ ├── src/
│ │ ├── api/ # REST API routes and middleware
│ │ ├── app/ # Next.js pages (checkout, dashboard)
│ │ ├── lib/ # Core utilities (prisma, redis, crypto)
│ │ └── email/ # Email parsing and SRS validation
│ └── public/sdk/ # Client-side SDK
├── packages/
│ └── payparse-mcp/ # Model Context Protocol server
├── odoo-module/ # Odoo 19 integration module
├── mail-server/ # Haraka mail server config
├── docs/ # Developer documentation site
└── docker-compose.yml # Service orchestration
Next Steps
- SDK Reference — Client-side iframe embedding mechanics
- API Reference — Full endpoint and parameter documentation
- Webhook Integrations — Signature verification and event handling