Skip to main content

API Reference

Base Configuration

PropertyValue
Production Base URLhttps://api.payparse.ca/v1
AuthenticationAuthorization: Bearer <API_KEY>
Content-Typeapplication/json
IdempotencyRedis-backed, 24-hour TTL per key

API Key Formats

PrefixTypeModeAccess Level
pp_pub_*PublishableLiveClient-side checkout creation only
pp_pub_test_*PublishableTestClient-side test checkout only
pp_live_*SecretLiveFull server-side API access (livemode: true)
pp_live_test_*SecretTestFull server-side API access (livemode: false)
pp_rk_*RestrictedLiveScope-limited server-side access

Secret keys created in the dashboard include checkout.write, payments.read, and events.read by default. Test secret keys never read or mutate live sessions/events.


1. Create Checkout Session

POST /v1/checkout/sessions

Initializes a new checkout session and returns a redirect URL or embedded client secret.

Required Headers

HeaderTypeRequiredDescription
AuthorizationStringYesBearer pp_live_*, Bearer pp_live_test_*, or Bearer pp_rk_*
Idempotency-KeyStringYesUnique UUID to prevent duplicate session creation. Cached for 24 hours.
Content-TypeStringYesapplication/json

Required Scopes

checkout.write

Test keys (pp_live_test_*) create sessions with livemode: false. Live keys create livemode: true.

Request Body

