For developers
Build with VeriGiving
Technical documentation for businesses. VeriGiving is infrastructure as much as it is a website: links and QR codes you can place anywhere, a button for your site, your own domain, and a REST API that lets your software start and manage pages. Payments, receipts, verification, and compliance run behind all of it.
Four ways to integrate
From no code at all to a full integration. Each one builds on the one before, and all of them end with the invoice paid directly into your own account.
1. Links and QR codes, no code
Every verified business has stable addresses it can put anywhere: an email, an invoice, a printed card.
| /v/{your-slug} | profile | Your verified profile. A family can start a page from it. |
| /w/{your-slug}/start | start | The start form with your business already chosen. |
| /v/{your-slug}/share-the-cost | family package | One page in your name that explains sharing the cost. Link it in enquiry replies. |
| /c/{page-slug} | page | A family's page. This is the link they share. |
Any of those can be turned into a QR code: GET /api/qr?u={address}&s={size} returns a PNG, from 120 to 1200 pixels, and &download=1 downloads it. Only VeriGiving addresses can be encoded. Your kit has the code and a print ready counter card already made.
2. A button on your website
Paste one line of HTML where families will see it. Your kit has it filled in with your own addresses.
<a href="https://verigiving.com/v/your-slug/share-the-cost"
style="display:inline-block;background:#2E7D5B;color:#fff;font-weight:600;
padding:12px 22px;border-radius:999px;text-decoration:none">
Share the cost with family and friends
</a>3. Your own domain
Host the whole experience at an address you own, such as giving.yourbusiness.ca, with your logo and colours. Families never leave your site. In your dashboard under Your domain, enter the address, add two DNS records, and press Verify. The certificate is issued automatically.
| CNAME giving | cname.vercel-dns.com | Points your address at VeriGiving. |
| TXT _verigiving.giving | the token shown in your dashboard | Proves the domain is yours. |
Once verified, / is your branded home, /start starts a page, /share-the-cost is your family package, and /c/{page-slug} is each family's page.
4. The API
For your own software. Start a page the moment a file is opened in your case management system, show live totals on your own screens, revise an invoice, close a page. The reference follows.
API basics and authentication
The base address is https://verigiving.com/api/v1. Requests and responses are JSON. Amounts are Canadian dollars as numbers (8500 or 8500.50). Times are ISO 8601 in UTC. Identifiers are UUIDs.
Create a key in your dashboard under API and send it as a bearer token. A key acts as your business, so keep it on your server. It is shown once, stored only as a hash, and can be revoked at any time.
curl https://verigiving.com/api/v1/business \
-H "Authorization: Bearer vg_sk_your_key"There are two kinds of key. A test key (vg_test_...) makes pages marked "test": true: nobody is emailed and no money can be taken, so it is the safe way to build and rehearse an integration. A live key (vg_sk_...) makes real pages. The requests and responses are identical.
A machine readable description is at /developers/openapi.json (OpenAPI 3.1), which Postman and most code generators can import.
When you create a page, send an Idempotency-Key header with a value that is unique to that file in your system. If the same request is retried, you get the page that was made the first time instead of a second page and a second email to the family.
The page object
A page is one family, one invoice, one link. Every endpoint that returns a page returns this shape.
{
"id": "5b0c2a9e-3f1d-4c57-9a55-0d0a3b1f6c21",
"object": "page",
"slug": "in-memory-of-arun-sharma",
"title": "In memory of Arun Sharma",
"family_name": "The Sharma family",
"family_email": "priya@example.com",
"client_reference": "CRM-48213",
"story": null,
"status": "collecting",
"visibility": "link_only",
"created_via": "api",
"invoice": {
"id": "0f6d7c1e-8a52-4b0c-b1d2-7e9c4a3f2b10",
"total": 8500,
"currency": "CAD",
"reference": "File 2026-0412",
"document_url": null,
"confirmed_at": "2026-10-01T15:04:11.000Z"
},
"contributed_total": 1250,
"remaining": 7250,
"contributor_count": 9,
"url": "https://verigiving.com/c/in-memory-of-arun-sharma",
"own_domain_url": "https://giving.yourbusiness.ca/c/in-memory-of-arun-sharma",
"qr_url": "https://verigiving.com/api/qr?u=...",
"test": true,
"created_at": "2026-10-01T15:04:11.000Z",
"updated_at": "2026-10-01T15:04:11.000Z"
}| client_reference | string or null | Your own id for this client, from your CRM or case system. Returned on the page and in every webhook about it. |
| status | string | collecting, settled (the invoice is fully paid, set automatically), or closed (you stopped contributions). |
| visibility | string | link_only (default, shared by link) or public (also listed on VeriGiving and your profile). |
| remaining | number | What is still needed. Contributions can never exceed it. |
| own_domain_url | string or null | The same page on your own domain, when you have connected one. |
| qr_url | string | A PNG QR code that opens the page. Print it or place it in a service folder. |
| test | boolean | true while the page is in the test environment and no real payment can be taken. |
POST/pages
Start a page for a family. Because you supply the invoice amount, the invoice is confirmed on creation and contributions open immediately. If you include the family's email, they receive the link.
| title | string, required | What contributors see first. For example: In memory of Arun Sharma. |
| family_name | string, required | Who the page is for. |
| amount | number, required | The invoice total, from 100 to 500000. |
| family_email | string | Where to send the link. Omit it to share the link yourself. |
| notify_family | boolean | Defaults to true. Send false to create the page without emailing the family. Test keys never email. |
| story | string | A few words for the page. Up to 5,000 characters. |
| reference | string | Your file or invoice number. Up to 80 characters. |
| client_reference | string | The id of this client in your CRM or case system. Up to 120 characters. Use it to find the client's pages later and to match webhooks to your records. |
| visibility | string | link_only (default) or public. |
curl https://verigiving.com/api/v1/pages \
-H "Authorization: Bearer vg_sk_your_key" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: file-2026-0412" \
-d '{
"title": "In memory of Arun Sharma",
"family_name": "The Sharma family",
"family_email": "priya@example.com",
"amount": 8500,
"reference": "File 2026-0412",
"client_reference": "CRM-48213"
}'Returns 201 with the page, or 200 with the original page when the idempotency key was seen before.
GET/pages
Your pages, newest first. Filter with status, client_reference (every page for one client in your CRM), or reference (your invoice number). Page with limit (1 to 100, default 25) and starting_after (the id of the last page you received).
curl "https://verigiving.com/api/v1/pages?status=collecting&limit=50" \
-H "Authorization: Bearer vg_sk_your_key"
# Everything for one client in your CRM
curl "https://verigiving.com/api/v1/pages?client_reference=CRM-48213" \
-H "Authorization: Bearer vg_sk_your_key"
{ "object": "list", "data": [ { "id": "...", "object": "page", ... } ], "has_more": false }GET/pages/:id
One page with live totals. Use webhooks to be told when it changes, or poll; once a minute is plenty.
curl https://verigiving.com/api/v1/pages/5b0c2a9e-3f1d-4c57-9a55-0d0a3b1f6c21 \
-H "Authorization: Bearer vg_sk_your_key"PATCH/pages/:id
Send only what changes.
| invoice_total | number | Revise the invoice. Going below what contributors have paid returns the difference to them, each the same share, and settles the page; send confirm_refunds: true with it, or the request answers 409. Every revision is recorded and shown on the page. |
| confirm_refunds | boolean | Required when invoice_total is below what has been collected. |
| note | string | Why the invoice changed, shown in the revision history. Up to 200 characters. |
| status | string | closed stops contributions. collecting reopens a closed page. cancelled means the service is not going ahead: every contribution is returned to its card and the page closes. Settled pages are final. |
| visibility | string | link_only or public. |
| title, story, family_email | string | Edit the text or the family's address. |
| client_reference | string | Attach or change your own client id, for example on a page a family started themselves. |
curl -X PATCH https://verigiving.com/api/v1/pages/5b0c2a9e-3f1d-4c57-9a55-0d0a3b1f6c21 \
-H "Authorization: Bearer vg_sk_your_key" \
-H "Content-Type: application/json" \
-d '{ "invoice_total": 9100, "note": "Added reception catering" }'GET/pages/:id/contributions
Contributions to a page, newest first: amount, the name the contributor gave, their note, and the time. Email addresses are not included. Use limit up to 100.
{ "object": "list",
"data": [ { "id": "...", "object": "contribution", "amount": 100, "currency": "CAD",
"contributor_name": "Meera K.", "note": "With love", "status": "succeeded",
"created_at": "2026-10-02T13:20:05.000Z" } ],
"has_more": false }GET/business
The business the key belongs to: whether payments are enabled, your fee, and the links you hand to families (profile, start page, family package, QR code). The quickest way to check a key works.
Webhooks
Register up to three HTTPS addresses in your dashboard under API and VeriGiving will POST a signed JSON event to each one as things happen. Answer with any 2xx status within six seconds. Failed deliveries are retried daily, six times in all, and the dashboard shows the result of each.
Every event about a page carries your own client_reference and invoice reference, so your CRM can update the right client record without another request.
| contribution.succeeded | A contribution was paid. Carries the amount, the name given, the note, and the page's new totals. | |
| contribution.refunded | A contribution was refunded in full or in part. Carries the amount refunded and what is now remaining. | |
| page.settled | The invoice is fully paid. | |
| page.closed | You or the family stopped contributions. | |
| page.reopened | Contributions resumed, or a refund or dispute reopened a settled page. |
POST https://yoursystem.ca/verigiving-events
VeriGiving-Signature: t=1790900000,v1=5f2b...e91a
{ "id": "evt_9c1f...", "type": "page.settled", "created_at": "2026-10-04T18:22:10.000Z",
"data": { "page_id": "5b0c2a9e-...", "client_reference": "CRM-48213", "reference": "File 2026-0412",
"contributed_total": 8500, "contributor_count": 31, "test": false } }Verify every event. The signature is an HMAC SHA256 of the timestamp, a dot, and the raw request body, using the signing secret shown once when you added the endpoint. Reject anything older than five minutes.
const crypto = require("crypto");
function verify(rawBody, header, secret) {
const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const expected = crypto.createHmac("sha256", secret).update(t + "." + rawBody).digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}Errors and rate limits
Errors use the HTTP status and one JSON shape. param names the field at fault when there is one.
{ "error": { "type": "invalid_request", "message": "The invoice amount must be between $100 and $500,000.", "param": "amount" } }| 400 invalid_request | Something in the request is missing or out of range. | |
| 401 authentication_error | The key is missing, wrong, or revoked. | |
| 404 not_found | No page with that id belongs to your business. | |
| 409 invalid_state | The page is settled, so it cannot be revised, closed, or reopened. | |
| 429 rate_limit_error | More than 120 requests in a minute on one key. Wait for the number of seconds in the Retry-After header. | |
| 500 api_error | Our side. Retry with the same idempotency key. |
Rules the API will not bend
- Every page pays your own connected payment account. There is no field for another recipient, and there never will be.
- Collection stops at the invoice total. The last contribution can only be as large as what remains.
- Contributions of $1,000 or more include an identity check required by Canadian law, done on the page before payment. Nothing changes for you.
- Contributors are never charged a fee and are never asked for a tip.
- Keys are for your server. A key found in a public web page or repository will be revoked.
Questions and requests: support@verigiving.com.