Campaign Sales API
The Campaign Sales API is for orders your campaign took somewhere other than Argenta — a partner's storefront, a phone bank, a chapter's own spreadsheet. Record them here and they land in your campaign exactly like a hand-keyed sale, so the campaign's takings are the real number. You can also read your sales history and list the items a campaign is selling. It shares everything with the Constituents API, the Volunteerism API, the Donations API and the Events API — the same API keys, the same base URL, the same error shape.
Authentication
Use the same key you use for the other APIs (Subscription Settings → API Keys, team admins only), sent as a bearer token on every request:
Authorization: Bearer argenta_sk_...
The base URL is https://app.argentasoftware.com/api/v1. All requests and responses are JSON.
pkSale, the deductible leg is donationTotal. The field names written
throughout this guide are the Argenta column names, which is what you send. When you send a
request, either casing works: FkCampaign and fkCampaign are both
accepted, so you can build a request out of fields you read back from us.
Endpoints
| Method & path | What it does |
|---|---|
POST /campaign-sales | Record a sale that was paid outside Argenta. Needs the campaign, the purchaser and at least one item. |
GET /campaign-sales/{id} | Fetch one sale with its item lines and both money legs. |
GET /campaign-sales?search=...&startDate=...&endDate=... | Search your sales, newest purchase date first. Paged, max page size 100. |
GET /campaign-sales?constituentId=...&isPaidInFull=... | Filter to one purchaser, or to sales that are or are not settled. |
GET /campaign-sale-items?campaignId=... | The items a campaign is selling, with prices, the tax-deductible split and remaining stock. |
GET /campaign-sale-items/{id} | Fetch one sale item. |
Record a sale
You send the campaign, who bought, and what they bought. You do not send prices. Every price and tax-deductible amount is read from that campaign's own item catalogue at the moment the sale is recorded, so a sale can never be booked at a price you did not set in Argenta.
curl -X POST "https://app.argentasoftware.com/api/v1/campaign-sales" \
-H "Authorization: Bearer argenta_sk_..." \
-H "Content-Type: application/json" \
-d '{
"FkCampaign": 5522,
"FkConstituent": 240188,
"PurchaseDate": "2026-09-12",
"Items": [
{ "FkItem": 411, "ItemQTY": 2 },
{ "FkItem": 415, "ItemQTY": 1 }
]
}'
FkConstituent must be someone already in your account. If the buyer is new, create them
first with the Constituents API and use the id it returns.
PurchaseDate is optional and defaults to today.
The response is the created sale, including its item lines and its id, so you can store the id against the order in your own system.
The two money legs
Every sale carries its money as two separate figures, and reading only one of them will give you a wrong total:
| Field | What it is |
|---|---|
DonationTotal | The tax-deductible portion, added up from the items' tax-deductible amounts. |
PaymentTotal | The rest — what the buyer paid for goods received. |
TotalAmountPaid | The two together: the full amount owed on the sale. |
If an item's tax-deductible amount is set higher than its price, the deductible portion is capped at the amount actually owed and we raise it internally so your team can correct the item. The sale still records correctly; the cap can only ever under-claim a deduction, never over-claim one.
Reading the item catalogue
curl "https://app.argentasoftware.com/api/v1/campaign-sale-items?campaignId=5522" \
-H "Authorization: Bearer argenta_sk_..."
Each item carries its name, description, price, tax-deductible amount, sales window and — where the item has limited stock — how many exist and how many have sold. Read this before recording a sale so you are sending item ids that campaign actually offers.
Stock and quantity limits
An item marked limited-availability will refuse a sale that would oversell it, and the refusal happens before anything is written, so a rejected request never leaves a partial sale behind. There is also a ceiling of 999 on any one line and 999 items on an order in total — the same limits the public sales form enforces.
Errors
Same shape as the other APIs: an HTTP status plus a JSON body with a machine code and a human message.
| Status | Code | When |
|---|---|---|
| 400 | missing_field / invalid_field | The body failed validation — an unknown item, a quantity below 1, a purchaser not in your account. Nothing was written. |
| 400 | invalid_request | The sale was refused as a whole: not enough stock left, or over a quantity ceiling. |
| 401 | unauthorized | Missing, malformed, revoked, or unknown key. |
| 403 | insufficient_scope | A read-only key tried to write. |
| 404 | not_found | No sale, item or campaign with that id in your account. |
| 413 | payload_too_large | Body over 64 KB. |
| 429 | rate_limited | Slow down and retry with backoff. |
Rate limits
The same per-key limits as the rest of /api/v1. Loading a backlog of orders is fine — pace it and
honor 429 responses with a backoff and it will sail through.
GET /campaign-sales with a date range if you need to pull new sales, and see
Webhooks for the events that are available today.