Donorbox - nself-org/plugins GitHub Wiki
Complete Donorbox donation data integration for nself. Syncs campaigns, donors, donations, recurring plans, events, and tickets to PostgreSQL with webhook support and cross-plugin references to Stripe and PayPal.
- Overview
- Quick Start
- Configuration
- CLI Commands
- REST API
- Webhook Events
- Database Schema
- Analytics Views
- Cross-Plugin Integration
- Troubleshooting
The Donorbox plugin provides complete synchronization of your Donorbox account data to a local PostgreSQL database. It supports:
- 7 Database Tables - Campaigns, donors, donations, plans, events, tickets, webhook events
-
1 Webhook Event -
donation.createdwith HMAC-SHA256 verification - 5 Analytics Views - Pre-built SQL views for fundraising metrics
- Full REST API - Query synced data via HTTP endpoints
- CLI Interface - Manage everything from the command line
- Multi-Account Support - Sync multiple Donorbox accounts into one database
-
Cross-Plugin References -
np_stripe_charge_idandnp_paypal_transaction_idon donations
| Resource | Description | Table |
|---|---|---|
| Campaigns | Fundraising campaigns | np_donorbox_campaigns |
| Donors | Donor profiles | np_donorbox_donors |
| Donations | Individual donations | np_donorbox_donations |
| Plans | Recurring donation plans | np_donorbox_plans |
| Events | Donorbox events | np_donorbox_events |
| Tickets | Event tickets | np_donorbox_tickets |
| Webhook Events | Raw event log | np_donorbox_webhook_events |
# Install the plugin
nself plugin install donorbox
# Configure environment
echo "[email protected]" >> .env
echo "DONORBOX_API_KEY=your_api_key" >> .env
echo "DATABASE_URL=postgresql://user:pass@localhost:5432/nself" >> .env
# Sync all data
nself plugin donorbox sync
# Start webhook server
nself plugin donorbox server --port 3005| Variable | Required | Default | Description |
|---|---|---|---|
DATABASE_URL |
Yes | - | PostgreSQL connection string |
DONORBOX_EMAIL |
Yes* | - | Donorbox account email |
DONORBOX_API_KEY |
Yes* | - | Donorbox API key |
DONORBOX_EMAILS |
No | - | Comma-separated emails for multi-account sync |
DONORBOX_API_KEYS |
No | - | Comma-separated API keys matching DONORBOX_EMAILS
|
DONORBOX_ACCOUNT_LABELS |
No | - | Comma-separated labels matching DONORBOX_EMAILS
|
DONORBOX_WEBHOOK_SECRET |
No | - | Webhook HMAC-SHA256 signing secret |
DONORBOX_WEBHOOK_SECRETS |
No | - | Comma-separated secrets for multi-account |
DONORBOX_SYNC_INTERVAL |
No | 3600 |
Sync interval in seconds |
PORT |
No | 3005 |
HTTP server port |
LOG_LEVEL |
No | info |
Logging level (debug, info, warn, error) |
* DONORBOX_EMAIL and DONORBOX_API_KEY are required when DONORBOX_EMAILS is not set.
- Log in to Donorbox
- Go to Account Settings > API & Webhooks
- Copy your API key
- The API uses Basic HTTP auth (
email:api_key)
Donorbox limits API requests to 60 per minute. The plugin enforces a 1 request/second rate limit to stay within this budget.
# Database
DATABASE_URL=postgresql://nself:password@localhost:5432/nself
# Donorbox API
[email protected]
DONORBOX_API_KEY=abc123def456...
DONORBOX_WEBHOOK_SECRET=whsec_xyz789...
# Server
PORT=3005
LOG_LEVEL=info[email protected],[email protected]
DONORBOX_API_KEYS=key_charity_a,key_charity_b
DONORBOX_ACCOUNT_LABELS=charity-a,charity-b
DONORBOX_WEBHOOK_SECRETS=secret_a,secret_bEach synced record stores its origin in source_account_id.
# Full sync (all resources)
nself plugin donorbox sync
# Incremental sync (only recent data)
nself plugin donorbox sync --incremental
# Sync specific account only
nself plugin donorbox sync --account charity-a# Re-sync recent data (default 7-day lookback)
nself plugin donorbox reconcile
# Custom lookback window
nself plugin donorbox reconcile --days 14
# Reconcile specific account
nself plugin donorbox reconcile --account charity-b# Start HTTP server
nself plugin donorbox server
# Start on custom port
nself plugin donorbox server --port 3005# Show sync status and statistics
nself plugin donorbox statushttp://localhost:3005
GET /health # Basic liveness check
GET /ready # Readiness check (verifies database)
GET /live # Liveness check with sync info
GET /status # Full status with account info and statsPOST /sync # Trigger full data sync
POST /reconcile # Reconcile recent dataBoth endpoints accept optional JSON body:
{
"accounts": ["charity-a"]
}POST /webhooks/donorbox # Donorbox webhook receiverDonorbox webhooks use HMAC-SHA256 signature verification via the Donorbox-Signature header.
GET /api/campaigns # List campaigns (limit, offset)
GET /api/donors # List donors (limit, offset)
GET /api/donations # List donations (limit, offset, status)
GET /api/plans # List recurring plans (limit, offset, status)
GET /api/stats # Aggregated statistics
GET /api/events # List webhook events (limit)Donorbox supports one webhook event:
Triggered when a new donation is made. The webhook payload is verified using HMAC-SHA256 with the Donorbox-Signature header.
| Field | Description |
|---|---|
id |
Donation ID |
amount |
Donation amount |
currency |
Currency code |
donor.email |
Donor email |
campaign.name |
Campaign name |
np_stripe_charge_id |
Associated Stripe charge (if applicable) |
np_paypal_transaction_id |
Associated PayPal transaction (if applicable) |
Action: Upserts the donation into np_donorbox_donations with cross-reference IDs.
- Go to Donorbox Account Settings > API & Webhooks
- Add your webhook URL:
https://your-domain.com/webhooks/donorbox - Copy the signing secret and set
DONORBOX_WEBHOOK_SECRET
All tables include source_account_id VARCHAR(128) NOT NULL DEFAULT 'primary' for multi-account support.
CREATE TABLE np_donorbox_campaigns (
id INTEGER NOT NULL,
source_account_id VARCHAR(128) NOT NULL DEFAULT 'primary',
name VARCHAR(255),
slug VARCHAR(255),
currency VARCHAR(10) DEFAULT 'USD',
goal_amount NUMERIC(20, 2),
total_raised NUMERIC(20, 2) DEFAULT 0,
donations_count INTEGER DEFAULT 0,
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMP WITH TIME ZONE,
updated_at TIMESTAMP WITH TIME ZONE,
synced_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
PRIMARY KEY (id, source_account_id)
);CREATE TABLE np_donorbox_donors (
id INTEGER NOT NULL,
source_account_id VARCHAR(128) NOT NULL DEFAULT 'primary',
first_name VARCHAR(255),
last_name VARCHAR(255),
email VARCHAR(255),
phone VARCHAR(50),
address TEXT,
city VARCHAR(255),
state VARCHAR(100),
zip_code VARCHAR(20),
country VARCHAR(100),
employer VARCHAR(255),
donations_count INTEGER DEFAULT 0,
last_donation_at TIMESTAMP WITH TIME ZONE,
total NUMERIC(20, 2) DEFAULT 0,
created_at TIMESTAMP WITH TIME ZONE,
updated_at TIMESTAMP WITH TIME ZONE,
synced_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
PRIMARY KEY (id, source_account_id)
);CREATE TABLE np_donorbox_donations (
id INTEGER NOT NULL,
source_account_id VARCHAR(128) NOT NULL DEFAULT 'primary',
campaign_id INTEGER,
campaign_name VARCHAR(255),
donor_id INTEGER,
donor_email VARCHAR(255),
donor_name VARCHAR(255),
amount NUMERIC(20, 2) DEFAULT 0,
converted_amount NUMERIC(20, 2),
converted_net_amount NUMERIC(20, 2),
amount_refunded NUMERIC(20, 2) DEFAULT 0,
currency VARCHAR(10) DEFAULT 'USD',
donation_type VARCHAR(50),
donation_date TIMESTAMP WITH TIME ZONE,
processing_fee NUMERIC(20, 2),
status VARCHAR(50),
recurring BOOLEAN DEFAULT false,
comment TEXT,
designation VARCHAR(255),
np_stripe_charge_id VARCHAR(255), -- Cross-reference to np_stripe_charges.id
np_paypal_transaction_id VARCHAR(255), -- Cross-reference to np_paypal_transactions.id
questions JSONB DEFAULT '[]',
created_at TIMESTAMP WITH TIME ZONE,
updated_at TIMESTAMP WITH TIME ZONE,
synced_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
PRIMARY KEY (id, source_account_id)
);CREATE TABLE np_donorbox_plans (
id INTEGER NOT NULL,
source_account_id VARCHAR(128) NOT NULL DEFAULT 'primary',
campaign_id INTEGER,
campaign_name VARCHAR(255),
donor_id INTEGER,
donor_email VARCHAR(255),
type VARCHAR(50),
amount NUMERIC(20, 2) DEFAULT 0,
currency VARCHAR(10) DEFAULT 'USD',
status VARCHAR(50),
started_at TIMESTAMP WITH TIME ZONE,
last_donation_date TIMESTAMP WITH TIME ZONE,
next_donation_date TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE,
updated_at TIMESTAMP WITH TIME ZONE,
synced_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
PRIMARY KEY (id, source_account_id)
);CREATE TABLE np_donorbox_events (
id INTEGER NOT NULL,
source_account_id VARCHAR(128) NOT NULL DEFAULT 'primary',
name VARCHAR(255),
slug VARCHAR(255),
description TEXT,
start_date TIMESTAMP WITH TIME ZONE,
end_date TIMESTAMP WITH TIME ZONE,
timezone VARCHAR(50),
venue_name VARCHAR(255),
address TEXT,
city VARCHAR(255),
state VARCHAR(100),
country VARCHAR(100),
zip_code VARCHAR(20),
currency VARCHAR(10) DEFAULT 'USD',
tickets_count INTEGER DEFAULT 0,
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMP WITH TIME ZONE,
updated_at TIMESTAMP WITH TIME ZONE,
synced_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
PRIMARY KEY (id, source_account_id)
);CREATE TABLE np_donorbox_tickets (
id INTEGER NOT NULL,
source_account_id VARCHAR(128) NOT NULL DEFAULT 'primary',
event_id INTEGER,
event_name VARCHAR(255),
donor_id INTEGER,
donor_email VARCHAR(255),
ticket_type VARCHAR(100),
quantity INTEGER DEFAULT 0,
amount NUMERIC(20, 2) DEFAULT 0,
currency VARCHAR(10) DEFAULT 'USD',
status VARCHAR(50),
created_at TIMESTAMP WITH TIME ZONE,
updated_at TIMESTAMP WITH TIME ZONE,
synced_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
PRIMARY KEY (id, source_account_id)
);CREATE TABLE np_donorbox_webhook_events (
id VARCHAR(255) PRIMARY KEY,
event_type VARCHAR(255),
payload JSONB DEFAULT '{}',
source_account_id VARCHAR(128) NOT NULL DEFAULT 'primary',
processed BOOLEAN DEFAULT false,
processed_at TIMESTAMP WITH TIME ZONE,
error TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
synced_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);All donations with campaign and donor details, excluding refunded donations.
SELECT * FROM np_donorbox_unified_donations;
-- donation_id, source_account_id, campaign_id, campaign_name,
-- donor_id, donor_email, donor_name, amount, amount_refunded, net_amount,
-- currency, donation_type, donation_date, status, recurring,
-- np_stripe_charge_id, np_paypal_transaction_id, processing_feePer-campaign totals and donor counts.
SELECT * FROM np_donorbox_campaign_summary;
-- campaign_id, name, source_account_id, goal_amount, total_raised,
-- donations_count, is_active, currency, unique_donorsDaily donation aggregation.
SELECT * FROM np_donorbox_daily_donations;
-- source_account_id, donation_day, currency, donation_count,
-- total_amount, net_amountRecurring plan statistics.
SELECT * FROM np_donorbox_recurring_summary;
-- source_account_id, status, currency, plan_count, total_recurring_amountRanked donors by total giving.
SELECT * FROM np_donorbox_top_donors;
-- donor_id, source_account_id, email, name, total,
-- donations_count, last_donation_atDonorbox stores the underlying payment processor IDs on each donation, enabling joins across all three plugins (Stripe, PayPal, Donorbox).
SELECT
dd.donor_name,
dd.amount AS np_donorbox_amount,
sc.amount / 100.0 AS np_stripe_amount,
sc.status AS np_stripe_status,
sc.payment_method_details
FROM np_donorbox_donations dd
JOIN np_stripe_charges sc ON dd.np_stripe_charge_id = sc.id
WHERE dd.np_stripe_charge_id IS NOT NULL;SELECT
dd.donor_name,
dd.amount AS np_donorbox_amount,
pt.amount AS np_paypal_amount,
pt.fee_amount AS np_paypal_fee
FROM np_donorbox_donations dd
JOIN np_paypal_transactions pt ON dd.np_paypal_transaction_id = pt.id
WHERE dd.np_paypal_transaction_id IS NOT NULL;-- Total giving across all three platforms
SELECT 'stripe' AS source, SUM(amount / 100.0) AS total
FROM np_stripe_charges WHERE status = 'succeeded'
UNION ALL
SELECT 'paypal', SUM(amount)
FROM np_paypal_transactions WHERE status = 'S' AND amount > 0
UNION ALL
SELECT 'donorbox', SUM(amount)
FROM np_donorbox_donations WHERE status != 'refunded';Verify your DONORBOX_EMAIL and DONORBOX_API_KEY are correct. The API uses Basic HTTP auth with email:api_key.
Donorbox's API rate limit is 60 requests/minute (1/sec). A full sync of large accounts will take time. The plugin respects this limit automatically.
Ensure DONORBOX_WEBHOOK_SECRET matches the secret configured in your Donorbox webhook settings. The plugin uses HMAC-SHA256 verification.
np_stripe_charge_id and np_paypal_transaction_id are only populated when Donorbox includes them in the API response. These depend on the payment method the donor used.
LOG_LEVEL=debug nself plugin donorbox syncLast Updated: February 10, 2026 Plugin Version: 1.0.0 nself Version: 0.4.8+