FieldTypeRequiredConstraintsDescription
amountIntegerYesPositive integer, value in cents (e.g., 2500 = $25.00 CAD)Transaction amount in CAD cents
currencyStringYesMust be exactly "cad" (lowercase)Currency code — only CAD is supported
referenceStringYesNon-empty, max 255 characters, unique per merchantYour platform's tracking ID (invoice, Odoo S00021, order id). Not shown to the payer.
success_urlStringYesFully qualified URL (https://...)Redirect destination on successful payment
cancel_urlStringYesFully qualified URL (https://...)Redirect destination on payment cancellation or expiry
metadataObjectNoArbitrary key-value pairsCustom metadata attached to the session and forwarded to webhooks

Response Codes

CodeMeaningBody
201Session created successfullySession object (see below)
200Idempotent cache hitOriginal session response + header X-Cache-Lookup: HIT
400Validation error{ "error": "Validation failed: ..." }
401Unauthorized{ "error": "Invalid or missing API key" }
403Forbidden (scope){ "error": "Insufficient scope: checkout.write required" }
409Reference conflict{ "error": "Reference already exists" }

Response Body (201 Created)

{
"id": "cuid_generated_session_id",
"checkout_url": "https://checkout.payparse.ca/sessions/cuid_generated_session_id",
"client_secret": "cs_secret_token_for_embedded_frames",
"status": "PENDING",
"livemode": true,
"reference": "INV-2026-0847",
"memo": "PP-7K2M9Q",
"expires_at": "2026-07-15T17:30:00.000Z"
}

Field Descriptions

FieldTypeDescription
idStringUnique checkout session identifier (CUID)
checkout_urlStringFully qualified hosted checkout page URL for redirect flow
client_secretStringToken for the embedded iframe checkout mode — never expose client-side
statusEnumAlways "PENDING" on creation
livemodeBooleantrue for live keys, false for test keys
referenceStringEcho of the merchant tracking ID you sent
memoStringPayparse-issued Interac message (PP-XXXXXX). Hosted checkout shows this; ingest matches it.
expires_atISO 8601Absolute expiration timestamp — session expires 30 minutes after creation

cURL Example

curl -X POST https://api.payparse.ca/v1/checkout/sessions \
-H "Authorization: Bearer pp_live_your_secret_key" \
-H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
-H "Content-Type: application/json" \
-d '{
"amount": 25000,
"currency": "cad",
"reference": "INV-2026-0847",
"success_url": "https://yoursite.com/payment/success?session_id={SESSION_ID}",
"cancel_url": "https://yoursite.com/payment/cancelled"
}'

Node.js Example

const response = await fetch('https://api.payparse.ca/v1/checkout/sessions', {
method: 'POST',
headers: {
'Authorization': 'Bearer pp_live_your_secret_key',
'Idempotency-Key': crypto.randomUUID(),
'Content-Type': 'application/json',
},
body: JSON.stringify({
amount: 25000,
currency: 'cad',
reference: 'INV-2026-0847',
success_url: 'https://yoursite.com/payment/success?session_id={SESSION_ID}',
cancel_url: 'https://yoursite.com/payment/cancelled',
}),
});

const session = await response.json();
// session.id, session.checkout_url, session.client_secret

2. Retrieve Checkout Session

GET /v1/checkout/sessions/:id

Returns the full state of an existing checkout session.

Required Headers

HeaderTypeRequiredDescription
AuthorizationStringYesBearer pp_live_* or Bearer pp_rk_*
Content-TypeStringYesapplication/json

Required Scopes

checkout.write

Sessions are isolated by merchant and livemode: a test key cannot retrieve a live session (and vice versa).

Path Parameters

ParameterTypeRequiredDescription
idStringYesThe checkout session identifier returned during creation

Response Codes

CodeMeaningBody
200Session foundFull CheckoutSession object
401Unauthorized{ "error": "Invalid or missing API key" }
403Forbidden (scope){ "error": "Insufficient scope: checkout.write required" }
404Not found{ "error": "Checkout session not found" }

Response Body (200 OK)

{
"id": "cuid_generated_session_id",
"amount": 25000,
"currency": "CAD",
"reference": "INV-2026-0847",
"memo": "PP-7K2M9Q",
"status": "PENDING",
"livemode": true,
"client_secret": "cs_secret_token_for_embedded_frames",
"success_url": "https://yoursite.com/payment/success?session_id={SESSION_ID}",
"cancel_url": "https://yoursite.com/payment/cancelled",
"metadata": null,
"expires_at": "2026-07-15T17:30:00.000Z",
"created_at": "2026-07-15T17:00:00.000Z"
}

Field Descriptions

FieldTypeDescription
idStringUnique checkout session identifier
amountIntegerTransaction amount in CAD cents
currencyStringAlways "CAD"
referenceStringYour platform tracking ID
memoStringPayparse-issued Interac memo shown to the payer
statusEnumCurrent session state
livemodeBooleanWhether the session was created with a live key
client_secretStringEmbedded checkout token
success_urlStringMerchant redirect on success
cancel_urlStringMerchant redirect on cancel
metadataObject | nullCustom metadata from creation
expires_atISO 8601Absolute expiration timestamp
created_atISO 8601Session creation timestamp

Session Status Values

StatusDescription
PENDINGSession active, awaiting customer payment
COMPLETEDCustomer completed payment successfully
EXPIREDSession expired (30-minute window elapsed)

cURL Example

curl -X GET https://api.payparse.ca/v1/checkout/sessions/cuid_generated_session_id \
-H "Authorization: Bearer pp_live_your_secret_key" \
-H "Content-Type: application/json"

3. List Transactions

GET /v1/payments

Returns a filtered list of payment transactions. Use this to query the transactional ledger.

Required Headers

HeaderTypeRequiredDescription
AuthorizationStringYesBearer pp_live_* or Bearer pp_rk_*
Content-TypeStringYesapplication/json

Required Scopes

payments.read

Query Parameters

ParameterTypeRequiredDefaultMaxDescription
referenceStringNoPartial match against interac_ref, payment comment, or checkout session reference
statusStringNoFilter by payment status (see enum values below)
limitIntegerNo1050Maximum number of results to return (values outside 1–50 → 400)

Results are scoped to the authenticated merchant and the API key’s livemode.

Status Filter Values

ValueDescription
PENDINGPayment received, awaiting confirmation
CONFIRMEDPayment verified and confirmed
FAILEDPayment failed or rejected
REFUNDEDPayment refunded to sender
REQUIRES_MANUAL_REVIEWAuto-verification failed — requires admin review

Response Codes

CodeMeaningBody
200SuccessArray of Transaction objects
400Bad request{ "error": "Invalid query parameters" }
401Unauthorized{ "error": "Invalid or missing API key" }
403Forbidden (scope){ "error": "Insufficient scope: payments.read required" }

Response Body (200 OK)

[
{
"id": "cuid_transaction_id",
"interac_ref": "PP-A1B2C3",
"amount": 25000,
"sender_name": "Jane Smith",
"sender_email": "[email protected]",
"comment": "Invoice INV-2026-0847",
"status": "CONFIRMED",
"verification_method": "AUTO_EMAIL",
"created_at": "2026-07-15T17:15:00.000Z"
}
]

Field Descriptions

FieldTypeDescription
idStringUnique transaction identifier
interac_refStringReference code parsed from the Interac e-Transfer payload (e.g., PP-A1B2C3)
amountIntegerTransaction amount in CAD cents
sender_nameStringName of the person who sent the e-Transfer
sender_emailString | nullSender email address (if available)
commentString | nullPayment comment/message from the Interac transfer
statusEnumCurrent payment status
verification_methodEnumHow the payment was verified
created_atISO 8601Transaction creation timestamp

Verification Method Values

MethodDescription
AUTO_EMAILAutomatically confirmed via email parsing and comment matching
MANUAL_ADMINManually verified by a merchant administrator
VO_PAYVerified via VoPay PSP integration (future)

cURL Examples

List all transactions:

curl -X GET "https://api.payparse.ca/v1/payments?limit=20" \
-H "Authorization: Bearer pp_live_your_secret_key" \
-H "Content-Type: application/json"

Filter by status:

curl -X GET "https://api.payparse.ca/v1/payments?status=REQUIRES_MANUAL_REVIEW&limit=50" \
-H "Authorization: Bearer pp_live_your_secret_key" \
-H "Content-Type: application/json"

Filter by reference:

curl -X GET "https://api.payparse.ca/v1/payments?reference=INV-2026-0847" \
-H "Authorization: Bearer pp_live_your_secret_key" \
-H "Content-Type: application/json"

Node.js Example

const params = new URLSearchParams({
status: 'PENDING',
limit: '25',
});

const response = await fetch(`https://api.payparse.ca/v1/payments?${params}`, {
headers: {
'Authorization': 'Bearer pp_live_your_secret_key',
},
});

const transactions = await response.json();
// transactions[].interac_ref, transactions[].status, etc.

4. List Events

GET /v1/events

Returns immutable platform events for the authenticated merchant (same livemode as the API key). Delivery attempts are available on the detail endpoint.

Required Scopes

events.read

Query Parameters

ParameterTypeRequiredDefaultMaxDescription
typeStringNoFilter by event type (e.g. payment.confirmed)
limitIntegerNo1050Maximum number of results (1–50)

Response Body (200 OK)

[
{
"id": "evt_unique_event_id",
"type": "payment.confirmed",
"livemode": true,
"data": {
"reference": "INV-2026-0847",
"amount": 25000,
"status": "CONFIRMED"
},
"created_at": "2026-07-15T17:15:00.000Z"
}
]

5. Retrieve Event

GET /v1/events/:id

Returns one event plus webhook delivery attempts (status, HTTP code, latency, errors). Events are insert-only — there is no update or delete API.

Required Scopes

events.read

Response Body (200 OK)

{
"id": "evt_unique_event_id",
"type": "payment.confirmed",
"livemode": true,
"data": {
"reference": "INV-2026-0847",
"amount": 25000,
"status": "CONFIRMED"
},
"created_at": "2026-07-15T17:15:00.000Z",
"deliveries": [
{
"webhook_id": "wh_…",
"url": "https://example.com/hooks",
"delivery_status": "SUCCESS",
"http_status": 200,
"attempt": 1,
"retry_count": 0,
"latency_ms": 120,
"error_message": null
}
]
}

6. Sandbox Simulate Payment

POST /v1/sandbox/simulate-payment

Simulates Interac outcomes for test-mode checkout sessions only. Requires a test secret key (pp_live_test_*). Live keys receive 403. See Sandbox / test mode.

Required Scopes

checkout.write

Request Body

FieldTypeRequiredDescription
sessionIdStringOne of sessionId / referenceTest checkout session id
referenceStringOne of sessionId / referenceCase-insensitive checkout reference
outcomeStringYesconfirmed, failed, or requires_manual_review

Ownership, expiry, and terminal-state checks apply. Simulations always enqueue webhooks with livemode: false.


Refunds (dashboard)

Completed Interac deposits are not reversed in place. Merchants request a full refund from the dashboard (/dashboard/transactions/:id). Admins approve, mark outbound Interac as sent, and complete with evidence.

StageNotes
REQUESTEDMerchant request; test-mode auto-approves
APPROVED / REJECTEDAdmin decision (live)
SENTOutbound Interac marked sent
COMPLETEDPayment status → REFUNDED; emits exactly one payment.refunded event
FAILED / CANCELLEDTerminal non-success

Live completion requires an outbound Interac reference and evidence note. Only one open or completed refund is allowed per payment. Idempotent completion retries do not re-emit payment.refunded.


Error Response Format

All error responses follow a consistent structure:

{
"error": "Human-readable error message describing the failure"
}

Common Error Codes

CodeDescription
400Request body validation failed — check field types and constraints
401API key is missing, expired, or invalid
403API key does not have the required scope for this endpoint
404Resource not found — verify the identifier
409Conflict — the reference already exists (idempotency violation)
429Rate limit exceeded — back off and retry after the Retry-After header
500Internal server error — contact [email protected] with the request ID

Rate Limits

API requests may be throttled under abuse. When rate limited, expect HTTP 429. Exact per-key quotas are configured at the edge; do not rely on fixed client-side QPS assumptions for correctness — use idempotency keys for writes.


Webhook Events

Outbound webhook payloads are delivered to your registered endpoints and signed with X-Payparse-Signature (HMAC-SHA256). See Webhook Integrations for verification examples.

Event Structure

{
"id": "evt_unique_event_id",
"type": "payment.confirmed",
"created_at": "2026-07-15T17:15:00.000Z",
"livemode": true,
"data": {
"reference": "INV-2026-0847",
"amount": 25000,
"status": "CONFIRMED",
"metadata": {}
}
}

Event Types

EventTrigger
checkout.session.completedCheckout session completed (confirmed payment)
payment.confirmedAuto-confirmed, sandbox-confirmed, or manually verified
payment.pending_reviewAuto-confirm failed — requires admin review
payment.failedPayment failed or sandbox failed outcome
payment.refundedFull refund completed (exactly once per completed refund)

Use GET /v1/events to inspect immutable events and delivery attempts. Dashboard merchants can also use Developers → Events.