REST API · Guide

Wallet & billing

Labels and pickups are paid from a prepaid wallet. Top it up from a saved card, and the wallet is charged the moment you buy. All amounts are integer cents.

Balance and history

curl -s https://api.parcelhub.ca/v1/wallet -H "Authorization: Bearer $TOKEN"
curl -s "https://api.parcelhub.ca/v1/wallet/transactions?type=top_up&limit=20" -H "Authorization: Bearer $TOKEN"

type is top_up, payment (labels, pickups, invoices), refund or adjustment (credits and corrections). Each one's detail is at GET /v1/wallet/transactions/{id}.

Top up from a saved card

A top-up charges a card already saved on the account, in two calls. GET /v1/wallet/topup-bonuses gives the minimum, the maximum balance and any bonus the account can get.

# The saved cards (never full numbers)
curl -s https://api.parcelhub.ca/v1/wallet/cards -H "Authorization: Bearer $TOKEN"

# 1. Charge one: payment_method_id is the card's stripe_payment_method_id (pm_…)
curl -s https://api.parcelhub.ca/v1/wallet/top-up -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d '{"amount_cents": 10000, "payment_method_id": "pm_…"}'
# → data.transaction_id

# 2. Confirm it: checks the payment and credits the wallet (and any bonus)
curl -s -X POST https://api.parcelhub.ca/v1/wallet/top-up/$TRANSACTION_ID/confirm -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d '{}'
The card is charged at step 1. Ask before topping up for someone, and don't retry step 1 if a response is lost: check GET /v1/wallet/transactions?type=top_up first. Step 2 is safe to repeat.
  • If the bank wants extra verification (3-D Secure), step 2 fails with a message containing requires_action. Only the cardholder can finish it, at my.parcelhub.ca/wallet/top-up.
  • Adding a card is never done through the API: the cardholder adds it on Stripe's secure form at my.parcelhub.ca/wallet/add-card. Over the API you can choose the default (POST /v1/wallet/cards/{id}/default) and remove one (DELETE /v1/wallet/cards/{id}), using the card's id.

Invoices and receipts

When a carrier bills more than the label price (for example the parcel weighed more than declared, or was bigger), ParcelHub sends an invoice for the difference. Unpaid invoices can be paid from the wallet. Everything that was paid straight away (top-ups, labels, refunds) has a receipt instead.

# Charges billed after the fact (e.g. a carrier's weight adjustment)
curl -s https://api.parcelhub.ca/v1/invoices -H "Authorization: Bearer $TOKEN"
curl -s https://api.parcelhub.ca/v1/wallet/unpaid -H "Authorization: Bearer $TOKEN"          # total owed
curl -s -X POST https://api.parcelhub.ca/v1/invoices/$ID/pay -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d '{}'   # pay from the wallet
curl -s https://api.parcelhub.ca/v1/invoices/$ID/pdf -H "Authorization: Bearer $TOKEN"       # PDF link

# Receipts: settled top-ups, label purchases and refunds
curl -s https://api.parcelhub.ca/v1/receipts -H "Authorization: Bearer $TOKEN"

Paying returns 409 with insufficient_funds when the wallet doesn't cover the invoice: top up first. Accurate weights and sizes on the label are the best way to avoid adjustments.

Refunds of unused funds

Unused money from a past top-up can be refunded to the card that paid for it, and only to that card. ParcelHub staff review each request. Voided labels and cancelled pickups are refunded to the wallet automatically; they don't need a request.

curl -s https://api.parcelhub.ca/v1/wallet/refunds/$TOP_UP_TRANSACTION_ID -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d '{"reason":"Closing the account"}'
curl -s https://api.parcelhub.ca/v1/wallet/refunds -H "Authorization: Bearer $TOKEN"