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
referenceStringNo——Partial match against interac_ref, payment comment, or checkout session reference
statusStringNo——Filter 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
typeStringNo——Filter 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.