Developers
Guide

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.

A note on field names. Responses come back in camelCase — the sale id is 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 & pathWhat it does
POST /campaign-salesRecord 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.
Sales are create-and-read only — by design. A campaign sale carries a payment, a tax-deductible split and merchant fees, so there is no update and no delete endpoint. Correcting or voiding a sale happens inside Argenta, where the modification log records who changed what. This is the same rule the Donations API follows, and for the same reason: money records keep their audit trail.
This endpoint does not take payment. It records a sale that has already been paid for somewhere else. To actually collect money — card, wallet, or a mailed check — use your campaign's own public sales form, which handles the charge, the receipt and the fee cover.

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:

FieldWhat it is
DonationTotalThe tax-deductible portion, added up from the items' tax-deductible amounts.
PaymentTotalThe rest — what the buyer paid for goods received.
TotalAmountPaidThe 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.

StatusCodeWhen
400missing_field / invalid_fieldThe body failed validation — an unknown item, a quantity below 1, a purchaser not in your account. Nothing was written.
400invalid_requestThe sale was refused as a whole: not enough stock left, or over a quantity ceiling.
401unauthorizedMissing, malformed, revoked, or unknown key.
403insufficient_scopeA read-only key tried to write.
404not_foundNo sale, item or campaign with that id in your account.
413payload_too_largeBody over 64 KB.
429rate_limitedSlow down and retry with backoff.

Rate limits
Two limits apply, not one. Per key it is 15 requests a second and 600 a minute. There is also a per-IP limit of 40 a second and 1200 a minute, checked before we even read your key, so several keys calling from the same server share that budget. Either limit returns a 429 with a Retry-After header saying how many seconds to wait. The AI writing assistant is metered on its own separate from these: 10 requests a minute and 100 an hour for each person, and 1,000 an hour across the whole system. It also refuses text longer than 10,000 characters before any limit is counted.

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.

There are no campaign webhooks yet. Unlike constituents, donations, volunteers and events, we do not currently notify your system when a campaign sale is recorded. Poll GET /campaign-sales with a date range if you need to pull new sales, and see Webhooks for the events that are available today.
Reconnecting…

Whoops!

You've Encountered An Error

Something went wrong on our end. Don't worry, our development team has already been notified, and we'll get it fixed as soon as we can.

Please avoid repeating the same action for now. A quick reload usually gets you going again.