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}profileYour verified profile. A family can start a page from it.
/w/{your-slug}/startstartThe start form with your business already chosen.
/v/{your-slug}/share-the-costfamily packageOne page in your name that explains sharing the cost. Link it in enquiry replies.
/c/{page-slug}pageA 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 givingcname.vercel-dns.comPoints your address at VeriGiving.
TXT _verigiving.givingthe token shown in your dashboardProves 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_referencestring or nullYour own id for this client, from your CRM or case system. Returned on the page and in every webhook about it.
statusstringcollecting, settled (the invoice is fully paid, set automatically), or closed (you stopped contributions).
visibilitystringlink_only (default, shared by link) or public (also listed on VeriGiving and your profile).
remainingnumberWhat is still needed. Contributions can never exceed it.
own_domain_urlstring or nullThe same page on your own domain, when you have connected one.
qr_urlstringA PNG QR code that opens the page. Print it or place it in a service folder.
testbooleantrue 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.

titlestring, requiredWhat contributors see first. For example: In memory of Arun Sharma.
family_namestring, requiredWho the page is for.
amountnumber, requiredThe invoice total, from 100 to 500000.
family_emailstringWhere to send the link. Omit it to share the link yourself.
notify_familybooleanDefaults to true. Send false to create the page without emailing the family. Test keys never email.
storystringA few words for the page. Up to 5,000 characters.
referencestringYour file or invoice number. Up to 80 characters.
client_referencestringThe 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.
visibilitystringlink_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_totalnumberRevise 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_refundsbooleanRequired when invoice_total is below what has been collected.
notestringWhy the invoice changed, shown in the revision history. Up to 200 characters.
statusstringclosed 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.
visibilitystringlink_only or public.
title, story, family_emailstringEdit the text or the family's address.
client_referencestringAttach 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.succeededA contribution was paid. Carries the amount, the name given, the note, and the page's new totals.
contribution.refundedA contribution was refunded in full or in part. Carries the amount refunded and what is now remaining.
page.settledThe invoice is fully paid.
page.closedYou or the family stopped contributions.
page.reopenedContributions 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_requestSomething in the request is missing or out of range.
401 authentication_errorThe key is missing, wrong, or revoked.
404 not_foundNo page with that id belongs to your business.
409 invalid_stateThe page is settled, so it cannot be revised, closed, or reopened.
429 rate_limit_errorMore than 120 requests in a minute on one key. Wait for the number of seconds in the Retry-After header.
500 api_errorOur 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.