Introduction
Recommended Integration Model
For manual eTransfer payments, your merchant website can use either:
- Webhooks — recommended
- Polling — fallback option
Webhooks are better because your system is notified when InvinciblePay has an update, instead of repeatedly checking for pending eTransfers.
Manual eTransfer Payment Flow with Webhooks
- Customer starts checkout on your website.
- Your backend creates an internal order.
- Your website shows the customer manual eTransfer instructions.
- Customer sends an Interac e-Transfer to your InvinciblePay receiving email.
- InvinciblePay detects the incoming manual eTransfer.
- InvinciblePay sends a webhook to your server.
- Your backend uses the webhook data to find the matching order.
- Your backend calls the manual eTransfer claim endpoint with the security answer.
- If the claim succeeds, your backend marks the order as paid.
Step 1: Register Your Webhook URL
Register a URL to receive webhook notifications:
POST /v1/webhook-urlsExample body:
{
"url": "https://myfencestore.com/api/invinciblepay/webhook"
}You can also list your registered webhook URLs:
GET /v1/webhook-urlsAnd manage an existing webhook URL:
PUT /v1/webhook-urls/{uuid}
DELETE /v1/webhook-urls/{uuid}The API also exposes a webhook history/list endpoint at /v1/webhooks.
Step 2: Get Your Manual eTransfer Receiving Email
GET /v1/manual-etransfers/addressThis returns the email address customers should send eTransfers to — the manual eTransfer receiving address that can be shared to receive eTransfers that must later be accepted manually.
Step 3: Show Payment Instructions to the Customer
Example:
Send an Interac e-Transfer for exactly $125.00 CAD to:
merchant123@cadpayment.ca
Security question:
What is the Payment ID for your ORD-10045 order?
Security answer:
PID-000985Important: send the exact amount.
Store this in your order:
order_id
expected_amount
security_answer
payment_status = pending
manual_etransfer_id = null
interac_reference_number = nullStep 4: Receive Webhook on Your Website
Your webhook endpoint should be:
POST /api/invinciblepay/webhookExample backend logic:
- Receive the webhook.
- Store the raw webhook body.
- If the webhook was already processed, return
200. - Identify the manual eTransfer id or related transaction id.
- Fetch the latest manual eTransfer data from InvinciblePay.
- Match it to your order.
- If matched, claim the manual eTransfer.
- If the claim succeeds, mark the order as paid.
- Return
200.
Do not rely only on the webhook body to mark an order paid. Use the webhook as a notification, then fetch/confirm the latest state from the API.
Step 5: Claim the Manual eTransfer
POST /v1/manual-etransfers/{id}/claimBody:
{
"securityAnswer": "ORD-10045"
}The claim endpoint requires a security answer. The transaction appears in the transaction list shortly after claiming.
After success:
payment_status = paid
manual_etransfer_id = met_123
paid_at = now()Polling Fallback
Even with webhooks, run a backup polling job every few minutes:
GET /v1/manual-etransfers?status=pending&pageSize=20&page=0&sort=descUse this to catch missed webhook deliveries.
Important Rules
- Never expose your InvinciblePay API key in frontend code.
- Always process webhooks on your backend.
- Always make webhook handling idempotent.
- Store the raw webhook payload for debugging.
- Return HTTP 200 only after your server accepts the webhook.
- Use exact amount matching.
- Do not mark the order paid just because a webhook arrived.
- Mark the order paid only after successful claim or confirmed completed status.
- Use polling as a backup safety net.