Skip to main content

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.
Never expose your secret key client-side. Use environment variables and keep it on your backend server only.

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

FieldTypeConstraints
amountIntegerPositive value strictly in cents (e.g., 25000 = $250.00 CAD)
currencyStringMust be exactly "cad" (lowercase)
referenceStringNon-empty, unique per merchant, max 255 characters
success_urlStringFully qualified URL (https://...)
cancel_urlStringFully qualified URL (https://...)
metadataObjectOptional — 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

RequirementVersionPurpose
Node.js>= 24.0Runtime for gateway-app and SDK
npm>= 10.0Workspace and dependency management
Docker>= 24.0Container orchestration for services
Docker Compose>= 2.20Multi-container orchestration
PostgreSQL18.4Primary database (via Docker)
Redis8.8Caching 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