Billing
16 endpoints, generated from the API's own OpenAPI document. The self-serve subscription: plan, interval, seats, county slots, the API add-on, the card, invoices.
GET /v2/plans
The plan catalogue
Credentials: API key or App session. Operation id acctListPlans.
Either credential (an API key or a session); resolves the caller's active organization (X-DTG-Org). Any role. T14/T31: the Trial row, then every active plan in price order, with prices, counties, seats, the monthly points allowance and the API add-on. Every price is read from the payment catalog the checkout charges. Takes no query parameters. No side effects.
Parameters
X-DTG-Orgheader · string (uuid)- The organization this request acts in (a uuid). Omitted: the caller's own organization, else their earliest active membership. An API key is bound to its organization and may only name that one.
Responses
200 success
The catalogue.
As application/json.
dataarray of AcctPlanRowalways present- The rows.
data[].codestringalways present- The plan code (
trialfor the Trial row). data[].namestringalways present- The display name (D42-FINAL).
data[].priceobjectalways present- Prices in US dollars.
data[].price.month_usdnumber or nullalways present- Monthly price; null for the Trial row.
data[].price.year_usdnumber or nullalways present- Annual price; null for the Trial row.
data[].countiesobjectalways present- Counties.
data[].counties.includedintegeralways present- Counties included; -1 means every county.
data[].counties.allbooleanalways present- True when every county is included.
data[].counties.extra_month_usdnumber or nullalways present- Price of one extra county slot a month; null when not sold.
data[].counties.extra_year_usdnumber or nullalways present- Price of one extra county slot a year; null when not sold.
data[].seatsobjectalways present- Seats.
data[].seats.includedinteger or nullalways present- Seats included; null for the Trial row.
data[].seats.extra_month_usdnumber or nullalways present- Price of one extra seat a month; null when not sold.
data[].seats.extra_year_usdnumber or nullalways present- Price of one extra seat a year; null when not sold.
data[].points_quota_monthinteger or nullalways present- The plan's monthly points allowance without the API add-on; null when unlimited, and on the Trial row.
data[].csv_accessboolean or nullalways present- True when CSV and XLSX export is included; null on the Trial row.
data[].vintage_accessboolean or nullalways present- True when earlier vintages are included; null on the Trial row.
data[].quarterly_accessboolean or nullalways present- True when quarterly data is included; null on the Trial row.
data[].api_addonobjectalways present- The API add-on with this plan.
data[].api_addon.availablebooleanalways present- True when the add-on is sold with this plan.
data[].api_addon.month_usdnumber or nullalways present- Always null: the add-on is sold with an annual plan only.
data[].api_addon.year_usdnumber or nullalways present- Its annual price; null when not sold.
data[].api_addon.points_quota_monthinteger or nullalways present- The monthly points allowance with the add-on; null when not sold or unlimited.
data[].trialobject or nullalways present- The trial's terms on the Trial row; null on every plan row.
data[].trial.daysintegeralways present- Trial length in days (
rules.trial_days). data[].trial.cooldown_daysnullalways present- Always null (not stated to customers).
data[].trial.countiesintegeralways present- Always 1: a trial unlocks one county.
data[].trial.export"trial_county"always present- Always
trial_county: export of the trial county only. data[].trial.live_keysbooleanalways present- Always false: a trial grants no live API keys.
metaobjectalways present- T153: which payment catalog the prices were read from.
meta.stripe_mode"fake" | "test" | "live"always present- The Stripe mode of the catalog every paid price here was read from:
live(production on live keys),test(Stripe test mode) orfake(the development simulation). A pricing check reads it to know which catalog it compared.
400 error
Bad Request. Codes: unknown_parameter (any query parameter; the body carries parameters).
As application/problem+json.
401 error
Unauthorized. Codes: key_revoked (the API key was revoked; revoked_at, reason, and a sentence saying when and why); unauthenticated (no API key or session; the key is unknown, or its account, membership or organization is no longer active; the session has expired, passed its 30-day maximum age, or belongs to an unverified email address).
As application/problem+json.
403 error
Forbidden. Codes: no_membership (the account has no active membership in an active organization), account_suspended (O56: the signed-in person's own account is suspended by DTG; reason where recorded), org_suspended (the selected organization is suspended by DTG; the body carries organization {id, name} and reason), org_closed (the selected organization is closed; the body carries organization {id, name}), wrong_instance (a key of the mode this process does not serve: a sandbox key on the live API, or a live key on the sandbox; the body carries expected and base_url, the address that serves it).
As application/problem+json.
404 error
Not Found. Codes: not_found (the X-DTG-Org header is not a uuid, names an organization the caller is not an active member of, or, on an API key, names an organization other than the key's own).
As application/problem+json.
429 error
Only the per-minute rate limit: rate_limited (120 requests a minute per credential, 300 per organization; lower ceilings for a sandbox key), with Retry-After and X-RateLimit-*.
As application/problem+json.
Retry-Afterheader- Seconds to wait before retrying.
X-RateLimit-Limitheader- The per-minute request ceiling that applies.
X-RateLimit-Remainingheader- Requests left in the current window.
X-RateLimit-Resetheader- Seconds until the window refills: on every answer, the time until the bucket is full again; on a refusal, until a request is allowed (as
Retry-After).
Problem codes: unknown_parameter (400), key_revoked (401), unauthenticated (401), no_membership (403), account_suspended (403), org_suspended (403), org_closed (403), wrong_instance (403), not_found (404), rate_limited (429). Every problem is a problem document.
GET /v2/account/billing
The organization's billing state
Credentials: API key or App session. Operation id billGetSummary.
The plan, interval, add-ons, seats, county slots, the current subscription and its renewal, what is scheduled for the period end (pending_change), the default payment method (brand, last four, expiry) and the 12 most recent invoices. Either credential (API key or session). The owner or a billing contact only (O63 S11, Q22): anyone else, an admin included, is answered 403 role_required (required: [owner, billing_contact]); whether service is paused reaches every member as organization.past_due on GET /v2/account. Prices and allowances in the response are read from the plan catalog; GET /v2/plans is canonical. While subscription.status is past_due, L18 pauses county detail, CSV/XLSX export, live API keys and cluster editing (not billing): fix the card with the payment-method endpoints and pay with POST /v2/account/billing/retry.
Responses
200 success
The billing summary.
As application/json.
gateway"fake" | "test" | "live"always present- Which payment gateway this server runs:
live(Stripe live mode, production only),test(Stripe test mode) orfake(an in-process simulation used in development and tests). T153: the Stripe secret key's prefix decides betweentestandlive. publishable_keystring or nullalways present- The Stripe publishable key to initialise Stripe.js and the Payment Element with.
billing_mode"self_serve" | "invoiced"always presentself_serve(card subscription managed through these endpoints) orinvoiced(a contract managed by Data Tactical Group: every self-serve change answers 403contract_managed).contractobject or nullalways present- The contract terms for an
invoicedorganization; null forself_serve. contract.expires_atstring (date-time) or null- When the contract ends; null for no end date.
contract.notesstring or null- DTG's notes on the contract.
planobjectalways present- The plan the organization holds now.
plan.codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. plan.namestringalways present- The plan's display name (e.g. Local, Regional, National, Free).
plan.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. addonsarray of stringalways present- Active add-ons.
seatsobjectalways present- Seats: the plan's included seats plus purchased extra seats.
seats.includedintegeralways present- Seats the plan includes (the plan's allowance; see
GET /v2/plans), raised tograndfatheredwhile that is set. seats.grandfatheredinteger or null- T163: an organization that had more seated members than its plan's new included count when Regional fell to 10 seats and National to 15 keeps that many included seats until its seated members fall to the plan's count or its plan changes. This is that count; null for every other organization.
seats.purchasedintegeralways present- Extra seats the organization holds beyond
included. A scheduled decrease does not lower this until period end. seats.billed_quantityintegeralways present- The seat quantity on the Stripe subscription (for an
invoicedorganization, the contracted extra seats; 0 with no subscription). Can differ frompurchasedbriefly while a scheduled decrease has been sent to Stripe ahead of the renewal. seats.seat_price_usd_monthnumber or nullalways present- The plan's monthly price of one extra seat, in US dollars; null when the plan sells no extra seats.
seats.proration"always_invoice"always present- How a seat increase is billed: always
always_invoice(prorated to the rest of the period and charged to the card at purchase). seats.proration_notestringalways present- A sentence stating the seat billing rule for display.
countiesobjectalways present- County slots: the plan's included counties plus paid county slots. The county SET is managed at
/v2/account/counties; this is the billing quantity behind it. counties.includedintegeralways present- Counties the plan includes; -1 means every county (National).
counties.purchasedintegeralways present- Paid county slots beyond
included. counties.billed_quantityintegeralways present- The county-slot quantity on the Stripe subscription (for an
invoicedorganization, the contracted slots; 0 with no subscription). counties.activeintegeralways present- Counties currently in the organization's active set, not counting a trial county.
counties.county_price_usd_monthnumber or nullalways present- The plan's monthly price of one extra county slot, in US dollars; null when the plan sells no extra counties.
counties.proration"always_invoice"always present- How a slot increase is billed: always
always_invoice(prorated and charged at purchase). counties.proration_notestringalways present- A sentence stating the county-slot billing rule for display.
counties.anchor_dayinteger or nullalways present- Day of the month of the organization's change window (the subscription's anchor date), on which county set changes land; null before a first subscription. (1 to 31)
subscriptionobject or nullalways present- The current Stripe subscription (status active, trialing, past_due or incomplete); null when there is none (Free, or contract-managed without one).
subscription.idstring- Stripe subscription id (
sub_...). subscription.status"active" | "trialing" | "past_due" | "incomplete"active;trialing;past_due(a renewal was declined: L18 pauses county detail, CSV/XLSX export, live API keys and cluster editing at once, while the plan and its capacity stay held; pay withPOST /v2/account/billing/retryafter fixing the card);incomplete(the first payment has not succeeded).subscription.current_period_startstring (date-time) or null- Start of the current billing period.
subscription.current_period_endstring (date-time) or null- End of the current billing period: where scheduled changes and a cancellation take effect.
subscription.renewal_datestring (date-time) or null- When the subscription renews (the period end); null when it is set to cancel at period end.
subscription.cancel_at_period_endboolean- True when the subscription ends at
current_period_endinstead of renewing. subscription.past_due_sincestring (date-time) or null- When the subscription first became past due; null when it is not past due.
subscription.dunning_grace_daysinteger- Days a past-due subscription has before it is cancelled and the organization drops to Free (the downgrade composite applies). Service is paused from the decline, not from the end of this window.
pending_changeBillPendingChange or nullalways present- What is scheduled for the period end; null when nothing (and no cancellation) is scheduled.
pending_change.plan_codestring or null- The plan the organization moves to at period end; null when no plan move is scheduled (an interval-only move leaves this null and sets
interval). pending_change.interval"month" | "year" | null- The interval the organization moves to at period end; null when no interval move is scheduled.
pending_change.seats_purchasedinteger or null- The purchased seat quantity from period end; null when no seat decrease is scheduled.
pending_change.counties_purchasedinteger or null- The paid county-slot quantity from period end; null when no slot release is scheduled.
pending_change.remove_addonsarray of string- Add-ons removed at period end; empty when none.
pending_change.cancelboolean- True when the subscription is set to cancel at period end (
POST /v2/account/billing/cancel);POST /v2/account/billing/resumeclears it and nothing else. pending_change.effective_atstring (date-time)- The period end at which everything here takes effect.
pending_change.changesarray of BillPendingItemPlan or BillPendingItemCounties or BillPendingItemSeats or BillPendingItemAddonRemoval- The scheduled set, one item per quantity. A cancellation is not an item here (see
cancel). pending_change.changes[].kind"plan"- Always
plan. pending_change.changes[].plan_codestring- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. pending_change.changes[].interval"month" | "year"- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. pending_change.changes[].effective_atstring (date-time) or null- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. pending_change.changes[].counties_purchasedinteger- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) pending_change.changes[].seats_purchasedinteger- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) pending_change.changes[].addonsarray of string- The add-ons that will be removed.
payment_methodBillPaymentMethod or nullalways present- The default payment method; null when none is set.
payment_method.idstring- Stripe PaymentMethod id (
pm_...). payment_method.brandstring- Card brand as Stripe reports it, e.g.
visa,mastercard. payment_method.last4string- Last four digits of the card number.
payment_method.exp_monthinteger- Card expiry month. (1 to 12)
payment_method.exp_yearinteger- Card expiry year (four digits).
invoicesarray of BillInvoicealways present- Up to the 12 most recent invoices, newest first.
invoices[].idstringalways present- Stripe invoice id (
in_...). invoices[].numberstring or nullalways present- The invoice number printed on it; null while a draft.
invoices[].status"draft" | "open" | "paid" | "void" | "uncollectible"always presentopenis unpaid and collectable (a declined renewal staysopenwhile the subscription ispast_due;POST /v2/account/billing/retrypays it);paid;void;uncollectible;draftnot yet finalized.invoices[].total_centsintegeralways present- Invoice total in US cents.
invoices[].amount_due_centsintegeralways present- Amount still owed, in US cents.
invoices[].amount_paid_centsintegeralways present- Amount paid, in US cents.
invoices[].createdstring (date-time)always present- When the invoice was created.
invoices[].due_datestring (date-time) or nullalways present- Due date for a
send_invoice(contract) invoice; null for card-charged invoices. invoices[].periodobjectalways present- The service period the invoice covers.
invoices[].period.startstring (date-time)always present- Period start.
invoices[].period.endstring (date-time)always present- Period end.
invoices[].hosted_invoice_urlstring (uri) or nullalways present- Stripe's hosted page for viewing and paying the invoice; null when Stripe has none.
invoices[].collection_method"charge_automatically" | "send_invoice"always presentcharge_automatically(charged to the card on file: self-serve) orsend_invoice(sent for payment by its due date: contract-managed organizations).invoices[].descriptionstring or nullalways present- Free-text memo on the invoice (contract invoices), else null.
invoices[].linesarray of BillInvoiceLinealways present- The invoice's lines.
invoices[].lines[].descriptionstringalways present- The line's text as Stripe renders it (product, quantity, period).
invoices[].lines[].amount_centsintegeralways present- Line amount in US cents; negative for a credit.
invoices[].lines[].quantityintegeralways present- Quantity the line bills (1 for the plan and the add-on; the seat or county-slot count for those items).
invoices[].lines[].prorationbooleanalways present- True when the line is a proration (the part-period charge or credit of a mid-period change).
401 error
Unauthenticated. Codes: unauthenticated (no valid API key or session); key_revoked (an API key that was revoked: revoked_at, and reason -- holder, admin, member_removed, seat_removed, api_disabled, addon_ended, account_closed, org_closed, retired, or null for a key revoked before T110 -- and a sentence saying when and why).
As application/problem+json.
403 error
Forbidden. Codes: no_membership (the account has no active organization), account_suspended (O56: the caller's own account is suspended by DTG), org_suspended (the organization is suspended), org_closed (the organization is closed), wrong_instance (a key of the mode this process does not serve: a sandbox key on the live API or a live key on the sandbox; base_url names the address that serves it).
As application/problem+json.
404 error
Not found. Codes: not_found (the X-DTG-Org header names an organization the caller does not belong to).
As application/problem+json.
429 error
rate_limited (the per-minute ceiling, X-RateLimit-* say which), points_exhausted (the monthly points allowance; Retry-After to the end of the UTC month), server_busy or sandbox_busy (load; retry after Retry-After). A refused server_busy request is not metered.
As application/problem+json.
Retry-Afterheader- Seconds to wait before retrying.
X-RateLimit-Limitheader- The per-minute request ceiling that applies.
X-RateLimit-Remainingheader- Requests left in the current window.
X-RateLimit-Resetheader- Seconds until the window refills: on every answer, the time until the bucket is full again; on a refusal, until a request is allowed (as
Retry-After).
Problem codes: unauthenticated (401), key_revoked (401), account_closed (401), org_closed (401), no_membership (403), account_suspended (403), org_suspended (403), org_closed (403), wrong_instance (403), not_found (404). Every problem is a problem document.
GET /v2/account/billing/invoices
The organization's recent invoices
Credentials: API key or App session. Operation id billListInvoices.
Up to the 12 most recent Stripe invoices, newest first (the same list as invoices in GET /v2/account/billing). Not paged. Either credential (API key or session). The owner or a billing contact only (O63 S11, Q22; 403 role_required otherwise).
Responses
200 success
The invoices.
As application/json.
dataarray of BillInvoicealways present- Up to the 12 most recent invoices, newest first. Empty when the organization has never had a Stripe customer.
data[].idstringalways present- Stripe invoice id (
in_...). data[].numberstring or nullalways present- The invoice number printed on it; null while a draft.
data[].status"draft" | "open" | "paid" | "void" | "uncollectible"always presentopenis unpaid and collectable (a declined renewal staysopenwhile the subscription ispast_due;POST /v2/account/billing/retrypays it);paid;void;uncollectible;draftnot yet finalized.data[].total_centsintegeralways present- Invoice total in US cents.
data[].amount_due_centsintegeralways present- Amount still owed, in US cents.
data[].amount_paid_centsintegeralways present- Amount paid, in US cents.
data[].createdstring (date-time)always present- When the invoice was created.
data[].due_datestring (date-time) or nullalways present- Due date for a
send_invoice(contract) invoice; null for card-charged invoices. data[].periodobjectalways present- The service period the invoice covers.
data[].period.startstring (date-time)always present- Period start.
data[].period.endstring (date-time)always present- Period end.
data[].hosted_invoice_urlstring (uri) or nullalways present- Stripe's hosted page for viewing and paying the invoice; null when Stripe has none.
data[].collection_method"charge_automatically" | "send_invoice"always presentcharge_automatically(charged to the card on file: self-serve) orsend_invoice(sent for payment by its due date: contract-managed organizations).data[].descriptionstring or nullalways present- Free-text memo on the invoice (contract invoices), else null.
data[].linesarray of BillInvoiceLinealways present- The invoice's lines.
data[].lines[].descriptionstringalways present- The line's text as Stripe renders it (product, quantity, period).
data[].lines[].amount_centsintegeralways present- Line amount in US cents; negative for a credit.
data[].lines[].quantityintegeralways present- Quantity the line bills (1 for the plan and the add-on; the seat or county-slot count for those items).
data[].lines[].prorationbooleanalways present- True when the line is a proration (the part-period charge or credit of a mid-period change).
401 error
Unauthenticated. Codes: unauthenticated (no valid API key or session); key_revoked (an API key that was revoked: revoked_at, and reason -- holder, admin, member_removed, seat_removed, api_disabled, addon_ended, account_closed, org_closed, retired, or null for a key revoked before T110 -- and a sentence saying when and why).
As application/problem+json.
403 error
Forbidden. Codes: no_membership (the account has no active organization), account_suspended (O56: the caller's own account is suspended by DTG), org_suspended (the organization is suspended), org_closed (the organization is closed), wrong_instance (a key of the mode this process does not serve: a sandbox key on the live API or a live key on the sandbox; base_url names the address that serves it).
As application/problem+json.
404 error
Not found. Codes: not_found (the X-DTG-Org header names an organization the caller does not belong to).
As application/problem+json.
429 error
rate_limited (the per-minute ceiling, X-RateLimit-* say which), points_exhausted (the monthly points allowance; Retry-After to the end of the UTC month), server_busy or sandbox_busy (load; retry after Retry-After). A refused server_busy request is not metered.
As application/problem+json.
Retry-Afterheader- Seconds to wait before retrying.
X-RateLimit-Limitheader- The per-minute request ceiling that applies.
X-RateLimit-Remainingheader- Requests left in the current window.
X-RateLimit-Resetheader- Seconds until the window refills: on every answer, the time until the bucket is full again; on a refusal, until a request is allowed (as
Retry-After).
Problem codes: unauthenticated (401), key_revoked (401), account_closed (401), org_closed (401), no_membership (403), account_suspended (403), org_suspended (403), org_closed (403), wrong_instance (403), not_found (404). Every problem is a problem document.
POST /v2/account/billing/payment-method
Start adding a card (a SetupIntent for the Payment Element)
Credentials: API key or App session. Operation id billCreateSetupIntent.
Creates a Stripe SetupIntent for the organization (creating its Stripe customer on first use) and returns its client secret for Stripe's Payment Element, which collects the card in the browser (card data never reaches Taigan). Then call POST /v2/account/billing/payment-method/confirm. No request body. Either credential (API key or session). Only the organization's owner or a member flagged as billing contact (an admin only when also a billing contact). Not refused for a contract-managed organization. T108: takes the organization's billing lock, as every billing write does (409 billing_in_progress after 15 s).
Responses
201 success
SetupIntent created.
As application/json.
setup_intent_idstringalways present- SetupIntent id (
seti_...); send it toPOST /v2/account/billing/payment-method/confirmonce Stripe.js has confirmed it. client_secretstringalways present- The SetupIntent's client secret, for the Payment Element. Treat as a secret; do not log it.
publishable_keystring or nullalways present- Stripe publishable key to initialise Stripe.js with.
gateway"fake" | "test" | "live"always presentlive(Stripe live mode, production only),test(Stripe test mode) orfake(development simulation).
401 error
Unauthenticated. Codes: unauthenticated (no valid API key or session); key_revoked (an API key that was revoked: revoked_at, and reason -- holder, admin, member_removed, seat_removed, api_disabled, addon_ended, account_closed, org_closed, retired, or null for a key revoked before T110 -- and a sentence saying when and why).
As application/problem+json.
403 error
Forbidden. Codes: role_required (only the owner, or a member flagged as billing contact, may manage billing; an admin only when also a billing contact; the problem carries required: [owner, billing_contact]), no_membership (the account has no active organization), account_suspended (O56: the caller's own account is suspended by DTG), org_suspended (the organization is suspended), org_closed (the organization is closed), wrong_instance (a key of the mode this process does not serve: a sandbox key on the live API or a live key on the sandbox; base_url names the address that serves it). A sandbox key: sandbox_read_only (it may write only clusters).
As application/problem+json.
404 error
Not found. Codes: not_found (the X-DTG-Org header names an organization the caller does not belong to).
As application/problem+json.
429 error
rate_limited (the per-minute ceiling, X-RateLimit-* say which), points_exhausted (the monthly points allowance; Retry-After to the end of the UTC month), server_busy or sandbox_busy (load; retry after Retry-After). A refused server_busy request is not metered.
As application/problem+json.
Retry-Afterheader- Seconds to wait before retrying.
X-RateLimit-Limitheader- The per-minute request ceiling that applies.
X-RateLimit-Remainingheader- Requests left in the current window.
X-RateLimit-Resetheader- Seconds until the window refills: on every answer, the time until the bucket is full again; on a refusal, until a request is allowed (as
Retry-After).
Problem codes: unauthenticated (401), key_revoked (401), account_closed (401), org_closed (401), role_required (403), no_membership (403), account_suspended (403), org_suspended (403), org_closed (403), wrong_instance (403), sandbox_read_only (403), not_found (404). Every problem is a problem document.
POST /v2/account/billing/payment-method/confirm
Make the confirmed card the default payment method
Credentials: API key or App session. Operation id billConfirmPaymentMethod.
After the Payment Element has confirmed the SetupIntent, makes its card the organization's default payment method for every future charge. Writes the audit row billing.payment_method_set (brand and last four only). Either credential (API key or session). Only the organization's owner or a member flagged as billing contact (an admin only when also a billing contact). T108: takes the organization's billing lock (409 billing_in_progress after 15 s); an unknown setup_intent_id is the same 404 as another organization's (it answered 500).
Request body
Required; application/json.
setup_intent_idstringrequired- The SetupIntent from
POST /v2/account/billing/payment-method, after the Payment Element confirmed it.
Responses
200 success
The new default payment method.
As application/json.
payment_methodBillPaymentMethodalways present- The organization's default payment method: the card brand, last four digits and expiry only (card data never reaches Taigan; it is captured by Stripe's Payment Element). When the card details cannot be read only
idis present. payment_method.idstringalways present- Stripe PaymentMethod id (
pm_...). payment_method.brandstring- Card brand as Stripe reports it, e.g.
visa,mastercard. payment_method.last4string- Last four digits of the card number.
payment_method.exp_monthinteger- Card expiry month. (1 to 12)
payment_method.exp_yearinteger- Card expiry year (four digits).
400 error
Bad request. Codes: bad_request (setup_intent_id is missing or not a string), malformed_json (the body is not valid JSON).
As application/problem+json.
401 error
Unauthenticated. Codes: unauthenticated (no valid API key or session); key_revoked (an API key that was revoked: revoked_at, and reason -- holder, admin, member_removed, seat_removed, api_disabled, addon_ended, account_closed, org_closed, retired, or null for a key revoked before T110 -- and a sentence saying when and why).
As application/problem+json.
403 error
Forbidden. Codes: role_required (only the owner, or a member flagged as billing contact, may manage billing; an admin only when also a billing contact; the problem carries required: [owner, billing_contact]), no_membership (the account has no active organization), account_suspended (O56: the caller's own account is suspended by DTG), org_suspended (the organization is suspended), org_closed (the organization is closed), wrong_instance (a key of the mode this process does not serve: a sandbox key on the live API or a live key on the sandbox; base_url names the address that serves it). A sandbox key: sandbox_read_only (it may write only clusters).
As application/problem+json.
404 error
Not found. Codes: not_found (the SetupIntent does not belong to this organization), not_found (the X-DTG-Org header names an organization the caller does not belong to).
As application/problem+json.
409 error
Conflict. Codes: setup_intent_incomplete (the SetupIntent has not succeeded yet; confirm it with the Payment Element first; the problem carries Stripe's status, e.g. requires_payment_method).
As application/problem+json.
413 error
Payload too large. Codes: body_too_large (the JSON body is over 16 KB; the problem carries limit_bytes).
As application/problem+json.
429 error
rate_limited (the per-minute ceiling, X-RateLimit-* say which), points_exhausted (the monthly points allowance; Retry-After to the end of the UTC month), server_busy or sandbox_busy (load; retry after Retry-After). A refused server_busy request is not metered.
As application/problem+json.
Retry-Afterheader- Seconds to wait before retrying.
X-RateLimit-Limitheader- The per-minute request ceiling that applies.
X-RateLimit-Remainingheader- Requests left in the current window.
X-RateLimit-Resetheader- Seconds until the window refills: on every answer, the time until the bucket is full again; on a refusal, until a request is allowed (as
Retry-After).
Problem codes: bad_request (400), malformed_json (400), unauthenticated (401), key_revoked (401), account_closed (401), org_closed (401), role_required (403), no_membership (403), account_suspended (403), org_suspended (403), org_closed (403), wrong_instance (403), sandbox_read_only (403), not_found (404), setup_intent_incomplete (409), body_too_large (413). Every problem is a problem document.
POST /v2/account/billing/subscribe
Create the organization's first subscription
Credentials: API key or App session. Operation id billSubscribe.
Subscribes the organization to a plan at an interval, optionally with extra seats, paid county slots and (annual only) the API add-on. Charges the default payment method, so one must be set first. Ends any running trial as converted (the trial county becomes an ordinary county). An annual term is non-refundable from the purchase; cancelling stops renewal and access runs to the paid-through date. Writes the audit row billing.subscribed. Either credential (API key or session). Only the organization's owner or a member flagged as billing contact (an admin only when also a billing contact). Billing changes for one organization are serialized: a second one waits for the first and, after 15 seconds, answers 409 billing_in_progress.
Request body
Required; application/json.
plan_codestringrequired- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. intervalobject- Billing interval; default
month. (default "month") seatsinteger- Extra seats to buy beyond the plan's included seats. (default 0; 0 to 500)
countiesinteger- Paid county slots to buy beyond the plan's included counties; only on a plan that sells extra counties. (default 0; 0 to 3194)
addonsarray of "api"- Add-ons to buy with the plan: only
api, and only withinterval: year.
Responses
201 success
Subscription created (check status: incomplete means the first payment did not succeed).
As application/json.
subscription_idstringalways present- Stripe subscription id (
sub_...). statusstringalways present- Stripe's status for the new subscription:
active(ortrialing) when the first payment succeeded;incompletewhen it did not (no entitlement until it is paid). summaryBillSummaryalways present- The organization's billing state as Kelpie's seats-and-billing screen shows it.
summary.gateway"fake" | "test" | "live"always present- Which payment gateway this server runs:
live(Stripe live mode, production only),test(Stripe test mode) orfake(an in-process simulation used in development and tests). T153: the Stripe secret key's prefix decides betweentestandlive. summary.publishable_keystring or nullalways present- The Stripe publishable key to initialise Stripe.js and the Payment Element with.
summary.billing_mode"self_serve" | "invoiced"always presentself_serve(card subscription managed through these endpoints) orinvoiced(a contract managed by Data Tactical Group: every self-serve change answers 403contract_managed).summary.contractobject or nullalways present- The contract terms for an
invoicedorganization; null forself_serve. summary.contract.expires_atstring (date-time) or null- When the contract ends; null for no end date.
summary.contract.notesstring or null- DTG's notes on the contract.
summary.planobjectalways present- The plan the organization holds now.
summary.plan.codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. summary.plan.namestringalways present- The plan's display name (e.g. Local, Regional, National, Free).
summary.plan.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. summary.addonsarray of stringalways present- Active add-ons.
summary.seatsobjectalways present- Seats: the plan's included seats plus purchased extra seats.
summary.seats.includedintegeralways present- Seats the plan includes (the plan's allowance; see
GET /v2/plans), raised tograndfatheredwhile that is set. summary.seats.grandfatheredinteger or null- T163: an organization that had more seated members than its plan's new included count when Regional fell to 10 seats and National to 15 keeps that many included seats until its seated members fall to the plan's count or its plan changes. This is that count; null for every other organization.
summary.seats.purchasedintegeralways present- Extra seats the organization holds beyond
included. A scheduled decrease does not lower this until period end. summary.seats.billed_quantityintegeralways present- The seat quantity on the Stripe subscription (for an
invoicedorganization, the contracted extra seats; 0 with no subscription). Can differ frompurchasedbriefly while a scheduled decrease has been sent to Stripe ahead of the renewal. summary.seats.seat_price_usd_monthnumber or nullalways present- The plan's monthly price of one extra seat, in US dollars; null when the plan sells no extra seats.
summary.seats.proration"always_invoice"always present- How a seat increase is billed: always
always_invoice(prorated to the rest of the period and charged to the card at purchase). summary.seats.proration_notestringalways present- A sentence stating the seat billing rule for display.
summary.countiesobjectalways present- County slots: the plan's included counties plus paid county slots. The county SET is managed at
/v2/account/counties; this is the billing quantity behind it. summary.counties.includedintegeralways present- Counties the plan includes; -1 means every county (National).
summary.counties.purchasedintegeralways present- Paid county slots beyond
included. summary.counties.billed_quantityintegeralways present- The county-slot quantity on the Stripe subscription (for an
invoicedorganization, the contracted slots; 0 with no subscription). summary.counties.activeintegeralways present- Counties currently in the organization's active set, not counting a trial county.
summary.counties.county_price_usd_monthnumber or nullalways present- The plan's monthly price of one extra county slot, in US dollars; null when the plan sells no extra counties.
summary.counties.proration"always_invoice"always present- How a slot increase is billed: always
always_invoice(prorated and charged at purchase). summary.counties.proration_notestringalways present- A sentence stating the county-slot billing rule for display.
summary.counties.anchor_dayinteger or nullalways present- Day of the month of the organization's change window (the subscription's anchor date), on which county set changes land; null before a first subscription. (1 to 31)
summary.subscriptionobject or nullalways present- The current Stripe subscription (status active, trialing, past_due or incomplete); null when there is none (Free, or contract-managed without one).
summary.subscription.idstring- Stripe subscription id (
sub_...). summary.subscription.status"active" | "trialing" | "past_due" | "incomplete"active;trialing;past_due(a renewal was declined: L18 pauses county detail, CSV/XLSX export, live API keys and cluster editing at once, while the plan and its capacity stay held; pay withPOST /v2/account/billing/retryafter fixing the card);incomplete(the first payment has not succeeded).summary.subscription.current_period_startstring (date-time) or null- Start of the current billing period.
summary.subscription.current_period_endstring (date-time) or null- End of the current billing period: where scheduled changes and a cancellation take effect.
summary.subscription.renewal_datestring (date-time) or null- When the subscription renews (the period end); null when it is set to cancel at period end.
summary.subscription.cancel_at_period_endboolean- True when the subscription ends at
current_period_endinstead of renewing. summary.subscription.past_due_sincestring (date-time) or null- When the subscription first became past due; null when it is not past due.
summary.subscription.dunning_grace_daysinteger- Days a past-due subscription has before it is cancelled and the organization drops to Free (the downgrade composite applies). Service is paused from the decline, not from the end of this window.
summary.pending_changeBillPendingChange or nullalways present- What is scheduled for the period end; null when nothing (and no cancellation) is scheduled.
summary.pending_change.plan_codestring or null- The plan the organization moves to at period end; null when no plan move is scheduled (an interval-only move leaves this null and sets
interval). summary.pending_change.interval"month" | "year" | null- The interval the organization moves to at period end; null when no interval move is scheduled.
summary.pending_change.seats_purchasedinteger or null- The purchased seat quantity from period end; null when no seat decrease is scheduled.
summary.pending_change.counties_purchasedinteger or null- The paid county-slot quantity from period end; null when no slot release is scheduled.
summary.pending_change.remove_addonsarray of string- Add-ons removed at period end; empty when none.
summary.pending_change.cancelboolean- True when the subscription is set to cancel at period end (
POST /v2/account/billing/cancel);POST /v2/account/billing/resumeclears it and nothing else. summary.pending_change.effective_atstring (date-time)- The period end at which everything here takes effect.
summary.pending_change.changesarray of BillPendingItemPlan or BillPendingItemCounties or BillPendingItemSeats or BillPendingItemAddonRemoval- The scheduled set, one item per quantity. A cancellation is not an item here (see
cancel). summary.pending_change.changes[].kind"plan"- Always
plan. summary.pending_change.changes[].plan_codestring- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. summary.pending_change.changes[].interval"month" | "year"- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. summary.pending_change.changes[].effective_atstring (date-time) or null- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. summary.pending_change.changes[].counties_purchasedinteger- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) summary.pending_change.changes[].seats_purchasedinteger- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) summary.pending_change.changes[].addonsarray of string- The add-ons that will be removed.
summary.payment_methodBillPaymentMethod or nullalways present- The default payment method; null when none is set.
summary.payment_method.idstring- Stripe PaymentMethod id (
pm_...). summary.payment_method.brandstring- Card brand as Stripe reports it, e.g.
visa,mastercard. summary.payment_method.last4string- Last four digits of the card number.
summary.payment_method.exp_monthinteger- Card expiry month. (1 to 12)
summary.payment_method.exp_yearinteger- Card expiry year (four digits).
summary.invoicesarray of BillInvoicealways present- Up to the 12 most recent invoices, newest first.
summary.invoices[].idstringalways present- Stripe invoice id (
in_...). summary.invoices[].numberstring or nullalways present- The invoice number printed on it; null while a draft.
summary.invoices[].status"draft" | "open" | "paid" | "void" | "uncollectible"always presentopenis unpaid and collectable (a declined renewal staysopenwhile the subscription ispast_due;POST /v2/account/billing/retrypays it);paid;void;uncollectible;draftnot yet finalized.summary.invoices[].total_centsintegeralways present- Invoice total in US cents.
summary.invoices[].amount_due_centsintegeralways present- Amount still owed, in US cents.
summary.invoices[].amount_paid_centsintegeralways present- Amount paid, in US cents.
summary.invoices[].createdstring (date-time)always present- When the invoice was created.
summary.invoices[].due_datestring (date-time) or nullalways present- Due date for a
send_invoice(contract) invoice; null for card-charged invoices. summary.invoices[].periodobjectalways present- The service period the invoice covers.
summary.invoices[].period.startstring (date-time)always present- Period start.
summary.invoices[].period.endstring (date-time)always present- Period end.
summary.invoices[].hosted_invoice_urlstring (uri) or nullalways present- Stripe's hosted page for viewing and paying the invoice; null when Stripe has none.
summary.invoices[].collection_method"charge_automatically" | "send_invoice"always presentcharge_automatically(charged to the card on file: self-serve) orsend_invoice(sent for payment by its due date: contract-managed organizations).summary.invoices[].descriptionstring or nullalways present- Free-text memo on the invoice (contract invoices), else null.
summary.invoices[].linesarray of BillInvoiceLinealways present- The invoice's lines.
summary.invoices[].lines[].descriptionstringalways present- The line's text as Stripe renders it (product, quantity, period).
summary.invoices[].lines[].amount_centsintegeralways present- Line amount in US cents; negative for a credit.
summary.invoices[].lines[].quantityintegeralways present- Quantity the line bills (1 for the plan and the add-on; the seat or county-slot count for those items).
summary.invoices[].lines[].prorationbooleanalways present- True when the line is a proration (the part-period charge or credit of a mid-period change).
400 error
Bad request. Codes: annual_plan_required (the API add-on was requested with a non-annual interval, D48), bad_request (plan_code missing, unknown or not purchasable; interval not month/year; seats not an integer 0 to 500; counties not an integer 0 to 3194, or extra counties on a plan that sells none; an add-on other than api; a field of the wrong type), malformed_json (the body is not valid JSON).
As application/problem+json.
401 error
Unauthenticated. Codes: unauthenticated (no valid API key or session); key_revoked (an API key that was revoked: revoked_at, and reason -- holder, admin, member_removed, seat_removed, api_disabled, addon_ended, account_closed, org_closed, retired, or null for a key revoked before T110 -- and a sentence saying when and why).
As application/problem+json.
402 error
Payment required. Codes: payment_method_required (add a payment method first: POST /v2/account/billing/payment-method).
As application/problem+json.
403 error
Forbidden. Codes: role_required (only the owner, or a member flagged as billing contact, may manage billing; an admin only when also a billing contact; the problem carries required: [owner, billing_contact]), contract_managed (the organization is billing_mode: invoiced: its plan is managed under a contract by Data Tactical Group), no_membership (the account has no active organization), account_suspended (O56: the caller's own account is suspended by DTG), org_suspended (the organization is suspended), org_closed (the organization is closed), wrong_instance (a key of the mode this process does not serve: a sandbox key on the live API or a live key on the sandbox; base_url names the address that serves it). A sandbox key: sandbox_read_only (it may write only clusters).
As application/problem+json.
404 error
Not found. Codes: not_found (the X-DTG-Org header names an organization the caller does not belong to).
As application/problem+json.
409 error
Conflict. Codes: already_subscribed (the organization already has a subscription; use POST /v2/account/billing/change), billing_in_progress (another billing change for this organization is running; the request waited 15 seconds; retry).
As application/problem+json.
413 error
Payload too large. Codes: body_too_large (the JSON body is over 16 KB; the problem carries limit_bytes).
As application/problem+json.
429 error
rate_limited (the per-minute ceiling, X-RateLimit-* say which), points_exhausted (the monthly points allowance; Retry-After to the end of the UTC month), server_busy or sandbox_busy (load; retry after Retry-After). A refused server_busy request is not metered.
As application/problem+json.
Retry-Afterheader- Seconds to wait before retrying.
X-RateLimit-Limitheader- The per-minute request ceiling that applies.
X-RateLimit-Remainingheader- Requests left in the current window.
X-RateLimit-Resetheader- Seconds until the window refills: on every answer, the time until the bucket is full again; on a refusal, until a request is allowed (as
Retry-After).
Problem codes: annual_plan_required (400), bad_request (400), malformed_json (400), unauthenticated (401), key_revoked (401), account_closed (401), org_closed (401), payment_method_required (402), role_required (403), contract_managed (403), no_membership (403), account_suspended (403), org_suspended (403), org_closed (403), wrong_instance (403), sandbox_read_only (403), not_found (404), already_subscribed (409), billing_in_progress (409), body_too_large (413). Every problem is a problem document.
POST /v2/account/billing/preview
Price a change before making it
Credentials: API key or App session. Operation id billPreviewChange.
Classifies and prices a change to the subscription without making it: what is charged now (prorated, always_invoice), the next renewal invoice, what is scheduled now and what the change would leave scheduled, and whether the change needs a surviving-county choice. Everything is computed on the period-end state: every quantity the request names as requested, every other one as already scheduled. Adding the API add-on restarts the whole subscription's term today: term_restart is true and credit_cents and new_renewal_date are set. surviving_fips is ignored here. Takes no lock and changes nothing. Either credential (API key or session). Only the organization's owner or a member flagged as billing contact (an admin only when also a billing contact).
Request body
Required; application/json.
plan_codestring- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. interval"month" | "year"- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. seatsnumber- The purchased (extra) seat quantity wanted, beyond the plan's included seats. The whole target, not a delta.
countiesnumber- The paid county-slot quantity wanted, beyond the plan's included counties. The whole target, not a delta.
addonsarray of string- The complete set of add-ons wanted (
[]removes the API add-on at period end;["api"]adds it, annual plans only, restarting the subscription's term, D49). surviving_fipsarray of string- Only on
POST /v2/account/billing/change: when the change leaves fewer county places than the organization's active counties (counties_requiring_choicein the preview), the counties to keep. Exactlycapacitycodes, each one of the preview'scandidates. A choice already made stands while it still fits the period-end capacity. Ignored by the preview.
Responses
200 success
The preview.
As application/json.
currentBillStateSnapshotalways present- A billing state: plan, interval, add-ons and purchased quantities.
current.plan_codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. current.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. current.addonsarray of stringalways present- Add-ons.
current.seats_purchasednumberalways present- Purchased seats beyond the plan's included seats.
current.counties_purchasednumberalways present- Paid county slots beyond the plan's included counties.
targetobjectalways present- The state the request asks for (unnamed quantities at their current values).
target.plan_codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. target.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. target.addonsarray of stringalways present- Add-ons.
target.seats_purchasednumberalways present- Purchased seats beyond the plan's included seats.
target.counties_purchasednumberalways present- Paid county slots beyond the plan's included counties.
kind"upgrade" | "downgrade" | "mixed" | "none"always presentupgrade(only increases: applied now),downgrade(only decreases: scheduled for period end),mixed(both: the increases now at the current plan and interval, the decreases scheduled),none(no change).effective"immediately" | "period_end"always presentimmediatelywhen anything applies now (upgrade or mixed), elseperiod_end(also fornone).effective_atstring (date-time) or nullalways present- Now for an immediate change, else the current period end.
proration_behavior"always_invoice" | "none"always presentalways_invoicewhen the change applies now: the prorated amount is invoiced and charged to the card at once.nonefor a period-end change: nothing is charged now and nothing is credited.immediate_charge_centsintegeralways present- What the card is charged now, in US cents (the sum of the proration lines, never below 0); 0 for a period-end change. (at least 0)
proration_linesarray of BillAmountLinealways present- The prorated lines charged now. When the API add-on is being added (term restart) these are every line of the restarted term.
proration_lines[].descriptionstringalways present- The line's text as Stripe renders it (product, quantity, period).
proration_lines[].amount_centsintegeralways present- Line amount in US cents; negative for a credit.
proration_lines[].quantityintegeralways present- Quantity the line bills (1 for the plan and the add-on; the seat or county-slot count for those items).
term_restartbooleanalways present- True when the change adds the API add-on: the WHOLE subscription restarts its term today, every item moving to the new anchor together; the new term is charged now.
credit_centsinteger or nullalways present- Only when
term_restartis true: the magnitude, in US cents, of any credit lines Stripe returns for unused time (commonly 0, because Stripe nets a continuing item into one line). Null otherwise. new_renewal_datestring (date-time) or nullalways present- Only when
term_restartis true: the renewal date after the restart. Null otherwise. next_invoiceobjectalways present- The next renewal invoice, priced on the period-end state (what this change asks for plus what is already scheduled). Empty (
total_cents0, no lines) on a term restart, where everything is due now. next_invoice.total_centsintegeralways present- Total of the next invoice in US cents.
next_invoice.linesarray of BillAmountLinealways present- Its lines.
next_invoice.lines[].descriptionstringalways present- The line's text as Stripe renders it (product, quantity, period).
next_invoice.lines[].amount_centsintegeralways present- Line amount in US cents; negative for a credit.
next_invoice.lines[].quantityintegeralways present- Quantity the line bills (1 for the plan and the add-on; the seat or county-slot count for those items).
unit_prices_centsobjectalways present- Unit prices, in US cents per interval, for the target plan and interval, from the price catalog; 0 where the catalog holds no such price.
unit_prices_cents.planintegeralways present- The plan price.
unit_prices_cents.seatintegeralways present- One extra seat.
unit_prices_cents.countyintegeralways present- One extra county slot; 0 when the plan sells none.
unit_prices_cents.api_addonintegeralways present- The API add-on (0 on a monthly interval: it is sold annual only).
counties_requiring_choiceobject or nullalways present- Set when the period-end county capacity is below the organization's active counties (counties already scheduled to leave are not counted): the change must then carry
surviving_fips. Null otherwise. counties_requiring_choice.capacityintegeralways present- How many counties the period-end state holds (included plus paid slots).
counties_requiring_choice.candidatesarray of BillCountyCandidatealways present- The active counties to choose from, in KEEP order: the first
capacityare the default choice. counties_requiring_choice.candidates[].fipsstringalways present- Five-digit county FIPS code.
counties_requiring_choice.candidates[].source"manual" | "state" | "msa"always present- How the county entered the active set:
manual(picked),stateormsa(added as part of a state or metro). counties_requiring_choice.candidates[].added_atstring (date-time)always present- When it was added.
counties_requiring_choice.candidates[].last_usedstring (date-time) or nullalways present- The organization's last data request touching this county in the past 90 days; null when none.
county_slots_releasableintegeralways present- How many paid county slots the period-end state holds that the active set does not need (for example after a move to a plan with more included counties), so the customer could release them.
seats_becoming_free_membersintegeralways present- How many seated members exceed the period-end seat count and would become free members.
scheduledarray of BillPendingItemPlan or BillPendingItemCounties or BillPendingItemSeats or BillPendingItemAddonRemovalalways present- What is scheduled now, before this change.
scheduled[].kind"plan"- Always
plan. scheduled[].plan_codestring- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. scheduled[].interval"month" | "year"- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. scheduled[].effective_atstring (date-time) or null- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. scheduled[].counties_purchasedinteger- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) scheduled[].seats_purchasedinteger- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) scheduled[].addonsarray of string- The add-ons that will be removed.
scheduled_afterarray of BillPendingItemPlan or BillPendingItemCounties or BillPendingItemSeats or BillPendingItemAddonRemovalalways present- What this change would leave scheduled (in a mixed change, the plan move appears here).
scheduled_after[].kind"plan"- Always
plan. scheduled_after[].plan_codestring- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. scheduled_after[].interval"month" | "year"- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. scheduled_after[].effective_atstring (date-time) or null- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. scheduled_after[].counties_purchasedinteger- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) scheduled_after[].seats_purchasedinteger- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) scheduled_after[].addonsarray of string- The add-ons that will be removed.
replacesBillPendingReplacedalways present- For each scheduled item a change would replace (a second change to the same quantity), the item it replaces, keyed by its kind (
plan,counties,seats,addon_removal). An empty object when it replaces nothing. replaces.planBillPendingItemPlan- A scheduled plan or interval move, applied at period end.
replaces.plan.kind"plan"always present- Always
plan. replaces.plan.plan_codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. replaces.plan.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. replaces.plan.effective_atstring (date-time) or nullalways present- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. replaces.countiesBillPendingItemCounties- A scheduled decrease of the paid county-slot quantity (a slot release), applied at period end, not credited; the slots stay usable until then.
replaces.counties.kind"counties"always present- Always
counties. replaces.counties.counties_purchasedintegeralways present- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) replaces.counties.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
replaces.seatsBillPendingItemSeats- A scheduled decrease of purchased seats, applied at period end, not credited; the seats stay usable until then.
replaces.seats.kind"seats"always present- Always
seats. replaces.seats.seats_purchasedintegeralways present- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) replaces.seats.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
replaces.addon_removalBillPendingItemAddonRemoval- A scheduled add-on removal, applied at period end. When the API add-on leaves, the organization's live API keys are revoked at that moment; sandbox keys stay.
replaces.addon_removal.kind"addon_removal"always present- Always
addon_removal. replaces.addon_removal.addonsarray of stringalways present- The add-ons that will be removed.
replaces.addon_removal.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
400 error
Bad request. Codes: annual_plan_required (the state the change produces would hold the API add-on on a non-annual interval: adding it off-annual, or keeping it through a move to monthly; for a deferred change the period-end state is checked, so a move to monthly is allowed when the add-on's removal is scheduled), bad_request (unknown or non-purchasable plan_code; interval not month/year; a field of the wrong type), malformed_json (the body is not valid JSON).
As application/problem+json.
401 error
Unauthenticated. Codes: unauthenticated (no valid API key or session); key_revoked (an API key that was revoked: revoked_at, and reason -- holder, admin, member_removed, seat_removed, api_disabled, addon_ended, account_closed, org_closed, retired, or null for a key revoked before T110 -- and a sentence saying when and why).
As application/problem+json.
403 error
Forbidden. Codes: role_required (only the owner, or a member flagged as billing contact, may manage billing; an admin only when also a billing contact; the problem carries required: [owner, billing_contact]), contract_managed (the organization is billing_mode: invoiced: its plan is managed under a contract by Data Tactical Group), no_membership (the account has no active organization), account_suspended (O56: the caller's own account is suspended by DTG), org_suspended (the organization is suspended), org_closed (the organization is closed), wrong_instance (a key of the mode this process does not serve: a sandbox key on the live API or a live key on the sandbox; base_url names the address that serves it). A sandbox key: sandbox_read_only (it may write only clusters).
As application/problem+json.
404 error
Not found. Codes: not_found (the X-DTG-Org header names an organization the caller does not belong to).
As application/problem+json.
409 error
Conflict. Codes: not_subscribed (the organization has no active subscription; use POST /v2/account/billing/subscribe).
As application/problem+json.
413 error
Payload too large. Codes: body_too_large (the JSON body is over 16 KB; the problem carries limit_bytes).
As application/problem+json.
429 error
rate_limited (the per-minute ceiling, X-RateLimit-* say which), points_exhausted (the monthly points allowance; Retry-After to the end of the UTC month), server_busy or sandbox_busy (load; retry after Retry-After). A refused server_busy request is not metered.
As application/problem+json.
Retry-Afterheader- Seconds to wait before retrying.
X-RateLimit-Limitheader- The per-minute request ceiling that applies.
X-RateLimit-Remainingheader- Requests left in the current window.
X-RateLimit-Resetheader- Seconds until the window refills: on every answer, the time until the bucket is full again; on a refusal, until a request is allowed (as
Retry-After).
Problem codes: annual_plan_required (400), bad_request (400), malformed_json (400), unauthenticated (401), key_revoked (401), account_closed (401), org_closed (401), role_required (403), contract_managed (403), no_membership (403), account_suspended (403), org_suspended (403), org_closed (403), wrong_instance (403), sandbox_read_only (403), not_found (404), not_subscribed (409), body_too_large (413). Every problem is a problem document.
POST /v2/account/billing/change
Change the plan, interval, seats, county slots or add-ons
Credentials: API key or App session. Operation id billApplyChange.
Applies a change. Increases (a higher plan, month to year, the add-on added, more seats or county slots) take effect now, prorated to the rest of the period and charged to the card at once (always_invoice); a declined card still grants them, except the API add-on. Decreases (a lower plan, year to month, add-on removal, fewer seats or slots) are scheduled for period end and are not credited; what was paid for stays usable until then. A mixed request applies its increases now at the current plan and interval and schedules the rest. The request touches only the quantities it names; a second change to the same quantity replaces the first (replaced); naming one at its current value withdraws its scheduled change. Adding the API add-on restarts the whole subscription's term with Stripe's pending-if-incomplete behaviour: a declined card leaves the add-on ungranted. When a scheduled add-on removal takes effect, the organization's live API keys are revoked; sandbox keys stay. When the period-end state holds fewer counties than are active, the request must carry surviving_fips (see the preview's counties_requiring_choice); at period end the counties not kept leave the active set, and members beyond the seat count become free members. Writes the audit row billing.changed. Either credential (API key or session). Only the organization's owner or a member flagged as billing contact (an admin only when also a billing contact). Billing changes for one organization are serialized: a second one waits for the first and, after 15 seconds, answers 409 billing_in_progress.
Request body
Required; application/json.
plan_codestring- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. interval"month" | "year"- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. seatsnumber- The purchased (extra) seat quantity wanted, beyond the plan's included seats. The whole target, not a delta.
countiesnumber- The paid county-slot quantity wanted, beyond the plan's included counties. The whole target, not a delta.
addonsarray of string- The complete set of add-ons wanted (
[]removes the API add-on at period end;["api"]adds it, annual plans only, restarting the subscription's term, D49). surviving_fipsarray of string- Only on
POST /v2/account/billing/change: when the change leaves fewer county places than the organization's active counties (counties_requiring_choicein the preview), the counties to keep. Exactlycapacitycodes, each one of the preview'scandidates. A choice already made stands while it still fits the period-end capacity. Ignored by the preview.
Responses
200 success
The change applied or scheduled, with the preview it was decided on and the new summary.
As application/json.
applied"immediately" | "period_end"always presentimmediatelywhen an increase was applied now (and charged), elseperiod_end(the change, if any, is scheduled; also returned for a no-op).replacedBillPendingReplacedalways present- For each scheduled item a change would replace (a second change to the same quantity), the item it replaces, keyed by its kind (
plan,counties,seats,addon_removal). An empty object when it replaces nothing. replaced.planBillPendingItemPlan- A scheduled plan or interval move, applied at period end.
replaced.plan.kind"plan"always present- Always
plan. replaced.plan.plan_codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. replaced.plan.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. replaced.plan.effective_atstring (date-time) or nullalways present- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. replaced.countiesBillPendingItemCounties- A scheduled decrease of the paid county-slot quantity (a slot release), applied at period end, not credited; the slots stay usable until then.
replaced.counties.kind"counties"always present- Always
counties. replaced.counties.counties_purchasedintegeralways present- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) replaced.counties.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
replaced.seatsBillPendingItemSeats- A scheduled decrease of purchased seats, applied at period end, not credited; the seats stay usable until then.
replaced.seats.kind"seats"always present- Always
seats. replaced.seats.seats_purchasedintegeralways present- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) replaced.seats.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
replaced.addon_removalBillPendingItemAddonRemoval- A scheduled add-on removal, applied at period end. When the API add-on leaves, the organization's live API keys are revoked at that moment; sandbox keys stay.
replaced.addon_removal.kind"addon_removal"always present- Always
addon_removal. replaced.addon_removal.addonsarray of stringalways present- The add-ons that will be removed.
replaced.addon_removal.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
previewobjectalways present- The preview the change was decided on.
preview.currentBillStateSnapshotalways present- A billing state: plan, interval, add-ons and purchased quantities.
preview.current.plan_codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. preview.current.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. preview.current.addonsarray of stringalways present- Add-ons.
preview.current.seats_purchasednumberalways present- Purchased seats beyond the plan's included seats.
preview.current.counties_purchasednumberalways present- Paid county slots beyond the plan's included counties.
preview.targetobjectalways present- The state the request asks for (unnamed quantities at their current values).
preview.target.plan_codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. preview.target.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. preview.target.addonsarray of stringalways present- Add-ons.
preview.target.seats_purchasednumberalways present- Purchased seats beyond the plan's included seats.
preview.target.counties_purchasednumberalways present- Paid county slots beyond the plan's included counties.
preview.kind"upgrade" | "downgrade" | "mixed" | "none"always presentupgrade(only increases: applied now),downgrade(only decreases: scheduled for period end),mixed(both: the increases now at the current plan and interval, the decreases scheduled),none(no change).preview.effective"immediately" | "period_end"always presentimmediatelywhen anything applies now (upgrade or mixed), elseperiod_end(also fornone).preview.effective_atstring (date-time) or nullalways present- Now for an immediate change, else the current period end.
preview.proration_behavior"always_invoice" | "none"always presentalways_invoicewhen the change applies now: the prorated amount is invoiced and charged to the card at once.nonefor a period-end change: nothing is charged now and nothing is credited.preview.immediate_charge_centsintegeralways present- What the card is charged now, in US cents (the sum of the proration lines, never below 0); 0 for a period-end change. (at least 0)
preview.proration_linesarray of BillAmountLinealways present- The prorated lines charged now. When the API add-on is being added (term restart) these are every line of the restarted term.
preview.proration_lines[].descriptionstringalways present- The line's text as Stripe renders it (product, quantity, period).
preview.proration_lines[].amount_centsintegeralways present- Line amount in US cents; negative for a credit.
preview.proration_lines[].quantityintegeralways present- Quantity the line bills (1 for the plan and the add-on; the seat or county-slot count for those items).
preview.term_restartbooleanalways present- True when the change adds the API add-on: the WHOLE subscription restarts its term today, every item moving to the new anchor together; the new term is charged now.
preview.credit_centsinteger or nullalways present- Only when
term_restartis true: the magnitude, in US cents, of any credit lines Stripe returns for unused time (commonly 0, because Stripe nets a continuing item into one line). Null otherwise. preview.new_renewal_datestring (date-time) or nullalways present- Only when
term_restartis true: the renewal date after the restart. Null otherwise. preview.next_invoiceobjectalways present- The next renewal invoice, priced on the period-end state (what this change asks for plus what is already scheduled). Empty (
total_cents0, no lines) on a term restart, where everything is due now. preview.next_invoice.total_centsintegeralways present- Total of the next invoice in US cents.
preview.next_invoice.linesarray of BillAmountLinealways present- Its lines.
preview.next_invoice.lines[].descriptionstringalways present- The line's text as Stripe renders it (product, quantity, period).
preview.next_invoice.lines[].amount_centsintegeralways present- Line amount in US cents; negative for a credit.
preview.next_invoice.lines[].quantityintegeralways present- Quantity the line bills (1 for the plan and the add-on; the seat or county-slot count for those items).
preview.unit_prices_centsobjectalways present- Unit prices, in US cents per interval, for the target plan and interval, from the price catalog; 0 where the catalog holds no such price.
preview.unit_prices_cents.planintegeralways present- The plan price.
preview.unit_prices_cents.seatintegeralways present- One extra seat.
preview.unit_prices_cents.countyintegeralways present- One extra county slot; 0 when the plan sells none.
preview.unit_prices_cents.api_addonintegeralways present- The API add-on (0 on a monthly interval: it is sold annual only).
preview.counties_requiring_choiceobject or nullalways present- Set when the period-end county capacity is below the organization's active counties (counties already scheduled to leave are not counted): the change must then carry
surviving_fips. Null otherwise. preview.counties_requiring_choice.capacityintegeralways present- How many counties the period-end state holds (included plus paid slots).
preview.counties_requiring_choice.candidatesarray of BillCountyCandidatealways present- The active counties to choose from, in KEEP order: the first
capacityare the default choice. preview.counties_requiring_choice.candidates[].fipsstringalways present- Five-digit county FIPS code.
preview.counties_requiring_choice.candidates[].source"manual" | "state" | "msa"always present- How the county entered the active set:
manual(picked),stateormsa(added as part of a state or metro). preview.counties_requiring_choice.candidates[].added_atstring (date-time)always present- When it was added.
preview.counties_requiring_choice.candidates[].last_usedstring (date-time) or nullalways present- The organization's last data request touching this county in the past 90 days; null when none.
preview.county_slots_releasableintegeralways present- How many paid county slots the period-end state holds that the active set does not need (for example after a move to a plan with more included counties), so the customer could release them.
preview.seats_becoming_free_membersintegeralways present- How many seated members exceed the period-end seat count and would become free members.
preview.scheduledarray of BillPendingItemPlan or BillPendingItemCounties or BillPendingItemSeats or BillPendingItemAddonRemovalalways present- What is scheduled now, before this change.
preview.scheduled[].kind"plan"- Always
plan. preview.scheduled[].plan_codestring- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. preview.scheduled[].interval"month" | "year"- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. preview.scheduled[].effective_atstring (date-time) or null- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. preview.scheduled[].counties_purchasedinteger- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) preview.scheduled[].seats_purchasedinteger- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) preview.scheduled[].addonsarray of string- The add-ons that will be removed.
preview.scheduled_afterarray of BillPendingItemPlan or BillPendingItemCounties or BillPendingItemSeats or BillPendingItemAddonRemovalalways present- What this change would leave scheduled (in a mixed change, the plan move appears here).
preview.scheduled_after[].kind"plan"- Always
plan. preview.scheduled_after[].plan_codestring- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. preview.scheduled_after[].interval"month" | "year"- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. preview.scheduled_after[].effective_atstring (date-time) or null- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. preview.scheduled_after[].counties_purchasedinteger- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) preview.scheduled_after[].seats_purchasedinteger- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) preview.scheduled_after[].addonsarray of string- The add-ons that will be removed.
preview.replacesBillPendingReplacedalways present- For each scheduled item a change would replace (a second change to the same quantity), the item it replaces, keyed by its kind (
plan,counties,seats,addon_removal). An empty object when it replaces nothing. preview.replaces.planBillPendingItemPlan- A scheduled plan or interval move, applied at period end.
preview.replaces.plan.kind"plan"always present- Always
plan. preview.replaces.plan.plan_codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. preview.replaces.plan.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. preview.replaces.plan.effective_atstring (date-time) or nullalways present- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. preview.replaces.countiesBillPendingItemCounties- A scheduled decrease of the paid county-slot quantity (a slot release), applied at period end, not credited; the slots stay usable until then.
preview.replaces.counties.kind"counties"always present- Always
counties. preview.replaces.counties.counties_purchasedintegeralways present- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) preview.replaces.counties.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
preview.replaces.seatsBillPendingItemSeats- A scheduled decrease of purchased seats, applied at period end, not credited; the seats stay usable until then.
preview.replaces.seats.kind"seats"always present- Always
seats. preview.replaces.seats.seats_purchasedintegeralways present- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) preview.replaces.seats.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
preview.replaces.addon_removalBillPendingItemAddonRemoval- A scheduled add-on removal, applied at period end. When the API add-on leaves, the organization's live API keys are revoked at that moment; sandbox keys stay.
preview.replaces.addon_removal.kind"addon_removal"always present- Always
addon_removal. preview.replaces.addon_removal.addonsarray of stringalways present- The add-ons that will be removed.
preview.replaces.addon_removal.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
summaryBillSummaryalways present- The organization's billing state as Kelpie's seats-and-billing screen shows it.
summary.gateway"fake" | "test" | "live"always present- Which payment gateway this server runs:
live(Stripe live mode, production only),test(Stripe test mode) orfake(an in-process simulation used in development and tests). T153: the Stripe secret key's prefix decides betweentestandlive. summary.publishable_keystring or nullalways present- The Stripe publishable key to initialise Stripe.js and the Payment Element with.
summary.billing_mode"self_serve" | "invoiced"always presentself_serve(card subscription managed through these endpoints) orinvoiced(a contract managed by Data Tactical Group: every self-serve change answers 403contract_managed).summary.contractobject or nullalways present- The contract terms for an
invoicedorganization; null forself_serve. summary.contract.expires_atstring (date-time) or null- When the contract ends; null for no end date.
summary.contract.notesstring or null- DTG's notes on the contract.
summary.planobjectalways present- The plan the organization holds now.
summary.plan.codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. summary.plan.namestringalways present- The plan's display name (e.g. Local, Regional, National, Free).
summary.plan.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. summary.addonsarray of stringalways present- Active add-ons.
summary.seatsobjectalways present- Seats: the plan's included seats plus purchased extra seats.
summary.seats.includedintegeralways present- Seats the plan includes (the plan's allowance; see
GET /v2/plans), raised tograndfatheredwhile that is set. summary.seats.grandfatheredinteger or null- T163: an organization that had more seated members than its plan's new included count when Regional fell to 10 seats and National to 15 keeps that many included seats until its seated members fall to the plan's count or its plan changes. This is that count; null for every other organization.
summary.seats.purchasedintegeralways present- Extra seats the organization holds beyond
included. A scheduled decrease does not lower this until period end. summary.seats.billed_quantityintegeralways present- The seat quantity on the Stripe subscription (for an
invoicedorganization, the contracted extra seats; 0 with no subscription). Can differ frompurchasedbriefly while a scheduled decrease has been sent to Stripe ahead of the renewal. summary.seats.seat_price_usd_monthnumber or nullalways present- The plan's monthly price of one extra seat, in US dollars; null when the plan sells no extra seats.
summary.seats.proration"always_invoice"always present- How a seat increase is billed: always
always_invoice(prorated to the rest of the period and charged to the card at purchase). summary.seats.proration_notestringalways present- A sentence stating the seat billing rule for display.
summary.countiesobjectalways present- County slots: the plan's included counties plus paid county slots. The county SET is managed at
/v2/account/counties; this is the billing quantity behind it. summary.counties.includedintegeralways present- Counties the plan includes; -1 means every county (National).
summary.counties.purchasedintegeralways present- Paid county slots beyond
included. summary.counties.billed_quantityintegeralways present- The county-slot quantity on the Stripe subscription (for an
invoicedorganization, the contracted slots; 0 with no subscription). summary.counties.activeintegeralways present- Counties currently in the organization's active set, not counting a trial county.
summary.counties.county_price_usd_monthnumber or nullalways present- The plan's monthly price of one extra county slot, in US dollars; null when the plan sells no extra counties.
summary.counties.proration"always_invoice"always present- How a slot increase is billed: always
always_invoice(prorated and charged at purchase). summary.counties.proration_notestringalways present- A sentence stating the county-slot billing rule for display.
summary.counties.anchor_dayinteger or nullalways present- Day of the month of the organization's change window (the subscription's anchor date), on which county set changes land; null before a first subscription. (1 to 31)
summary.subscriptionobject or nullalways present- The current Stripe subscription (status active, trialing, past_due or incomplete); null when there is none (Free, or contract-managed without one).
summary.subscription.idstring- Stripe subscription id (
sub_...). summary.subscription.status"active" | "trialing" | "past_due" | "incomplete"active;trialing;past_due(a renewal was declined: L18 pauses county detail, CSV/XLSX export, live API keys and cluster editing at once, while the plan and its capacity stay held; pay withPOST /v2/account/billing/retryafter fixing the card);incomplete(the first payment has not succeeded).summary.subscription.current_period_startstring (date-time) or null- Start of the current billing period.
summary.subscription.current_period_endstring (date-time) or null- End of the current billing period: where scheduled changes and a cancellation take effect.
summary.subscription.renewal_datestring (date-time) or null- When the subscription renews (the period end); null when it is set to cancel at period end.
summary.subscription.cancel_at_period_endboolean- True when the subscription ends at
current_period_endinstead of renewing. summary.subscription.past_due_sincestring (date-time) or null- When the subscription first became past due; null when it is not past due.
summary.subscription.dunning_grace_daysinteger- Days a past-due subscription has before it is cancelled and the organization drops to Free (the downgrade composite applies). Service is paused from the decline, not from the end of this window.
summary.pending_changeBillPendingChange or nullalways present- What is scheduled for the period end; null when nothing (and no cancellation) is scheduled.
summary.pending_change.plan_codestring or null- The plan the organization moves to at period end; null when no plan move is scheduled (an interval-only move leaves this null and sets
interval). summary.pending_change.interval"month" | "year" | null- The interval the organization moves to at period end; null when no interval move is scheduled.
summary.pending_change.seats_purchasedinteger or null- The purchased seat quantity from period end; null when no seat decrease is scheduled.
summary.pending_change.counties_purchasedinteger or null- The paid county-slot quantity from period end; null when no slot release is scheduled.
summary.pending_change.remove_addonsarray of string- Add-ons removed at period end; empty when none.
summary.pending_change.cancelboolean- True when the subscription is set to cancel at period end (
POST /v2/account/billing/cancel);POST /v2/account/billing/resumeclears it and nothing else. summary.pending_change.effective_atstring (date-time)- The period end at which everything here takes effect.
summary.pending_change.changesarray of BillPendingItemPlan or BillPendingItemCounties or BillPendingItemSeats or BillPendingItemAddonRemoval- The scheduled set, one item per quantity. A cancellation is not an item here (see
cancel). summary.pending_change.changes[].kind"plan"- Always
plan. summary.pending_change.changes[].plan_codestring- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. summary.pending_change.changes[].interval"month" | "year"- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. summary.pending_change.changes[].effective_atstring (date-time) or null- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. summary.pending_change.changes[].counties_purchasedinteger- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) summary.pending_change.changes[].seats_purchasedinteger- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) summary.pending_change.changes[].addonsarray of string- The add-ons that will be removed.
summary.payment_methodBillPaymentMethod or nullalways present- The default payment method; null when none is set.
summary.payment_method.idstring- Stripe PaymentMethod id (
pm_...). summary.payment_method.brandstring- Card brand as Stripe reports it, e.g.
visa,mastercard. summary.payment_method.last4string- Last four digits of the card number.
summary.payment_method.exp_monthinteger- Card expiry month. (1 to 12)
summary.payment_method.exp_yearinteger- Card expiry year (four digits).
summary.invoicesarray of BillInvoicealways present- Up to the 12 most recent invoices, newest first.
summary.invoices[].idstringalways present- Stripe invoice id (
in_...). summary.invoices[].numberstring or nullalways present- The invoice number printed on it; null while a draft.
summary.invoices[].status"draft" | "open" | "paid" | "void" | "uncollectible"always presentopenis unpaid and collectable (a declined renewal staysopenwhile the subscription ispast_due;POST /v2/account/billing/retrypays it);paid;void;uncollectible;draftnot yet finalized.summary.invoices[].total_centsintegeralways present- Invoice total in US cents.
summary.invoices[].amount_due_centsintegeralways present- Amount still owed, in US cents.
summary.invoices[].amount_paid_centsintegeralways present- Amount paid, in US cents.
summary.invoices[].createdstring (date-time)always present- When the invoice was created.
summary.invoices[].due_datestring (date-time) or nullalways present- Due date for a
send_invoice(contract) invoice; null for card-charged invoices. summary.invoices[].periodobjectalways present- The service period the invoice covers.
summary.invoices[].period.startstring (date-time)always present- Period start.
summary.invoices[].period.endstring (date-time)always present- Period end.
summary.invoices[].hosted_invoice_urlstring (uri) or nullalways present- Stripe's hosted page for viewing and paying the invoice; null when Stripe has none.
summary.invoices[].collection_method"charge_automatically" | "send_invoice"always presentcharge_automatically(charged to the card on file: self-serve) orsend_invoice(sent for payment by its due date: contract-managed organizations).summary.invoices[].descriptionstring or nullalways present- Free-text memo on the invoice (contract invoices), else null.
summary.invoices[].linesarray of BillInvoiceLinealways present- The invoice's lines.
summary.invoices[].lines[].descriptionstringalways present- The line's text as Stripe renders it (product, quantity, period).
summary.invoices[].lines[].amount_centsintegeralways present- Line amount in US cents; negative for a credit.
summary.invoices[].lines[].quantityintegeralways present- Quantity the line bills (1 for the plan and the add-on; the seat or county-slot count for those items).
summary.invoices[].lines[].prorationbooleanalways present- True when the line is a proration (the part-period charge or credit of a mid-period change).
400 error
Bad request. Codes: annual_plan_required (as on the preview), bad_request (unknown or non-purchasable plan_code; interval not month/year; a field of the wrong type; or the surviving-county choice is missing or invalid: then the code is surviving_counties_required, with capacity and candidates, the FIPS codes to choose from, and errors[0] repeats it), malformed_json (the body is not valid JSON).
As application/problem+json.
401 error
Unauthenticated. Codes: unauthenticated (no valid API key or session); key_revoked (an API key that was revoked: revoked_at, and reason -- holder, admin, member_removed, seat_removed, api_disabled, addon_ended, account_closed, org_closed, retired, or null for a key revoked before T110 -- and a sentence saying when and why).
As application/problem+json.
403 error
Forbidden. Codes: role_required (only the owner, or a member flagged as billing contact, may manage billing; an admin only when also a billing contact; the problem carries required: [owner, billing_contact]), contract_managed (the organization is billing_mode: invoiced: its plan is managed under a contract by Data Tactical Group), no_membership (the account has no active organization), account_suspended (O56: the caller's own account is suspended by DTG), org_suspended (the organization is suspended), org_closed (the organization is closed), wrong_instance (a key of the mode this process does not serve: a sandbox key on the live API or a live key on the sandbox; base_url names the address that serves it). A sandbox key: sandbox_read_only (it may write only clusters).
As application/problem+json.
404 error
Not found. Codes: not_found (the X-DTG-Org header names an organization the caller does not belong to).
As application/problem+json.
409 error
Conflict. Codes: not_subscribed (the organization has no active subscription; use POST /v2/account/billing/subscribe), billing_in_progress (another billing change for this organization is running; the request waited 15 seconds; retry).
As application/problem+json.
413 error
Payload too large. Codes: body_too_large (the JSON body is over 16 KB; the problem carries limit_bytes).
As application/problem+json.
429 error
rate_limited (the per-minute ceiling, X-RateLimit-* say which), points_exhausted (the monthly points allowance; Retry-After to the end of the UTC month), server_busy or sandbox_busy (load; retry after Retry-After). A refused server_busy request is not metered.
As application/problem+json.
Retry-Afterheader- Seconds to wait before retrying.
X-RateLimit-Limitheader- The per-minute request ceiling that applies.
X-RateLimit-Remainingheader- Requests left in the current window.
X-RateLimit-Resetheader- Seconds until the window refills: on every answer, the time until the bucket is full again; on a refusal, until a request is allowed (as
Retry-After).
Problem codes: annual_plan_required (400), bad_request (400), surviving_counties_required (400), malformed_json (400), unauthenticated (401), key_revoked (401), account_closed (401), org_closed (401), role_required (403), contract_managed (403), no_membership (403), account_suspended (403), org_suspended (403), org_closed (403), wrong_instance (403), sandbox_read_only (403), not_found (404), not_subscribed (409), billing_in_progress (409), body_too_large (413). Every problem is a problem document.
DELETE /v2/account/billing/pending/{kind}
Withdraw one scheduled period-end change
Credentials: API key or App session. Operation id billCancelPendingChange.
Withdraws the scheduled change for one quantity. The other scheduled quantities, and a scheduled cancellation (which POST /v2/account/billing/resume withdraws), stay. Writes the audit row billing.pending_cancelled. Either credential (API key or session). Only the organization's owner or a member flagged as billing contact (an admin only when also a billing contact). Billing changes for one organization are serialized: a second one waits for the first and, after 15 seconds, answers 409 billing_in_progress.
Parameters
kindpath · "plan" | "counties" | "seats" | "addon_removal"required- Which scheduled change to withdraw:
plan,counties(a slot release),seatsoraddon_removal.
Responses
200 success
The withdrawn item and the new summary.
As application/json.
cancelledobjectalways present- The scheduled item that was withdrawn.
cancelled.kind"plan"- Always
plan. cancelled.plan_codestring- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. cancelled.interval"month" | "year"- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. cancelled.effective_atstring (date-time) or null- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. cancelled.counties_purchasedinteger- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) cancelled.seats_purchasedinteger- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) cancelled.addonsarray of string- The add-ons that will be removed.
summaryBillSummaryalways present- The organization's billing state as Kelpie's seats-and-billing screen shows it.
summary.gateway"fake" | "test" | "live"always present- Which payment gateway this server runs:
live(Stripe live mode, production only),test(Stripe test mode) orfake(an in-process simulation used in development and tests). T153: the Stripe secret key's prefix decides betweentestandlive. summary.publishable_keystring or nullalways present- The Stripe publishable key to initialise Stripe.js and the Payment Element with.
summary.billing_mode"self_serve" | "invoiced"always presentself_serve(card subscription managed through these endpoints) orinvoiced(a contract managed by Data Tactical Group: every self-serve change answers 403contract_managed).summary.contractobject or nullalways present- The contract terms for an
invoicedorganization; null forself_serve. summary.contract.expires_atstring (date-time) or null- When the contract ends; null for no end date.
summary.contract.notesstring or null- DTG's notes on the contract.
summary.planobjectalways present- The plan the organization holds now.
summary.plan.codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. summary.plan.namestringalways present- The plan's display name (e.g. Local, Regional, National, Free).
summary.plan.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. summary.addonsarray of stringalways present- Active add-ons.
summary.seatsobjectalways present- Seats: the plan's included seats plus purchased extra seats.
summary.seats.includedintegeralways present- Seats the plan includes (the plan's allowance; see
GET /v2/plans), raised tograndfatheredwhile that is set. summary.seats.grandfatheredinteger or null- T163: an organization that had more seated members than its plan's new included count when Regional fell to 10 seats and National to 15 keeps that many included seats until its seated members fall to the plan's count or its plan changes. This is that count; null for every other organization.
summary.seats.purchasedintegeralways present- Extra seats the organization holds beyond
included. A scheduled decrease does not lower this until period end. summary.seats.billed_quantityintegeralways present- The seat quantity on the Stripe subscription (for an
invoicedorganization, the contracted extra seats; 0 with no subscription). Can differ frompurchasedbriefly while a scheduled decrease has been sent to Stripe ahead of the renewal. summary.seats.seat_price_usd_monthnumber or nullalways present- The plan's monthly price of one extra seat, in US dollars; null when the plan sells no extra seats.
summary.seats.proration"always_invoice"always present- How a seat increase is billed: always
always_invoice(prorated to the rest of the period and charged to the card at purchase). summary.seats.proration_notestringalways present- A sentence stating the seat billing rule for display.
summary.countiesobjectalways present- County slots: the plan's included counties plus paid county slots. The county SET is managed at
/v2/account/counties; this is the billing quantity behind it. summary.counties.includedintegeralways present- Counties the plan includes; -1 means every county (National).
summary.counties.purchasedintegeralways present- Paid county slots beyond
included. summary.counties.billed_quantityintegeralways present- The county-slot quantity on the Stripe subscription (for an
invoicedorganization, the contracted slots; 0 with no subscription). summary.counties.activeintegeralways present- Counties currently in the organization's active set, not counting a trial county.
summary.counties.county_price_usd_monthnumber or nullalways present- The plan's monthly price of one extra county slot, in US dollars; null when the plan sells no extra counties.
summary.counties.proration"always_invoice"always present- How a slot increase is billed: always
always_invoice(prorated and charged at purchase). summary.counties.proration_notestringalways present- A sentence stating the county-slot billing rule for display.
summary.counties.anchor_dayinteger or nullalways present- Day of the month of the organization's change window (the subscription's anchor date), on which county set changes land; null before a first subscription. (1 to 31)
summary.subscriptionobject or nullalways present- The current Stripe subscription (status active, trialing, past_due or incomplete); null when there is none (Free, or contract-managed without one).
summary.subscription.idstring- Stripe subscription id (
sub_...). summary.subscription.status"active" | "trialing" | "past_due" | "incomplete"active;trialing;past_due(a renewal was declined: L18 pauses county detail, CSV/XLSX export, live API keys and cluster editing at once, while the plan and its capacity stay held; pay withPOST /v2/account/billing/retryafter fixing the card);incomplete(the first payment has not succeeded).summary.subscription.current_period_startstring (date-time) or null- Start of the current billing period.
summary.subscription.current_period_endstring (date-time) or null- End of the current billing period: where scheduled changes and a cancellation take effect.
summary.subscription.renewal_datestring (date-time) or null- When the subscription renews (the period end); null when it is set to cancel at period end.
summary.subscription.cancel_at_period_endboolean- True when the subscription ends at
current_period_endinstead of renewing. summary.subscription.past_due_sincestring (date-time) or null- When the subscription first became past due; null when it is not past due.
summary.subscription.dunning_grace_daysinteger- Days a past-due subscription has before it is cancelled and the organization drops to Free (the downgrade composite applies). Service is paused from the decline, not from the end of this window.
summary.pending_changeBillPendingChange or nullalways present- What is scheduled for the period end; null when nothing (and no cancellation) is scheduled.
summary.pending_change.plan_codestring or null- The plan the organization moves to at period end; null when no plan move is scheduled (an interval-only move leaves this null and sets
interval). summary.pending_change.interval"month" | "year" | null- The interval the organization moves to at period end; null when no interval move is scheduled.
summary.pending_change.seats_purchasedinteger or null- The purchased seat quantity from period end; null when no seat decrease is scheduled.
summary.pending_change.counties_purchasedinteger or null- The paid county-slot quantity from period end; null when no slot release is scheduled.
summary.pending_change.remove_addonsarray of string- Add-ons removed at period end; empty when none.
summary.pending_change.cancelboolean- True when the subscription is set to cancel at period end (
POST /v2/account/billing/cancel);POST /v2/account/billing/resumeclears it and nothing else. summary.pending_change.effective_atstring (date-time)- The period end at which everything here takes effect.
summary.pending_change.changesarray of BillPendingItemPlan or BillPendingItemCounties or BillPendingItemSeats or BillPendingItemAddonRemoval- The scheduled set, one item per quantity. A cancellation is not an item here (see
cancel). summary.pending_change.changes[].kind"plan"- Always
plan. summary.pending_change.changes[].plan_codestring- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. summary.pending_change.changes[].interval"month" | "year"- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. summary.pending_change.changes[].effective_atstring (date-time) or null- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. summary.pending_change.changes[].counties_purchasedinteger- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) summary.pending_change.changes[].seats_purchasedinteger- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) summary.pending_change.changes[].addonsarray of string- The add-ons that will be removed.
summary.payment_methodBillPaymentMethod or nullalways present- The default payment method; null when none is set.
summary.payment_method.idstring- Stripe PaymentMethod id (
pm_...). summary.payment_method.brandstring- Card brand as Stripe reports it, e.g.
visa,mastercard. summary.payment_method.last4string- Last four digits of the card number.
summary.payment_method.exp_monthinteger- Card expiry month. (1 to 12)
summary.payment_method.exp_yearinteger- Card expiry year (four digits).
summary.invoicesarray of BillInvoicealways present- Up to the 12 most recent invoices, newest first.
summary.invoices[].idstringalways present- Stripe invoice id (
in_...). summary.invoices[].numberstring or nullalways present- The invoice number printed on it; null while a draft.
summary.invoices[].status"draft" | "open" | "paid" | "void" | "uncollectible"always presentopenis unpaid and collectable (a declined renewal staysopenwhile the subscription ispast_due;POST /v2/account/billing/retrypays it);paid;void;uncollectible;draftnot yet finalized.summary.invoices[].total_centsintegeralways present- Invoice total in US cents.
summary.invoices[].amount_due_centsintegeralways present- Amount still owed, in US cents.
summary.invoices[].amount_paid_centsintegeralways present- Amount paid, in US cents.
summary.invoices[].createdstring (date-time)always present- When the invoice was created.
summary.invoices[].due_datestring (date-time) or nullalways present- Due date for a
send_invoice(contract) invoice; null for card-charged invoices. summary.invoices[].periodobjectalways present- The service period the invoice covers.
summary.invoices[].period.startstring (date-time)always present- Period start.
summary.invoices[].period.endstring (date-time)always present- Period end.
summary.invoices[].hosted_invoice_urlstring (uri) or nullalways present- Stripe's hosted page for viewing and paying the invoice; null when Stripe has none.
summary.invoices[].collection_method"charge_automatically" | "send_invoice"always presentcharge_automatically(charged to the card on file: self-serve) orsend_invoice(sent for payment by its due date: contract-managed organizations).summary.invoices[].descriptionstring or nullalways present- Free-text memo on the invoice (contract invoices), else null.
summary.invoices[].linesarray of BillInvoiceLinealways present- The invoice's lines.
summary.invoices[].lines[].descriptionstringalways present- The line's text as Stripe renders it (product, quantity, period).
summary.invoices[].lines[].amount_centsintegeralways present- Line amount in US cents; negative for a credit.
summary.invoices[].lines[].quantityintegeralways present- Quantity the line bills (1 for the plan and the add-on; the seat or county-slot count for those items).
summary.invoices[].lines[].prorationbooleanalways present- True when the line is a proration (the part-period charge or credit of a mid-period change).
401 error
Unauthenticated. Codes: unauthenticated (no valid API key or session); key_revoked (an API key that was revoked: revoked_at, and reason -- holder, admin, member_removed, seat_removed, api_disabled, addon_ended, account_closed, org_closed, retired, or null for a key revoked before T110 -- and a sentence saying when and why).
As application/problem+json.
403 error
Forbidden. Codes: role_required (only the owner, or a member flagged as billing contact, may manage billing; an admin only when also a billing contact; the problem carries required: [owner, billing_contact]), contract_managed (the organization is billing_mode: invoiced: its plan is managed under a contract by Data Tactical Group), no_membership (the account has no active organization), account_suspended (O56: the caller's own account is suspended by DTG), org_suspended (the organization is suspended), org_closed (the organization is closed), wrong_instance (a key of the mode this process does not serve: a sandbox key on the live API or a live key on the sandbox; base_url names the address that serves it). A sandbox key: sandbox_read_only (it may write only clusters).
As application/problem+json.
404 error
Not found. Codes: not_found (kind is not one of plan, counties, seats, addon_removal), not_found (the X-DTG-Org header names an organization the caller does not belong to).
As application/problem+json.
409 error
Conflict. Codes: nothing_scheduled (nothing is scheduled for that quantity; the problem carries kind), billing_in_progress (another billing change for this organization is running; the request waited 15 seconds; retry).
As application/problem+json.
429 error
rate_limited (the per-minute ceiling, X-RateLimit-* say which), points_exhausted (the monthly points allowance; Retry-After to the end of the UTC month), server_busy or sandbox_busy (load; retry after Retry-After). A refused server_busy request is not metered.
As application/problem+json.
Retry-Afterheader- Seconds to wait before retrying.
X-RateLimit-Limitheader- The per-minute request ceiling that applies.
X-RateLimit-Remainingheader- Requests left in the current window.
X-RateLimit-Resetheader- Seconds until the window refills: on every answer, the time until the bucket is full again; on a refusal, until a request is allowed (as
Retry-After).
Problem codes: unauthenticated (401), key_revoked (401), account_closed (401), org_closed (401), role_required (403), contract_managed (403), no_membership (403), account_suspended (403), org_suspended (403), org_closed (403), wrong_instance (403), sandbox_read_only (403), not_found (404), nothing_scheduled (409), billing_in_progress (409). Every problem is a problem document.
POST /v2/account/billing/cancel
Cancel the subscription at period end
Credentials: API key or App session. Operation id billCancelAtPeriodEnd.
Sets the subscription to end at the current period end instead of renewing; the organization keeps everything until then and then drops to Free. Nothing is credited. Undo with POST /v2/account/billing/resume. No request body. Writes the audit row billing.cancelled. Either credential (API key or session). Only the organization's owner or a member flagged as billing contact (an admin only when also a billing contact). Billing changes for one organization are serialized: a second one waits for the first and, after 15 seconds, answers 409 billing_in_progress.
Responses
200 success
The billing summary after the change (subscription.cancel_at_period_end true, pending_change.cancel true).
As application/json.
gateway"fake" | "test" | "live"always present- Which payment gateway this server runs:
live(Stripe live mode, production only),test(Stripe test mode) orfake(an in-process simulation used in development and tests). T153: the Stripe secret key's prefix decides betweentestandlive. publishable_keystring or nullalways present- The Stripe publishable key to initialise Stripe.js and the Payment Element with.
billing_mode"self_serve" | "invoiced"always presentself_serve(card subscription managed through these endpoints) orinvoiced(a contract managed by Data Tactical Group: every self-serve change answers 403contract_managed).contractobject or nullalways present- The contract terms for an
invoicedorganization; null forself_serve. contract.expires_atstring (date-time) or null- When the contract ends; null for no end date.
contract.notesstring or null- DTG's notes on the contract.
planobjectalways present- The plan the organization holds now.
plan.codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. plan.namestringalways present- The plan's display name (e.g. Local, Regional, National, Free).
plan.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. addonsarray of stringalways present- Active add-ons.
seatsobjectalways present- Seats: the plan's included seats plus purchased extra seats.
seats.includedintegeralways present- Seats the plan includes (the plan's allowance; see
GET /v2/plans), raised tograndfatheredwhile that is set. seats.grandfatheredinteger or null- T163: an organization that had more seated members than its plan's new included count when Regional fell to 10 seats and National to 15 keeps that many included seats until its seated members fall to the plan's count or its plan changes. This is that count; null for every other organization.
seats.purchasedintegeralways present- Extra seats the organization holds beyond
included. A scheduled decrease does not lower this until period end. seats.billed_quantityintegeralways present- The seat quantity on the Stripe subscription (for an
invoicedorganization, the contracted extra seats; 0 with no subscription). Can differ frompurchasedbriefly while a scheduled decrease has been sent to Stripe ahead of the renewal. seats.seat_price_usd_monthnumber or nullalways present- The plan's monthly price of one extra seat, in US dollars; null when the plan sells no extra seats.
seats.proration"always_invoice"always present- How a seat increase is billed: always
always_invoice(prorated to the rest of the period and charged to the card at purchase). seats.proration_notestringalways present- A sentence stating the seat billing rule for display.
countiesobjectalways present- County slots: the plan's included counties plus paid county slots. The county SET is managed at
/v2/account/counties; this is the billing quantity behind it. counties.includedintegeralways present- Counties the plan includes; -1 means every county (National).
counties.purchasedintegeralways present- Paid county slots beyond
included. counties.billed_quantityintegeralways present- The county-slot quantity on the Stripe subscription (for an
invoicedorganization, the contracted slots; 0 with no subscription). counties.activeintegeralways present- Counties currently in the organization's active set, not counting a trial county.
counties.county_price_usd_monthnumber or nullalways present- The plan's monthly price of one extra county slot, in US dollars; null when the plan sells no extra counties.
counties.proration"always_invoice"always present- How a slot increase is billed: always
always_invoice(prorated and charged at purchase). counties.proration_notestringalways present- A sentence stating the county-slot billing rule for display.
counties.anchor_dayinteger or nullalways present- Day of the month of the organization's change window (the subscription's anchor date), on which county set changes land; null before a first subscription. (1 to 31)
subscriptionobject or nullalways present- The current Stripe subscription (status active, trialing, past_due or incomplete); null when there is none (Free, or contract-managed without one).
subscription.idstring- Stripe subscription id (
sub_...). subscription.status"active" | "trialing" | "past_due" | "incomplete"active;trialing;past_due(a renewal was declined: L18 pauses county detail, CSV/XLSX export, live API keys and cluster editing at once, while the plan and its capacity stay held; pay withPOST /v2/account/billing/retryafter fixing the card);incomplete(the first payment has not succeeded).subscription.current_period_startstring (date-time) or null- Start of the current billing period.
subscription.current_period_endstring (date-time) or null- End of the current billing period: where scheduled changes and a cancellation take effect.
subscription.renewal_datestring (date-time) or null- When the subscription renews (the period end); null when it is set to cancel at period end.
subscription.cancel_at_period_endboolean- True when the subscription ends at
current_period_endinstead of renewing. subscription.past_due_sincestring (date-time) or null- When the subscription first became past due; null when it is not past due.
subscription.dunning_grace_daysinteger- Days a past-due subscription has before it is cancelled and the organization drops to Free (the downgrade composite applies). Service is paused from the decline, not from the end of this window.
pending_changeBillPendingChange or nullalways present- What is scheduled for the period end; null when nothing (and no cancellation) is scheduled.
pending_change.plan_codestring or null- The plan the organization moves to at period end; null when no plan move is scheduled (an interval-only move leaves this null and sets
interval). pending_change.interval"month" | "year" | null- The interval the organization moves to at period end; null when no interval move is scheduled.
pending_change.seats_purchasedinteger or null- The purchased seat quantity from period end; null when no seat decrease is scheduled.
pending_change.counties_purchasedinteger or null- The paid county-slot quantity from period end; null when no slot release is scheduled.
pending_change.remove_addonsarray of string- Add-ons removed at period end; empty when none.
pending_change.cancelboolean- True when the subscription is set to cancel at period end (
POST /v2/account/billing/cancel);POST /v2/account/billing/resumeclears it and nothing else. pending_change.effective_atstring (date-time)- The period end at which everything here takes effect.
pending_change.changesarray of BillPendingItemPlan or BillPendingItemCounties or BillPendingItemSeats or BillPendingItemAddonRemoval- The scheduled set, one item per quantity. A cancellation is not an item here (see
cancel). pending_change.changes[].kind"plan"- Always
plan. pending_change.changes[].plan_codestring- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. pending_change.changes[].interval"month" | "year"- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. pending_change.changes[].effective_atstring (date-time) or null- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. pending_change.changes[].counties_purchasedinteger- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) pending_change.changes[].seats_purchasedinteger- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) pending_change.changes[].addonsarray of string- The add-ons that will be removed.
payment_methodBillPaymentMethod or nullalways present- The default payment method; null when none is set.
payment_method.idstring- Stripe PaymentMethod id (
pm_...). payment_method.brandstring- Card brand as Stripe reports it, e.g.
visa,mastercard. payment_method.last4string- Last four digits of the card number.
payment_method.exp_monthinteger- Card expiry month. (1 to 12)
payment_method.exp_yearinteger- Card expiry year (four digits).
invoicesarray of BillInvoicealways present- Up to the 12 most recent invoices, newest first.
invoices[].idstringalways present- Stripe invoice id (
in_...). invoices[].numberstring or nullalways present- The invoice number printed on it; null while a draft.
invoices[].status"draft" | "open" | "paid" | "void" | "uncollectible"always presentopenis unpaid and collectable (a declined renewal staysopenwhile the subscription ispast_due;POST /v2/account/billing/retrypays it);paid;void;uncollectible;draftnot yet finalized.invoices[].total_centsintegeralways present- Invoice total in US cents.
invoices[].amount_due_centsintegeralways present- Amount still owed, in US cents.
invoices[].amount_paid_centsintegeralways present- Amount paid, in US cents.
invoices[].createdstring (date-time)always present- When the invoice was created.
invoices[].due_datestring (date-time) or nullalways present- Due date for a
send_invoice(contract) invoice; null for card-charged invoices. invoices[].periodobjectalways present- The service period the invoice covers.
invoices[].period.startstring (date-time)always present- Period start.
invoices[].period.endstring (date-time)always present- Period end.
invoices[].hosted_invoice_urlstring (uri) or nullalways present- Stripe's hosted page for viewing and paying the invoice; null when Stripe has none.
invoices[].collection_method"charge_automatically" | "send_invoice"always presentcharge_automatically(charged to the card on file: self-serve) orsend_invoice(sent for payment by its due date: contract-managed organizations).invoices[].descriptionstring or nullalways present- Free-text memo on the invoice (contract invoices), else null.
invoices[].linesarray of BillInvoiceLinealways present- The invoice's lines.
invoices[].lines[].descriptionstringalways present- The line's text as Stripe renders it (product, quantity, period).
invoices[].lines[].amount_centsintegeralways present- Line amount in US cents; negative for a credit.
invoices[].lines[].quantityintegeralways present- Quantity the line bills (1 for the plan and the add-on; the seat or county-slot count for those items).
invoices[].lines[].prorationbooleanalways present- True when the line is a proration (the part-period charge or credit of a mid-period change).
401 error
Unauthenticated. Codes: unauthenticated (no valid API key or session); key_revoked (an API key that was revoked: revoked_at, and reason -- holder, admin, member_removed, seat_removed, api_disabled, addon_ended, account_closed, org_closed, retired, or null for a key revoked before T110 -- and a sentence saying when and why).
As application/problem+json.
403 error
Forbidden. Codes: role_required (only the owner, or a member flagged as billing contact, may manage billing; an admin only when also a billing contact; the problem carries required: [owner, billing_contact]), contract_managed (the organization is billing_mode: invoiced: its plan is managed under a contract by Data Tactical Group), no_membership (the account has no active organization), account_suspended (O56: the caller's own account is suspended by DTG), org_suspended (the organization is suspended), org_closed (the organization is closed), wrong_instance (a key of the mode this process does not serve: a sandbox key on the live API or a live key on the sandbox; base_url names the address that serves it). A sandbox key: sandbox_read_only (it may write only clusters).
As application/problem+json.
404 error
Not found. Codes: not_found (the X-DTG-Org header names an organization the caller does not belong to).
As application/problem+json.
409 error
Conflict. Codes: not_subscribed (the organization has no active subscription; use POST /v2/account/billing/subscribe), billing_in_progress (another billing change for this organization is running; the request waited 15 seconds; retry).
As application/problem+json.
429 error
rate_limited (the per-minute ceiling, X-RateLimit-* say which), points_exhausted (the monthly points allowance; Retry-After to the end of the UTC month), server_busy or sandbox_busy (load; retry after Retry-After). A refused server_busy request is not metered.
As application/problem+json.
Retry-Afterheader- Seconds to wait before retrying.
X-RateLimit-Limitheader- The per-minute request ceiling that applies.
X-RateLimit-Remainingheader- Requests left in the current window.
X-RateLimit-Resetheader- Seconds until the window refills: on every answer, the time until the bucket is full again; on a refusal, until a request is allowed (as
Retry-After).
Problem codes: unauthenticated (401), key_revoked (401), account_closed (401), org_closed (401), role_required (403), contract_managed (403), no_membership (403), account_suspended (403), org_suspended (403), org_closed (403), wrong_instance (403), sandbox_read_only (403), not_found (404), not_subscribed (409), billing_in_progress (409). Every problem is a problem document.
POST /v2/account/billing/resume
Withdraw a scheduled cancellation
Credentials: API key or App session. Operation id billResume.
Ends a scheduled cancellation so the subscription renews. Touches no other scheduled change or its date. No request body. Writes the audit row billing.resumed. Either credential (API key or session). Only the organization's owner or a member flagged as billing contact (an admin only when also a billing contact). Billing changes for one organization are serialized: a second one waits for the first and, after 15 seconds, answers 409 billing_in_progress.
Responses
200 success
The billing summary after the change.
As application/json.
gateway"fake" | "test" | "live"always present- Which payment gateway this server runs:
live(Stripe live mode, production only),test(Stripe test mode) orfake(an in-process simulation used in development and tests). T153: the Stripe secret key's prefix decides betweentestandlive. publishable_keystring or nullalways present- The Stripe publishable key to initialise Stripe.js and the Payment Element with.
billing_mode"self_serve" | "invoiced"always presentself_serve(card subscription managed through these endpoints) orinvoiced(a contract managed by Data Tactical Group: every self-serve change answers 403contract_managed).contractobject or nullalways present- The contract terms for an
invoicedorganization; null forself_serve. contract.expires_atstring (date-time) or null- When the contract ends; null for no end date.
contract.notesstring or null- DTG's notes on the contract.
planobjectalways present- The plan the organization holds now.
plan.codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. plan.namestringalways present- The plan's display name (e.g. Local, Regional, National, Free).
plan.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. addonsarray of stringalways present- Active add-ons.
seatsobjectalways present- Seats: the plan's included seats plus purchased extra seats.
seats.includedintegeralways present- Seats the plan includes (the plan's allowance; see
GET /v2/plans), raised tograndfatheredwhile that is set. seats.grandfatheredinteger or null- T163: an organization that had more seated members than its plan's new included count when Regional fell to 10 seats and National to 15 keeps that many included seats until its seated members fall to the plan's count or its plan changes. This is that count; null for every other organization.
seats.purchasedintegeralways present- Extra seats the organization holds beyond
included. A scheduled decrease does not lower this until period end. seats.billed_quantityintegeralways present- The seat quantity on the Stripe subscription (for an
invoicedorganization, the contracted extra seats; 0 with no subscription). Can differ frompurchasedbriefly while a scheduled decrease has been sent to Stripe ahead of the renewal. seats.seat_price_usd_monthnumber or nullalways present- The plan's monthly price of one extra seat, in US dollars; null when the plan sells no extra seats.
seats.proration"always_invoice"always present- How a seat increase is billed: always
always_invoice(prorated to the rest of the period and charged to the card at purchase). seats.proration_notestringalways present- A sentence stating the seat billing rule for display.
countiesobjectalways present- County slots: the plan's included counties plus paid county slots. The county SET is managed at
/v2/account/counties; this is the billing quantity behind it. counties.includedintegeralways present- Counties the plan includes; -1 means every county (National).
counties.purchasedintegeralways present- Paid county slots beyond
included. counties.billed_quantityintegeralways present- The county-slot quantity on the Stripe subscription (for an
invoicedorganization, the contracted slots; 0 with no subscription). counties.activeintegeralways present- Counties currently in the organization's active set, not counting a trial county.
counties.county_price_usd_monthnumber or nullalways present- The plan's monthly price of one extra county slot, in US dollars; null when the plan sells no extra counties.
counties.proration"always_invoice"always present- How a slot increase is billed: always
always_invoice(prorated and charged at purchase). counties.proration_notestringalways present- A sentence stating the county-slot billing rule for display.
counties.anchor_dayinteger or nullalways present- Day of the month of the organization's change window (the subscription's anchor date), on which county set changes land; null before a first subscription. (1 to 31)
subscriptionobject or nullalways present- The current Stripe subscription (status active, trialing, past_due or incomplete); null when there is none (Free, or contract-managed without one).
subscription.idstring- Stripe subscription id (
sub_...). subscription.status"active" | "trialing" | "past_due" | "incomplete"active;trialing;past_due(a renewal was declined: L18 pauses county detail, CSV/XLSX export, live API keys and cluster editing at once, while the plan and its capacity stay held; pay withPOST /v2/account/billing/retryafter fixing the card);incomplete(the first payment has not succeeded).subscription.current_period_startstring (date-time) or null- Start of the current billing period.
subscription.current_period_endstring (date-time) or null- End of the current billing period: where scheduled changes and a cancellation take effect.
subscription.renewal_datestring (date-time) or null- When the subscription renews (the period end); null when it is set to cancel at period end.
subscription.cancel_at_period_endboolean- True when the subscription ends at
current_period_endinstead of renewing. subscription.past_due_sincestring (date-time) or null- When the subscription first became past due; null when it is not past due.
subscription.dunning_grace_daysinteger- Days a past-due subscription has before it is cancelled and the organization drops to Free (the downgrade composite applies). Service is paused from the decline, not from the end of this window.
pending_changeBillPendingChange or nullalways present- What is scheduled for the period end; null when nothing (and no cancellation) is scheduled.
pending_change.plan_codestring or null- The plan the organization moves to at period end; null when no plan move is scheduled (an interval-only move leaves this null and sets
interval). pending_change.interval"month" | "year" | null- The interval the organization moves to at period end; null when no interval move is scheduled.
pending_change.seats_purchasedinteger or null- The purchased seat quantity from period end; null when no seat decrease is scheduled.
pending_change.counties_purchasedinteger or null- The paid county-slot quantity from period end; null when no slot release is scheduled.
pending_change.remove_addonsarray of string- Add-ons removed at period end; empty when none.
pending_change.cancelboolean- True when the subscription is set to cancel at period end (
POST /v2/account/billing/cancel);POST /v2/account/billing/resumeclears it and nothing else. pending_change.effective_atstring (date-time)- The period end at which everything here takes effect.
pending_change.changesarray of BillPendingItemPlan or BillPendingItemCounties or BillPendingItemSeats or BillPendingItemAddonRemoval- The scheduled set, one item per quantity. A cancellation is not an item here (see
cancel). pending_change.changes[].kind"plan"- Always
plan. pending_change.changes[].plan_codestring- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. pending_change.changes[].interval"month" | "year"- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. pending_change.changes[].effective_atstring (date-time) or null- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. pending_change.changes[].counties_purchasedinteger- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) pending_change.changes[].seats_purchasedinteger- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) pending_change.changes[].addonsarray of string- The add-ons that will be removed.
payment_methodBillPaymentMethod or nullalways present- The default payment method; null when none is set.
payment_method.idstring- Stripe PaymentMethod id (
pm_...). payment_method.brandstring- Card brand as Stripe reports it, e.g.
visa,mastercard. payment_method.last4string- Last four digits of the card number.
payment_method.exp_monthinteger- Card expiry month. (1 to 12)
payment_method.exp_yearinteger- Card expiry year (four digits).
invoicesarray of BillInvoicealways present- Up to the 12 most recent invoices, newest first.
invoices[].idstringalways present- Stripe invoice id (
in_...). invoices[].numberstring or nullalways present- The invoice number printed on it; null while a draft.
invoices[].status"draft" | "open" | "paid" | "void" | "uncollectible"always presentopenis unpaid and collectable (a declined renewal staysopenwhile the subscription ispast_due;POST /v2/account/billing/retrypays it);paid;void;uncollectible;draftnot yet finalized.invoices[].total_centsintegeralways present- Invoice total in US cents.
invoices[].amount_due_centsintegeralways present- Amount still owed, in US cents.
invoices[].amount_paid_centsintegeralways present- Amount paid, in US cents.
invoices[].createdstring (date-time)always present- When the invoice was created.
invoices[].due_datestring (date-time) or nullalways present- Due date for a
send_invoice(contract) invoice; null for card-charged invoices. invoices[].periodobjectalways present- The service period the invoice covers.
invoices[].period.startstring (date-time)always present- Period start.
invoices[].period.endstring (date-time)always present- Period end.
invoices[].hosted_invoice_urlstring (uri) or nullalways present- Stripe's hosted page for viewing and paying the invoice; null when Stripe has none.
invoices[].collection_method"charge_automatically" | "send_invoice"always presentcharge_automatically(charged to the card on file: self-serve) orsend_invoice(sent for payment by its due date: contract-managed organizations).invoices[].descriptionstring or nullalways present- Free-text memo on the invoice (contract invoices), else null.
invoices[].linesarray of BillInvoiceLinealways present- The invoice's lines.
invoices[].lines[].descriptionstringalways present- The line's text as Stripe renders it (product, quantity, period).
invoices[].lines[].amount_centsintegeralways present- Line amount in US cents; negative for a credit.
invoices[].lines[].quantityintegeralways present- Quantity the line bills (1 for the plan and the add-on; the seat or county-slot count for those items).
invoices[].lines[].prorationbooleanalways present- True when the line is a proration (the part-period charge or credit of a mid-period change).
401 error
Unauthenticated. Codes: unauthenticated (no valid API key or session); key_revoked (an API key that was revoked: revoked_at, and reason -- holder, admin, member_removed, seat_removed, api_disabled, addon_ended, account_closed, org_closed, retired, or null for a key revoked before T110 -- and a sentence saying when and why).
As application/problem+json.
403 error
Forbidden. Codes: role_required (only the owner, or a member flagged as billing contact, may manage billing; an admin only when also a billing contact; the problem carries required: [owner, billing_contact]), contract_managed (the organization is billing_mode: invoiced: its plan is managed under a contract by Data Tactical Group), no_membership (the account has no active organization), account_suspended (O56: the caller's own account is suspended by DTG), org_suspended (the organization is suspended), org_closed (the organization is closed), wrong_instance (a key of the mode this process does not serve: a sandbox key on the live API or a live key on the sandbox; base_url names the address that serves it). A sandbox key: sandbox_read_only (it may write only clusters).
As application/problem+json.
404 error
Not found. Codes: not_found (the X-DTG-Org header names an organization the caller does not belong to).
As application/problem+json.
409 error
Conflict. Codes: not_subscribed (the organization has no active subscription; use POST /v2/account/billing/subscribe), billing_in_progress (another billing change for this organization is running; the request waited 15 seconds; retry).
As application/problem+json.
429 error
rate_limited (the per-minute ceiling, X-RateLimit-* say which), points_exhausted (the monthly points allowance; Retry-After to the end of the UTC month), server_busy or sandbox_busy (load; retry after Retry-After). A refused server_busy request is not metered.
As application/problem+json.
Retry-Afterheader- Seconds to wait before retrying.
X-RateLimit-Limitheader- The per-minute request ceiling that applies.
X-RateLimit-Remainingheader- Requests left in the current window.
X-RateLimit-Resetheader- Seconds until the window refills: on every answer, the time until the bucket is full again; on a refusal, until a request is allowed (as
Retry-After).
Problem codes: unauthenticated (401), key_revoked (401), account_closed (401), org_closed (401), role_required (403), contract_managed (403), no_membership (403), account_suspended (403), org_suspended (403), org_closed (403), wrong_instance (403), sandbox_read_only (403), not_found (404), not_subscribed (409), billing_in_progress (409). Every problem is a problem document.
POST /v2/account/billing/retry
Pay the open invoice now
Credentials: API key or App session. Operation id billRetryInvoice.
Pays the latest open, card-charged invoice of the current subscription against the default payment method now, instead of waiting for Stripe's retry schedule. A success brings the subscription out of past_due in this response, which lifts L18's pause at once. A decline is a 200 with paid: false and the subscription still past_due. No request body. Writes the audit row billing.retried (invoice, paid, amount due). Either credential (API key or session). Only the organization's owner or a member flagged as billing contact (an admin only when also a billing contact). Billing changes for one organization are serialized: a second one waits for the first and, after 15 seconds, answers 409 billing_in_progress.
Responses
200 success
The payment attempt's outcome.
As application/json.
paidbooleanalways present- True when the invoice is now paid. A decline is not an error:
paidis false and the subscription stayspast_due. invoiceBillInvoicealways present- A Stripe invoice for the organization.
invoice.idstringalways present- Stripe invoice id (
in_...). invoice.numberstring or nullalways present- The invoice number printed on it; null while a draft.
invoice.status"draft" | "open" | "paid" | "void" | "uncollectible"always presentopenis unpaid and collectable (a declined renewal staysopenwhile the subscription ispast_due;POST /v2/account/billing/retrypays it);paid;void;uncollectible;draftnot yet finalized.invoice.total_centsintegeralways present- Invoice total in US cents.
invoice.amount_due_centsintegeralways present- Amount still owed, in US cents.
invoice.amount_paid_centsintegeralways present- Amount paid, in US cents.
invoice.createdstring (date-time)always present- When the invoice was created.
invoice.due_datestring (date-time) or nullalways present- Due date for a
send_invoice(contract) invoice; null for card-charged invoices. invoice.periodobjectalways present- The service period the invoice covers.
invoice.period.startstring (date-time)always present- Period start.
invoice.period.endstring (date-time)always present- Period end.
invoice.hosted_invoice_urlstring (uri) or nullalways present- Stripe's hosted page for viewing and paying the invoice; null when Stripe has none.
invoice.collection_method"charge_automatically" | "send_invoice"always presentcharge_automatically(charged to the card on file: self-serve) orsend_invoice(sent for payment by its due date: contract-managed organizations).invoice.descriptionstring or nullalways present- Free-text memo on the invoice (contract invoices), else null.
invoice.linesarray of BillInvoiceLinealways present- The invoice's lines.
invoice.lines[].descriptionstringalways present- The line's text as Stripe renders it (product, quantity, period).
invoice.lines[].amount_centsintegeralways present- Line amount in US cents; negative for a credit.
invoice.lines[].quantityintegeralways present- Quantity the line bills (1 for the plan and the add-on; the seat or county-slot count for those items).
invoice.lines[].prorationbooleanalways present- True when the line is a proration (the part-period charge or credit of a mid-period change).
summaryBillSummaryalways present- The organization's billing state as Kelpie's seats-and-billing screen shows it.
summary.gateway"fake" | "test" | "live"always present- Which payment gateway this server runs:
live(Stripe live mode, production only),test(Stripe test mode) orfake(an in-process simulation used in development and tests). T153: the Stripe secret key's prefix decides betweentestandlive. summary.publishable_keystring or nullalways present- The Stripe publishable key to initialise Stripe.js and the Payment Element with.
summary.billing_mode"self_serve" | "invoiced"always presentself_serve(card subscription managed through these endpoints) orinvoiced(a contract managed by Data Tactical Group: every self-serve change answers 403contract_managed).summary.contractobject or nullalways present- The contract terms for an
invoicedorganization; null forself_serve. summary.contract.expires_atstring (date-time) or null- When the contract ends; null for no end date.
summary.contract.notesstring or null- DTG's notes on the contract.
summary.planobjectalways present- The plan the organization holds now.
summary.plan.codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. summary.plan.namestringalways present- The plan's display name (e.g. Local, Regional, National, Free).
summary.plan.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. summary.addonsarray of stringalways present- Active add-ons.
summary.seatsobjectalways present- Seats: the plan's included seats plus purchased extra seats.
summary.seats.includedintegeralways present- Seats the plan includes (the plan's allowance; see
GET /v2/plans), raised tograndfatheredwhile that is set. summary.seats.grandfatheredinteger or null- T163: an organization that had more seated members than its plan's new included count when Regional fell to 10 seats and National to 15 keeps that many included seats until its seated members fall to the plan's count or its plan changes. This is that count; null for every other organization.
summary.seats.purchasedintegeralways present- Extra seats the organization holds beyond
included. A scheduled decrease does not lower this until period end. summary.seats.billed_quantityintegeralways present- The seat quantity on the Stripe subscription (for an
invoicedorganization, the contracted extra seats; 0 with no subscription). Can differ frompurchasedbriefly while a scheduled decrease has been sent to Stripe ahead of the renewal. summary.seats.seat_price_usd_monthnumber or nullalways present- The plan's monthly price of one extra seat, in US dollars; null when the plan sells no extra seats.
summary.seats.proration"always_invoice"always present- How a seat increase is billed: always
always_invoice(prorated to the rest of the period and charged to the card at purchase). summary.seats.proration_notestringalways present- A sentence stating the seat billing rule for display.
summary.countiesobjectalways present- County slots: the plan's included counties plus paid county slots. The county SET is managed at
/v2/account/counties; this is the billing quantity behind it. summary.counties.includedintegeralways present- Counties the plan includes; -1 means every county (National).
summary.counties.purchasedintegeralways present- Paid county slots beyond
included. summary.counties.billed_quantityintegeralways present- The county-slot quantity on the Stripe subscription (for an
invoicedorganization, the contracted slots; 0 with no subscription). summary.counties.activeintegeralways present- Counties currently in the organization's active set, not counting a trial county.
summary.counties.county_price_usd_monthnumber or nullalways present- The plan's monthly price of one extra county slot, in US dollars; null when the plan sells no extra counties.
summary.counties.proration"always_invoice"always present- How a slot increase is billed: always
always_invoice(prorated and charged at purchase). summary.counties.proration_notestringalways present- A sentence stating the county-slot billing rule for display.
summary.counties.anchor_dayinteger or nullalways present- Day of the month of the organization's change window (the subscription's anchor date), on which county set changes land; null before a first subscription. (1 to 31)
summary.subscriptionobject or nullalways present- The current Stripe subscription (status active, trialing, past_due or incomplete); null when there is none (Free, or contract-managed without one).
summary.subscription.idstring- Stripe subscription id (
sub_...). summary.subscription.status"active" | "trialing" | "past_due" | "incomplete"active;trialing;past_due(a renewal was declined: L18 pauses county detail, CSV/XLSX export, live API keys and cluster editing at once, while the plan and its capacity stay held; pay withPOST /v2/account/billing/retryafter fixing the card);incomplete(the first payment has not succeeded).summary.subscription.current_period_startstring (date-time) or null- Start of the current billing period.
summary.subscription.current_period_endstring (date-time) or null- End of the current billing period: where scheduled changes and a cancellation take effect.
summary.subscription.renewal_datestring (date-time) or null- When the subscription renews (the period end); null when it is set to cancel at period end.
summary.subscription.cancel_at_period_endboolean- True when the subscription ends at
current_period_endinstead of renewing. summary.subscription.past_due_sincestring (date-time) or null- When the subscription first became past due; null when it is not past due.
summary.subscription.dunning_grace_daysinteger- Days a past-due subscription has before it is cancelled and the organization drops to Free (the downgrade composite applies). Service is paused from the decline, not from the end of this window.
summary.pending_changeBillPendingChange or nullalways present- What is scheduled for the period end; null when nothing (and no cancellation) is scheduled.
summary.pending_change.plan_codestring or null- The plan the organization moves to at period end; null when no plan move is scheduled (an interval-only move leaves this null and sets
interval). summary.pending_change.interval"month" | "year" | null- The interval the organization moves to at period end; null when no interval move is scheduled.
summary.pending_change.seats_purchasedinteger or null- The purchased seat quantity from period end; null when no seat decrease is scheduled.
summary.pending_change.counties_purchasedinteger or null- The paid county-slot quantity from period end; null when no slot release is scheduled.
summary.pending_change.remove_addonsarray of string- Add-ons removed at period end; empty when none.
summary.pending_change.cancelboolean- True when the subscription is set to cancel at period end (
POST /v2/account/billing/cancel);POST /v2/account/billing/resumeclears it and nothing else. summary.pending_change.effective_atstring (date-time)- The period end at which everything here takes effect.
summary.pending_change.changesarray of BillPendingItemPlan or BillPendingItemCounties or BillPendingItemSeats or BillPendingItemAddonRemoval- The scheduled set, one item per quantity. A cancellation is not an item here (see
cancel). summary.pending_change.changes[].kind"plan"- Always
plan. summary.pending_change.changes[].plan_codestring- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. summary.pending_change.changes[].interval"month" | "year"- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. summary.pending_change.changes[].effective_atstring (date-time) or null- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. summary.pending_change.changes[].counties_purchasedinteger- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) summary.pending_change.changes[].seats_purchasedinteger- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) summary.pending_change.changes[].addonsarray of string- The add-ons that will be removed.
summary.payment_methodBillPaymentMethod or nullalways present- The default payment method; null when none is set.
summary.payment_method.idstring- Stripe PaymentMethod id (
pm_...). summary.payment_method.brandstring- Card brand as Stripe reports it, e.g.
visa,mastercard. summary.payment_method.last4string- Last four digits of the card number.
summary.payment_method.exp_monthinteger- Card expiry month. (1 to 12)
summary.payment_method.exp_yearinteger- Card expiry year (four digits).
summary.invoicesarray of BillInvoicealways present- Up to the 12 most recent invoices, newest first.
summary.invoices[].idstringalways present- Stripe invoice id (
in_...). summary.invoices[].numberstring or nullalways present- The invoice number printed on it; null while a draft.
summary.invoices[].status"draft" | "open" | "paid" | "void" | "uncollectible"always presentopenis unpaid and collectable (a declined renewal staysopenwhile the subscription ispast_due;POST /v2/account/billing/retrypays it);paid;void;uncollectible;draftnot yet finalized.summary.invoices[].total_centsintegeralways present- Invoice total in US cents.
summary.invoices[].amount_due_centsintegeralways present- Amount still owed, in US cents.
summary.invoices[].amount_paid_centsintegeralways present- Amount paid, in US cents.
summary.invoices[].createdstring (date-time)always present- When the invoice was created.
summary.invoices[].due_datestring (date-time) or nullalways present- Due date for a
send_invoice(contract) invoice; null for card-charged invoices. summary.invoices[].periodobjectalways present- The service period the invoice covers.
summary.invoices[].period.startstring (date-time)always present- Period start.
summary.invoices[].period.endstring (date-time)always present- Period end.
summary.invoices[].hosted_invoice_urlstring (uri) or nullalways present- Stripe's hosted page for viewing and paying the invoice; null when Stripe has none.
summary.invoices[].collection_method"charge_automatically" | "send_invoice"always presentcharge_automatically(charged to the card on file: self-serve) orsend_invoice(sent for payment by its due date: contract-managed organizations).summary.invoices[].descriptionstring or nullalways present- Free-text memo on the invoice (contract invoices), else null.
summary.invoices[].linesarray of BillInvoiceLinealways present- The invoice's lines.
summary.invoices[].lines[].descriptionstringalways present- The line's text as Stripe renders it (product, quantity, period).
summary.invoices[].lines[].amount_centsintegeralways present- Line amount in US cents; negative for a credit.
summary.invoices[].lines[].quantityintegeralways present- Quantity the line bills (1 for the plan and the add-on; the seat or county-slot count for those items).
summary.invoices[].lines[].prorationbooleanalways present- True when the line is a proration (the part-period charge or credit of a mid-period change).
401 error
Unauthenticated. Codes: unauthenticated (no valid API key or session); key_revoked (an API key that was revoked: revoked_at, and reason -- holder, admin, member_removed, seat_removed, api_disabled, addon_ended, account_closed, org_closed, retired, or null for a key revoked before T110 -- and a sentence saying when and why).
As application/problem+json.
403 error
Forbidden. Codes: role_required (only the owner, or a member flagged as billing contact, may manage billing; an admin only when also a billing contact; the problem carries required: [owner, billing_contact]), contract_managed (the organization is billing_mode: invoiced: its plan is managed under a contract by Data Tactical Group), no_membership (the account has no active organization), account_suspended (O56: the caller's own account is suspended by DTG), org_suspended (the organization is suspended), org_closed (the organization is closed), wrong_instance (a key of the mode this process does not serve: a sandbox key on the live API or a live key on the sandbox; base_url names the address that serves it). A sandbox key: sandbox_read_only (it may write only clusters).
As application/problem+json.
404 error
Not found. Codes: not_found (the X-DTG-Org header names an organization the caller does not belong to).
As application/problem+json.
409 error
Conflict. Codes: not_subscribed (the organization has no active subscription; use POST /v2/account/billing/subscribe), no_open_invoice (nothing is owed right now), billing_in_progress (another billing change for this organization is running; the request waited 15 seconds; retry).
As application/problem+json.
429 error
rate_limited (the per-minute ceiling, X-RateLimit-* say which), points_exhausted (the monthly points allowance; Retry-After to the end of the UTC month), server_busy or sandbox_busy (load; retry after Retry-After). A refused server_busy request is not metered.
As application/problem+json.
Retry-Afterheader- Seconds to wait before retrying.
X-RateLimit-Limitheader- The per-minute request ceiling that applies.
X-RateLimit-Remainingheader- Requests left in the current window.
X-RateLimit-Resetheader- Seconds until the window refills: on every answer, the time until the bucket is full again; on a refusal, until a request is allowed (as
Retry-After).
Problem codes: unauthenticated (401), key_revoked (401), account_closed (401), org_closed (401), role_required (403), contract_managed (403), no_membership (403), account_suspended (403), org_suspended (403), org_closed (403), wrong_instance (403), sandbox_read_only (403), not_found (404), not_subscribed (409), no_open_invoice (409), billing_in_progress (409). Every problem is a problem document.
POST /v2/account/seats
Set the purchased seat quantity
Credentials: API key or App session. Operation id billSetSeats.
Sets the number of extra seats bought beyond the plan's included seats (the whole target, not a delta). The same as POST /v2/account/billing/change {seats}: an increase applies now, prorated to the rest of the period and charged at once (always_invoice); a decrease is scheduled for period end, not credited, and the seats stay usable until then, when members beyond the seat count become free members. Price it first with POST /v2/account/billing/preview {seats}. Writes no audit row of its own. Either credential (API key or session). Only the organization's owner or a member flagged as billing contact (an admin only when also a billing contact). Billing changes for one organization are serialized: a second one waits for the first and, after 15 seconds, answers 409 billing_in_progress.
Request body
Required; application/json.
quantityintegerrequired- Extra seats wanted, 0 to 500. (0 to 500)
Responses
200 success
The change applied or scheduled.
As application/json.
applied"immediately" | "period_end"always presentimmediatelywhen an increase was applied now (and charged), elseperiod_end(the change, if any, is scheduled; also returned for a no-op).replacedBillPendingReplacedalways present- For each scheduled item a change would replace (a second change to the same quantity), the item it replaces, keyed by its kind (
plan,counties,seats,addon_removal). An empty object when it replaces nothing. replaced.planBillPendingItemPlan- A scheduled plan or interval move, applied at period end.
replaced.plan.kind"plan"always present- Always
plan. replaced.plan.plan_codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. replaced.plan.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. replaced.plan.effective_atstring (date-time) or nullalways present- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. replaced.countiesBillPendingItemCounties- A scheduled decrease of the paid county-slot quantity (a slot release), applied at period end, not credited; the slots stay usable until then.
replaced.counties.kind"counties"always present- Always
counties. replaced.counties.counties_purchasedintegeralways present- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) replaced.counties.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
replaced.seatsBillPendingItemSeats- A scheduled decrease of purchased seats, applied at period end, not credited; the seats stay usable until then.
replaced.seats.kind"seats"always present- Always
seats. replaced.seats.seats_purchasedintegeralways present- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) replaced.seats.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
replaced.addon_removalBillPendingItemAddonRemoval- A scheduled add-on removal, applied at period end. When the API add-on leaves, the organization's live API keys are revoked at that moment; sandbox keys stay.
replaced.addon_removal.kind"addon_removal"always present- Always
addon_removal. replaced.addon_removal.addonsarray of stringalways present- The add-ons that will be removed.
replaced.addon_removal.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
previewobjectalways present- The preview the change was decided on.
preview.currentBillStateSnapshotalways present- A billing state: plan, interval, add-ons and purchased quantities.
preview.current.plan_codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. preview.current.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. preview.current.addonsarray of stringalways present- Add-ons.
preview.current.seats_purchasednumberalways present- Purchased seats beyond the plan's included seats.
preview.current.counties_purchasednumberalways present- Paid county slots beyond the plan's included counties.
preview.targetobjectalways present- The state the request asks for (unnamed quantities at their current values).
preview.target.plan_codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. preview.target.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. preview.target.addonsarray of stringalways present- Add-ons.
preview.target.seats_purchasednumberalways present- Purchased seats beyond the plan's included seats.
preview.target.counties_purchasednumberalways present- Paid county slots beyond the plan's included counties.
preview.kind"upgrade" | "downgrade" | "mixed" | "none"always presentupgrade(only increases: applied now),downgrade(only decreases: scheduled for period end),mixed(both: the increases now at the current plan and interval, the decreases scheduled),none(no change).preview.effective"immediately" | "period_end"always presentimmediatelywhen anything applies now (upgrade or mixed), elseperiod_end(also fornone).preview.effective_atstring (date-time) or nullalways present- Now for an immediate change, else the current period end.
preview.proration_behavior"always_invoice" | "none"always presentalways_invoicewhen the change applies now: the prorated amount is invoiced and charged to the card at once.nonefor a period-end change: nothing is charged now and nothing is credited.preview.immediate_charge_centsintegeralways present- What the card is charged now, in US cents (the sum of the proration lines, never below 0); 0 for a period-end change. (at least 0)
preview.proration_linesarray of BillAmountLinealways present- The prorated lines charged now. When the API add-on is being added (term restart) these are every line of the restarted term.
preview.proration_lines[].descriptionstringalways present- The line's text as Stripe renders it (product, quantity, period).
preview.proration_lines[].amount_centsintegeralways present- Line amount in US cents; negative for a credit.
preview.proration_lines[].quantityintegeralways present- Quantity the line bills (1 for the plan and the add-on; the seat or county-slot count for those items).
preview.term_restartbooleanalways present- True when the change adds the API add-on: the WHOLE subscription restarts its term today, every item moving to the new anchor together; the new term is charged now.
preview.credit_centsinteger or nullalways present- Only when
term_restartis true: the magnitude, in US cents, of any credit lines Stripe returns for unused time (commonly 0, because Stripe nets a continuing item into one line). Null otherwise. preview.new_renewal_datestring (date-time) or nullalways present- Only when
term_restartis true: the renewal date after the restart. Null otherwise. preview.next_invoiceobjectalways present- The next renewal invoice, priced on the period-end state (what this change asks for plus what is already scheduled). Empty (
total_cents0, no lines) on a term restart, where everything is due now. preview.next_invoice.total_centsintegeralways present- Total of the next invoice in US cents.
preview.next_invoice.linesarray of BillAmountLinealways present- Its lines.
preview.next_invoice.lines[].descriptionstringalways present- The line's text as Stripe renders it (product, quantity, period).
preview.next_invoice.lines[].amount_centsintegeralways present- Line amount in US cents; negative for a credit.
preview.next_invoice.lines[].quantityintegeralways present- Quantity the line bills (1 for the plan and the add-on; the seat or county-slot count for those items).
preview.unit_prices_centsobjectalways present- Unit prices, in US cents per interval, for the target plan and interval, from the price catalog; 0 where the catalog holds no such price.
preview.unit_prices_cents.planintegeralways present- The plan price.
preview.unit_prices_cents.seatintegeralways present- One extra seat.
preview.unit_prices_cents.countyintegeralways present- One extra county slot; 0 when the plan sells none.
preview.unit_prices_cents.api_addonintegeralways present- The API add-on (0 on a monthly interval: it is sold annual only).
preview.counties_requiring_choiceobject or nullalways present- Set when the period-end county capacity is below the organization's active counties (counties already scheduled to leave are not counted): the change must then carry
surviving_fips. Null otherwise. preview.counties_requiring_choice.capacityintegeralways present- How many counties the period-end state holds (included plus paid slots).
preview.counties_requiring_choice.candidatesarray of BillCountyCandidatealways present- The active counties to choose from, in KEEP order: the first
capacityare the default choice. preview.counties_requiring_choice.candidates[].fipsstringalways present- Five-digit county FIPS code.
preview.counties_requiring_choice.candidates[].source"manual" | "state" | "msa"always present- How the county entered the active set:
manual(picked),stateormsa(added as part of a state or metro). preview.counties_requiring_choice.candidates[].added_atstring (date-time)always present- When it was added.
preview.counties_requiring_choice.candidates[].last_usedstring (date-time) or nullalways present- The organization's last data request touching this county in the past 90 days; null when none.
preview.county_slots_releasableintegeralways present- How many paid county slots the period-end state holds that the active set does not need (for example after a move to a plan with more included counties), so the customer could release them.
preview.seats_becoming_free_membersintegeralways present- How many seated members exceed the period-end seat count and would become free members.
preview.scheduledarray of BillPendingItemPlan or BillPendingItemCounties or BillPendingItemSeats or BillPendingItemAddonRemovalalways present- What is scheduled now, before this change.
preview.scheduled[].kind"plan"- Always
plan. preview.scheduled[].plan_codestring- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. preview.scheduled[].interval"month" | "year"- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. preview.scheduled[].effective_atstring (date-time) or null- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. preview.scheduled[].counties_purchasedinteger- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) preview.scheduled[].seats_purchasedinteger- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) preview.scheduled[].addonsarray of string- The add-ons that will be removed.
preview.scheduled_afterarray of BillPendingItemPlan or BillPendingItemCounties or BillPendingItemSeats or BillPendingItemAddonRemovalalways present- What this change would leave scheduled (in a mixed change, the plan move appears here).
preview.scheduled_after[].kind"plan"- Always
plan. preview.scheduled_after[].plan_codestring- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. preview.scheduled_after[].interval"month" | "year"- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. preview.scheduled_after[].effective_atstring (date-time) or null- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. preview.scheduled_after[].counties_purchasedinteger- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) preview.scheduled_after[].seats_purchasedinteger- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) preview.scheduled_after[].addonsarray of string- The add-ons that will be removed.
preview.replacesBillPendingReplacedalways present- For each scheduled item a change would replace (a second change to the same quantity), the item it replaces, keyed by its kind (
plan,counties,seats,addon_removal). An empty object when it replaces nothing. preview.replaces.planBillPendingItemPlan- A scheduled plan or interval move, applied at period end.
preview.replaces.plan.kind"plan"always present- Always
plan. preview.replaces.plan.plan_codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. preview.replaces.plan.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. preview.replaces.plan.effective_atstring (date-time) or nullalways present- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. preview.replaces.countiesBillPendingItemCounties- A scheduled decrease of the paid county-slot quantity (a slot release), applied at period end, not credited; the slots stay usable until then.
preview.replaces.counties.kind"counties"always present- Always
counties. preview.replaces.counties.counties_purchasedintegeralways present- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) preview.replaces.counties.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
preview.replaces.seatsBillPendingItemSeats- A scheduled decrease of purchased seats, applied at period end, not credited; the seats stay usable until then.
preview.replaces.seats.kind"seats"always present- Always
seats. preview.replaces.seats.seats_purchasedintegeralways present- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) preview.replaces.seats.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
preview.replaces.addon_removalBillPendingItemAddonRemoval- A scheduled add-on removal, applied at period end. When the API add-on leaves, the organization's live API keys are revoked at that moment; sandbox keys stay.
preview.replaces.addon_removal.kind"addon_removal"always present- Always
addon_removal. preview.replaces.addon_removal.addonsarray of stringalways present- The add-ons that will be removed.
preview.replaces.addon_removal.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
summaryBillSummaryalways present- The organization's billing state as Kelpie's seats-and-billing screen shows it.
summary.gateway"fake" | "test" | "live"always present- Which payment gateway this server runs:
live(Stripe live mode, production only),test(Stripe test mode) orfake(an in-process simulation used in development and tests). T153: the Stripe secret key's prefix decides betweentestandlive. summary.publishable_keystring or nullalways present- The Stripe publishable key to initialise Stripe.js and the Payment Element with.
summary.billing_mode"self_serve" | "invoiced"always presentself_serve(card subscription managed through these endpoints) orinvoiced(a contract managed by Data Tactical Group: every self-serve change answers 403contract_managed).summary.contractobject or nullalways present- The contract terms for an
invoicedorganization; null forself_serve. summary.contract.expires_atstring (date-time) or null- When the contract ends; null for no end date.
summary.contract.notesstring or null- DTG's notes on the contract.
summary.planobjectalways present- The plan the organization holds now.
summary.plan.codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. summary.plan.namestringalways present- The plan's display name (e.g. Local, Regional, National, Free).
summary.plan.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. summary.addonsarray of stringalways present- Active add-ons.
summary.seatsobjectalways present- Seats: the plan's included seats plus purchased extra seats.
summary.seats.includedintegeralways present- Seats the plan includes (the plan's allowance; see
GET /v2/plans), raised tograndfatheredwhile that is set. summary.seats.grandfatheredinteger or null- T163: an organization that had more seated members than its plan's new included count when Regional fell to 10 seats and National to 15 keeps that many included seats until its seated members fall to the plan's count or its plan changes. This is that count; null for every other organization.
summary.seats.purchasedintegeralways present- Extra seats the organization holds beyond
included. A scheduled decrease does not lower this until period end. summary.seats.billed_quantityintegeralways present- The seat quantity on the Stripe subscription (for an
invoicedorganization, the contracted extra seats; 0 with no subscription). Can differ frompurchasedbriefly while a scheduled decrease has been sent to Stripe ahead of the renewal. summary.seats.seat_price_usd_monthnumber or nullalways present- The plan's monthly price of one extra seat, in US dollars; null when the plan sells no extra seats.
summary.seats.proration"always_invoice"always present- How a seat increase is billed: always
always_invoice(prorated to the rest of the period and charged to the card at purchase). summary.seats.proration_notestringalways present- A sentence stating the seat billing rule for display.
summary.countiesobjectalways present- County slots: the plan's included counties plus paid county slots. The county SET is managed at
/v2/account/counties; this is the billing quantity behind it. summary.counties.includedintegeralways present- Counties the plan includes; -1 means every county (National).
summary.counties.purchasedintegeralways present- Paid county slots beyond
included. summary.counties.billed_quantityintegeralways present- The county-slot quantity on the Stripe subscription (for an
invoicedorganization, the contracted slots; 0 with no subscription). summary.counties.activeintegeralways present- Counties currently in the organization's active set, not counting a trial county.
summary.counties.county_price_usd_monthnumber or nullalways present- The plan's monthly price of one extra county slot, in US dollars; null when the plan sells no extra counties.
summary.counties.proration"always_invoice"always present- How a slot increase is billed: always
always_invoice(prorated and charged at purchase). summary.counties.proration_notestringalways present- A sentence stating the county-slot billing rule for display.
summary.counties.anchor_dayinteger or nullalways present- Day of the month of the organization's change window (the subscription's anchor date), on which county set changes land; null before a first subscription. (1 to 31)
summary.subscriptionobject or nullalways present- The current Stripe subscription (status active, trialing, past_due or incomplete); null when there is none (Free, or contract-managed without one).
summary.subscription.idstring- Stripe subscription id (
sub_...). summary.subscription.status"active" | "trialing" | "past_due" | "incomplete"active;trialing;past_due(a renewal was declined: L18 pauses county detail, CSV/XLSX export, live API keys and cluster editing at once, while the plan and its capacity stay held; pay withPOST /v2/account/billing/retryafter fixing the card);incomplete(the first payment has not succeeded).summary.subscription.current_period_startstring (date-time) or null- Start of the current billing period.
summary.subscription.current_period_endstring (date-time) or null- End of the current billing period: where scheduled changes and a cancellation take effect.
summary.subscription.renewal_datestring (date-time) or null- When the subscription renews (the period end); null when it is set to cancel at period end.
summary.subscription.cancel_at_period_endboolean- True when the subscription ends at
current_period_endinstead of renewing. summary.subscription.past_due_sincestring (date-time) or null- When the subscription first became past due; null when it is not past due.
summary.subscription.dunning_grace_daysinteger- Days a past-due subscription has before it is cancelled and the organization drops to Free (the downgrade composite applies). Service is paused from the decline, not from the end of this window.
summary.pending_changeBillPendingChange or nullalways present- What is scheduled for the period end; null when nothing (and no cancellation) is scheduled.
summary.pending_change.plan_codestring or null- The plan the organization moves to at period end; null when no plan move is scheduled (an interval-only move leaves this null and sets
interval). summary.pending_change.interval"month" | "year" | null- The interval the organization moves to at period end; null when no interval move is scheduled.
summary.pending_change.seats_purchasedinteger or null- The purchased seat quantity from period end; null when no seat decrease is scheduled.
summary.pending_change.counties_purchasedinteger or null- The paid county-slot quantity from period end; null when no slot release is scheduled.
summary.pending_change.remove_addonsarray of string- Add-ons removed at period end; empty when none.
summary.pending_change.cancelboolean- True when the subscription is set to cancel at period end (
POST /v2/account/billing/cancel);POST /v2/account/billing/resumeclears it and nothing else. summary.pending_change.effective_atstring (date-time)- The period end at which everything here takes effect.
summary.pending_change.changesarray of BillPendingItemPlan or BillPendingItemCounties or BillPendingItemSeats or BillPendingItemAddonRemoval- The scheduled set, one item per quantity. A cancellation is not an item here (see
cancel). summary.pending_change.changes[].kind"plan"- Always
plan. summary.pending_change.changes[].plan_codestring- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. summary.pending_change.changes[].interval"month" | "year"- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. summary.pending_change.changes[].effective_atstring (date-time) or null- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. summary.pending_change.changes[].counties_purchasedinteger- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) summary.pending_change.changes[].seats_purchasedinteger- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) summary.pending_change.changes[].addonsarray of string- The add-ons that will be removed.
summary.payment_methodBillPaymentMethod or nullalways present- The default payment method; null when none is set.
summary.payment_method.idstring- Stripe PaymentMethod id (
pm_...). summary.payment_method.brandstring- Card brand as Stripe reports it, e.g.
visa,mastercard. summary.payment_method.last4string- Last four digits of the card number.
summary.payment_method.exp_monthinteger- Card expiry month. (1 to 12)
summary.payment_method.exp_yearinteger- Card expiry year (four digits).
summary.invoicesarray of BillInvoicealways present- Up to the 12 most recent invoices, newest first.
summary.invoices[].idstringalways present- Stripe invoice id (
in_...). summary.invoices[].numberstring or nullalways present- The invoice number printed on it; null while a draft.
summary.invoices[].status"draft" | "open" | "paid" | "void" | "uncollectible"always presentopenis unpaid and collectable (a declined renewal staysopenwhile the subscription ispast_due;POST /v2/account/billing/retrypays it);paid;void;uncollectible;draftnot yet finalized.summary.invoices[].total_centsintegeralways present- Invoice total in US cents.
summary.invoices[].amount_due_centsintegeralways present- Amount still owed, in US cents.
summary.invoices[].amount_paid_centsintegeralways present- Amount paid, in US cents.
summary.invoices[].createdstring (date-time)always present- When the invoice was created.
summary.invoices[].due_datestring (date-time) or nullalways present- Due date for a
send_invoice(contract) invoice; null for card-charged invoices. summary.invoices[].periodobjectalways present- The service period the invoice covers.
summary.invoices[].period.startstring (date-time)always present- Period start.
summary.invoices[].period.endstring (date-time)always present- Period end.
summary.invoices[].hosted_invoice_urlstring (uri) or nullalways present- Stripe's hosted page for viewing and paying the invoice; null when Stripe has none.
summary.invoices[].collection_method"charge_automatically" | "send_invoice"always presentcharge_automatically(charged to the card on file: self-serve) orsend_invoice(sent for payment by its due date: contract-managed organizations).summary.invoices[].descriptionstring or nullalways present- Free-text memo on the invoice (contract invoices), else null.
summary.invoices[].linesarray of BillInvoiceLinealways present- The invoice's lines.
summary.invoices[].lines[].descriptionstringalways present- The line's text as Stripe renders it (product, quantity, period).
summary.invoices[].lines[].amount_centsintegeralways present- Line amount in US cents; negative for a credit.
summary.invoices[].lines[].quantityintegeralways present- Quantity the line bills (1 for the plan and the add-on; the seat or county-slot count for those items).
summary.invoices[].lines[].prorationbooleanalways present- True when the line is a proration (the part-period charge or credit of a mid-period change).
400 error
Bad request. Codes: bad_request (quantity missing, not a number, or not an integer 0 to 500), surviving_counties_required (a county choice is owed; capacity, candidates; errors repeats it), annual_plan_required (only when the period-end state would re-price the API add-on onto a non-annual interval), malformed_json (the body is not valid JSON).
As application/problem+json.
401 error
Unauthenticated. Codes: unauthenticated (no valid API key or session); key_revoked (an API key that was revoked: revoked_at, and reason -- holder, admin, member_removed, seat_removed, api_disabled, addon_ended, account_closed, org_closed, retired, or null for a key revoked before T110 -- and a sentence saying when and why).
As application/problem+json.
403 error
Forbidden. Codes: role_required (only the owner, or a member flagged as billing contact, may manage billing; an admin only when also a billing contact; the problem carries required: [owner, billing_contact]), contract_managed (the organization is billing_mode: invoiced: its plan is managed under a contract by Data Tactical Group), no_membership (the account has no active organization), account_suspended (O56: the caller's own account is suspended by DTG), org_suspended (the organization is suspended), org_closed (the organization is closed), wrong_instance (a key of the mode this process does not serve: a sandbox key on the live API or a live key on the sandbox; base_url names the address that serves it). A sandbox key: sandbox_read_only (it may write only clusters).
As application/problem+json.
404 error
Not found. Codes: not_found (the X-DTG-Org header names an organization the caller does not belong to).
As application/problem+json.
409 error
Conflict. Codes: not_subscribed (the organization has no active subscription; use POST /v2/account/billing/subscribe), billing_in_progress (another billing change for this organization is running; the request waited 15 seconds; retry).
As application/problem+json.
413 error
Payload too large. Codes: body_too_large (the JSON body is over 4 KB; the problem carries limit_bytes).
As application/problem+json.
429 error
rate_limited (the per-minute ceiling, X-RateLimit-* say which), points_exhausted (the monthly points allowance; Retry-After to the end of the UTC month), server_busy or sandbox_busy (load; retry after Retry-After). A refused server_busy request is not metered.
As application/problem+json.
Retry-Afterheader- Seconds to wait before retrying.
X-RateLimit-Limitheader- The per-minute request ceiling that applies.
X-RateLimit-Remainingheader- Requests left in the current window.
X-RateLimit-Resetheader- Seconds until the window refills: on every answer, the time until the bucket is full again; on a refusal, until a request is allowed (as
Retry-After).
Problem codes: bad_request (400), surviving_counties_required (400), annual_plan_required (400), malformed_json (400), unauthenticated (401), key_revoked (401), account_closed (401), org_closed (401), role_required (403), contract_managed (403), no_membership (403), account_suspended (403), org_suspended (403), org_closed (403), wrong_instance (403), sandbox_read_only (403), not_found (404), not_subscribed (409), billing_in_progress (409), body_too_large (413). Every problem is a problem document.
POST /v2/account/county-slots
Set the paid county-slot quantity
Credentials: API key or App session. Operation id billSetCountySlots.
Sets the number of paid county slots beyond the plan's included counties (D44; the whole target, not a delta). The same as POST /v2/account/billing/change {counties}: an increase applies now, prorated and charged at once (always_invoice); a decrease is scheduled for period end, not credited, and the slots stay usable until then. The county SET is managed at /v2/account/counties (which answers confirm_purchase_required when adding a county needs a slot bought); this is the billing quantity behind it. A decrease below the active counties needs a surviving-county choice, which this endpoint cannot carry: use POST /v2/account/billing/change {counties, surviving_fips}. Either credential (API key or session). Only the organization's owner or a member flagged as billing contact (an admin only when also a billing contact). Billing changes for one organization are serialized: a second one waits for the first and, after 15 seconds, answers 409 billing_in_progress.
Request body
Required; application/json.
quantityintegerrequired- Paid county slots wanted, 0 to 3194. (0 to 3194)
Responses
200 success
The change applied or scheduled.
As application/json.
applied"immediately" | "period_end"always presentimmediatelywhen an increase was applied now (and charged), elseperiod_end(the change, if any, is scheduled; also returned for a no-op).replacedBillPendingReplacedalways present- For each scheduled item a change would replace (a second change to the same quantity), the item it replaces, keyed by its kind (
plan,counties,seats,addon_removal). An empty object when it replaces nothing. replaced.planBillPendingItemPlan- A scheduled plan or interval move, applied at period end.
replaced.plan.kind"plan"always present- Always
plan. replaced.plan.plan_codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. replaced.plan.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. replaced.plan.effective_atstring (date-time) or nullalways present- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. replaced.countiesBillPendingItemCounties- A scheduled decrease of the paid county-slot quantity (a slot release), applied at period end, not credited; the slots stay usable until then.
replaced.counties.kind"counties"always present- Always
counties. replaced.counties.counties_purchasedintegeralways present- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) replaced.counties.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
replaced.seatsBillPendingItemSeats- A scheduled decrease of purchased seats, applied at period end, not credited; the seats stay usable until then.
replaced.seats.kind"seats"always present- Always
seats. replaced.seats.seats_purchasedintegeralways present- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) replaced.seats.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
replaced.addon_removalBillPendingItemAddonRemoval- A scheduled add-on removal, applied at period end. When the API add-on leaves, the organization's live API keys are revoked at that moment; sandbox keys stay.
replaced.addon_removal.kind"addon_removal"always present- Always
addon_removal. replaced.addon_removal.addonsarray of stringalways present- The add-ons that will be removed.
replaced.addon_removal.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
previewobjectalways present- The preview the change was decided on.
preview.currentBillStateSnapshotalways present- A billing state: plan, interval, add-ons and purchased quantities.
preview.current.plan_codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. preview.current.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. preview.current.addonsarray of stringalways present- Add-ons.
preview.current.seats_purchasednumberalways present- Purchased seats beyond the plan's included seats.
preview.current.counties_purchasednumberalways present- Paid county slots beyond the plan's included counties.
preview.targetobjectalways present- The state the request asks for (unnamed quantities at their current values).
preview.target.plan_codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. preview.target.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. preview.target.addonsarray of stringalways present- Add-ons.
preview.target.seats_purchasednumberalways present- Purchased seats beyond the plan's included seats.
preview.target.counties_purchasednumberalways present- Paid county slots beyond the plan's included counties.
preview.kind"upgrade" | "downgrade" | "mixed" | "none"always presentupgrade(only increases: applied now),downgrade(only decreases: scheduled for period end),mixed(both: the increases now at the current plan and interval, the decreases scheduled),none(no change).preview.effective"immediately" | "period_end"always presentimmediatelywhen anything applies now (upgrade or mixed), elseperiod_end(also fornone).preview.effective_atstring (date-time) or nullalways present- Now for an immediate change, else the current period end.
preview.proration_behavior"always_invoice" | "none"always presentalways_invoicewhen the change applies now: the prorated amount is invoiced and charged to the card at once.nonefor a period-end change: nothing is charged now and nothing is credited.preview.immediate_charge_centsintegeralways present- What the card is charged now, in US cents (the sum of the proration lines, never below 0); 0 for a period-end change. (at least 0)
preview.proration_linesarray of BillAmountLinealways present- The prorated lines charged now. When the API add-on is being added (term restart) these are every line of the restarted term.
preview.proration_lines[].descriptionstringalways present- The line's text as Stripe renders it (product, quantity, period).
preview.proration_lines[].amount_centsintegeralways present- Line amount in US cents; negative for a credit.
preview.proration_lines[].quantityintegeralways present- Quantity the line bills (1 for the plan and the add-on; the seat or county-slot count for those items).
preview.term_restartbooleanalways present- True when the change adds the API add-on: the WHOLE subscription restarts its term today, every item moving to the new anchor together; the new term is charged now.
preview.credit_centsinteger or nullalways present- Only when
term_restartis true: the magnitude, in US cents, of any credit lines Stripe returns for unused time (commonly 0, because Stripe nets a continuing item into one line). Null otherwise. preview.new_renewal_datestring (date-time) or nullalways present- Only when
term_restartis true: the renewal date after the restart. Null otherwise. preview.next_invoiceobjectalways present- The next renewal invoice, priced on the period-end state (what this change asks for plus what is already scheduled). Empty (
total_cents0, no lines) on a term restart, where everything is due now. preview.next_invoice.total_centsintegeralways present- Total of the next invoice in US cents.
preview.next_invoice.linesarray of BillAmountLinealways present- Its lines.
preview.next_invoice.lines[].descriptionstringalways present- The line's text as Stripe renders it (product, quantity, period).
preview.next_invoice.lines[].amount_centsintegeralways present- Line amount in US cents; negative for a credit.
preview.next_invoice.lines[].quantityintegeralways present- Quantity the line bills (1 for the plan and the add-on; the seat or county-slot count for those items).
preview.unit_prices_centsobjectalways present- Unit prices, in US cents per interval, for the target plan and interval, from the price catalog; 0 where the catalog holds no such price.
preview.unit_prices_cents.planintegeralways present- The plan price.
preview.unit_prices_cents.seatintegeralways present- One extra seat.
preview.unit_prices_cents.countyintegeralways present- One extra county slot; 0 when the plan sells none.
preview.unit_prices_cents.api_addonintegeralways present- The API add-on (0 on a monthly interval: it is sold annual only).
preview.counties_requiring_choiceobject or nullalways present- Set when the period-end county capacity is below the organization's active counties (counties already scheduled to leave are not counted): the change must then carry
surviving_fips. Null otherwise. preview.counties_requiring_choice.capacityintegeralways present- How many counties the period-end state holds (included plus paid slots).
preview.counties_requiring_choice.candidatesarray of BillCountyCandidatealways present- The active counties to choose from, in KEEP order: the first
capacityare the default choice. preview.counties_requiring_choice.candidates[].fipsstringalways present- Five-digit county FIPS code.
preview.counties_requiring_choice.candidates[].source"manual" | "state" | "msa"always present- How the county entered the active set:
manual(picked),stateormsa(added as part of a state or metro). preview.counties_requiring_choice.candidates[].added_atstring (date-time)always present- When it was added.
preview.counties_requiring_choice.candidates[].last_usedstring (date-time) or nullalways present- The organization's last data request touching this county in the past 90 days; null when none.
preview.county_slots_releasableintegeralways present- How many paid county slots the period-end state holds that the active set does not need (for example after a move to a plan with more included counties), so the customer could release them.
preview.seats_becoming_free_membersintegeralways present- How many seated members exceed the period-end seat count and would become free members.
preview.scheduledarray of BillPendingItemPlan or BillPendingItemCounties or BillPendingItemSeats or BillPendingItemAddonRemovalalways present- What is scheduled now, before this change.
preview.scheduled[].kind"plan"- Always
plan. preview.scheduled[].plan_codestring- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. preview.scheduled[].interval"month" | "year"- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. preview.scheduled[].effective_atstring (date-time) or null- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. preview.scheduled[].counties_purchasedinteger- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) preview.scheduled[].seats_purchasedinteger- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) preview.scheduled[].addonsarray of string- The add-ons that will be removed.
preview.scheduled_afterarray of BillPendingItemPlan or BillPendingItemCounties or BillPendingItemSeats or BillPendingItemAddonRemovalalways present- What this change would leave scheduled (in a mixed change, the plan move appears here).
preview.scheduled_after[].kind"plan"- Always
plan. preview.scheduled_after[].plan_codestring- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. preview.scheduled_after[].interval"month" | "year"- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. preview.scheduled_after[].effective_atstring (date-time) or null- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. preview.scheduled_after[].counties_purchasedinteger- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) preview.scheduled_after[].seats_purchasedinteger- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) preview.scheduled_after[].addonsarray of string- The add-ons that will be removed.
preview.replacesBillPendingReplacedalways present- For each scheduled item a change would replace (a second change to the same quantity), the item it replaces, keyed by its kind (
plan,counties,seats,addon_removal). An empty object when it replaces nothing. preview.replaces.planBillPendingItemPlan- A scheduled plan or interval move, applied at period end.
preview.replaces.plan.kind"plan"always present- Always
plan. preview.replaces.plan.plan_codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. preview.replaces.plan.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. preview.replaces.plan.effective_atstring (date-time) or nullalways present- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. preview.replaces.countiesBillPendingItemCounties- A scheduled decrease of the paid county-slot quantity (a slot release), applied at period end, not credited; the slots stay usable until then.
preview.replaces.counties.kind"counties"always present- Always
counties. preview.replaces.counties.counties_purchasedintegeralways present- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) preview.replaces.counties.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
preview.replaces.seatsBillPendingItemSeats- A scheduled decrease of purchased seats, applied at period end, not credited; the seats stay usable until then.
preview.replaces.seats.kind"seats"always present- Always
seats. preview.replaces.seats.seats_purchasedintegeralways present- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) preview.replaces.seats.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
preview.replaces.addon_removalBillPendingItemAddonRemoval- A scheduled add-on removal, applied at period end. When the API add-on leaves, the organization's live API keys are revoked at that moment; sandbox keys stay.
preview.replaces.addon_removal.kind"addon_removal"always present- Always
addon_removal. preview.replaces.addon_removal.addonsarray of stringalways present- The add-ons that will be removed.
preview.replaces.addon_removal.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
summaryBillSummaryalways present- The organization's billing state as Kelpie's seats-and-billing screen shows it.
summary.gateway"fake" | "test" | "live"always present- Which payment gateway this server runs:
live(Stripe live mode, production only),test(Stripe test mode) orfake(an in-process simulation used in development and tests). T153: the Stripe secret key's prefix decides betweentestandlive. summary.publishable_keystring or nullalways present- The Stripe publishable key to initialise Stripe.js and the Payment Element with.
summary.billing_mode"self_serve" | "invoiced"always presentself_serve(card subscription managed through these endpoints) orinvoiced(a contract managed by Data Tactical Group: every self-serve change answers 403contract_managed).summary.contractobject or nullalways present- The contract terms for an
invoicedorganization; null forself_serve. summary.contract.expires_atstring (date-time) or null- When the contract ends; null for no end date.
summary.contract.notesstring or null- DTG's notes on the contract.
summary.planobjectalways present- The plan the organization holds now.
summary.plan.codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. summary.plan.namestringalways present- The plan's display name (e.g. Local, Regional, National, Free).
summary.plan.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. summary.addonsarray of stringalways present- Active add-ons.
summary.seatsobjectalways present- Seats: the plan's included seats plus purchased extra seats.
summary.seats.includedintegeralways present- Seats the plan includes (the plan's allowance; see
GET /v2/plans), raised tograndfatheredwhile that is set. summary.seats.grandfatheredinteger or null- T163: an organization that had more seated members than its plan's new included count when Regional fell to 10 seats and National to 15 keeps that many included seats until its seated members fall to the plan's count or its plan changes. This is that count; null for every other organization.
summary.seats.purchasedintegeralways present- Extra seats the organization holds beyond
included. A scheduled decrease does not lower this until period end. summary.seats.billed_quantityintegeralways present- The seat quantity on the Stripe subscription (for an
invoicedorganization, the contracted extra seats; 0 with no subscription). Can differ frompurchasedbriefly while a scheduled decrease has been sent to Stripe ahead of the renewal. summary.seats.seat_price_usd_monthnumber or nullalways present- The plan's monthly price of one extra seat, in US dollars; null when the plan sells no extra seats.
summary.seats.proration"always_invoice"always present- How a seat increase is billed: always
always_invoice(prorated to the rest of the period and charged to the card at purchase). summary.seats.proration_notestringalways present- A sentence stating the seat billing rule for display.
summary.countiesobjectalways present- County slots: the plan's included counties plus paid county slots. The county SET is managed at
/v2/account/counties; this is the billing quantity behind it. summary.counties.includedintegeralways present- Counties the plan includes; -1 means every county (National).
summary.counties.purchasedintegeralways present- Paid county slots beyond
included. summary.counties.billed_quantityintegeralways present- The county-slot quantity on the Stripe subscription (for an
invoicedorganization, the contracted slots; 0 with no subscription). summary.counties.activeintegeralways present- Counties currently in the organization's active set, not counting a trial county.
summary.counties.county_price_usd_monthnumber or nullalways present- The plan's monthly price of one extra county slot, in US dollars; null when the plan sells no extra counties.
summary.counties.proration"always_invoice"always present- How a slot increase is billed: always
always_invoice(prorated and charged at purchase). summary.counties.proration_notestringalways present- A sentence stating the county-slot billing rule for display.
summary.counties.anchor_dayinteger or nullalways present- Day of the month of the organization's change window (the subscription's anchor date), on which county set changes land; null before a first subscription. (1 to 31)
summary.subscriptionobject or nullalways present- The current Stripe subscription (status active, trialing, past_due or incomplete); null when there is none (Free, or contract-managed without one).
summary.subscription.idstring- Stripe subscription id (
sub_...). summary.subscription.status"active" | "trialing" | "past_due" | "incomplete"active;trialing;past_due(a renewal was declined: L18 pauses county detail, CSV/XLSX export, live API keys and cluster editing at once, while the plan and its capacity stay held; pay withPOST /v2/account/billing/retryafter fixing the card);incomplete(the first payment has not succeeded).summary.subscription.current_period_startstring (date-time) or null- Start of the current billing period.
summary.subscription.current_period_endstring (date-time) or null- End of the current billing period: where scheduled changes and a cancellation take effect.
summary.subscription.renewal_datestring (date-time) or null- When the subscription renews (the period end); null when it is set to cancel at period end.
summary.subscription.cancel_at_period_endboolean- True when the subscription ends at
current_period_endinstead of renewing. summary.subscription.past_due_sincestring (date-time) or null- When the subscription first became past due; null when it is not past due.
summary.subscription.dunning_grace_daysinteger- Days a past-due subscription has before it is cancelled and the organization drops to Free (the downgrade composite applies). Service is paused from the decline, not from the end of this window.
summary.pending_changeBillPendingChange or nullalways present- What is scheduled for the period end; null when nothing (and no cancellation) is scheduled.
summary.pending_change.plan_codestring or null- The plan the organization moves to at period end; null when no plan move is scheduled (an interval-only move leaves this null and sets
interval). summary.pending_change.interval"month" | "year" | null- The interval the organization moves to at period end; null when no interval move is scheduled.
summary.pending_change.seats_purchasedinteger or null- The purchased seat quantity from period end; null when no seat decrease is scheduled.
summary.pending_change.counties_purchasedinteger or null- The paid county-slot quantity from period end; null when no slot release is scheduled.
summary.pending_change.remove_addonsarray of string- Add-ons removed at period end; empty when none.
summary.pending_change.cancelboolean- True when the subscription is set to cancel at period end (
POST /v2/account/billing/cancel);POST /v2/account/billing/resumeclears it and nothing else. summary.pending_change.effective_atstring (date-time)- The period end at which everything here takes effect.
summary.pending_change.changesarray of BillPendingItemPlan or BillPendingItemCounties or BillPendingItemSeats or BillPendingItemAddonRemoval- The scheduled set, one item per quantity. A cancellation is not an item here (see
cancel). summary.pending_change.changes[].kind"plan"- Always
plan. summary.pending_change.changes[].plan_codestring- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. summary.pending_change.changes[].interval"month" | "year"- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. summary.pending_change.changes[].effective_atstring (date-time) or null- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. summary.pending_change.changes[].counties_purchasedinteger- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) summary.pending_change.changes[].seats_purchasedinteger- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) summary.pending_change.changes[].addonsarray of string- The add-ons that will be removed.
summary.payment_methodBillPaymentMethod or nullalways present- The default payment method; null when none is set.
summary.payment_method.idstring- Stripe PaymentMethod id (
pm_...). summary.payment_method.brandstring- Card brand as Stripe reports it, e.g.
visa,mastercard. summary.payment_method.last4string- Last four digits of the card number.
summary.payment_method.exp_monthinteger- Card expiry month. (1 to 12)
summary.payment_method.exp_yearinteger- Card expiry year (four digits).
summary.invoicesarray of BillInvoicealways present- Up to the 12 most recent invoices, newest first.
summary.invoices[].idstringalways present- Stripe invoice id (
in_...). summary.invoices[].numberstring or nullalways present- The invoice number printed on it; null while a draft.
summary.invoices[].status"draft" | "open" | "paid" | "void" | "uncollectible"always presentopenis unpaid and collectable (a declined renewal staysopenwhile the subscription ispast_due;POST /v2/account/billing/retrypays it);paid;void;uncollectible;draftnot yet finalized.summary.invoices[].total_centsintegeralways present- Invoice total in US cents.
summary.invoices[].amount_due_centsintegeralways present- Amount still owed, in US cents.
summary.invoices[].amount_paid_centsintegeralways present- Amount paid, in US cents.
summary.invoices[].createdstring (date-time)always present- When the invoice was created.
summary.invoices[].due_datestring (date-time) or nullalways present- Due date for a
send_invoice(contract) invoice; null for card-charged invoices. summary.invoices[].periodobjectalways present- The service period the invoice covers.
summary.invoices[].period.startstring (date-time)always present- Period start.
summary.invoices[].period.endstring (date-time)always present- Period end.
summary.invoices[].hosted_invoice_urlstring (uri) or nullalways present- Stripe's hosted page for viewing and paying the invoice; null when Stripe has none.
summary.invoices[].collection_method"charge_automatically" | "send_invoice"always presentcharge_automatically(charged to the card on file: self-serve) orsend_invoice(sent for payment by its due date: contract-managed organizations).summary.invoices[].descriptionstring or nullalways present- Free-text memo on the invoice (contract invoices), else null.
summary.invoices[].linesarray of BillInvoiceLinealways present- The invoice's lines.
summary.invoices[].lines[].descriptionstringalways present- The line's text as Stripe renders it (product, quantity, period).
summary.invoices[].lines[].amount_centsintegeralways present- Line amount in US cents; negative for a credit.
summary.invoices[].lines[].quantityintegeralways present- Quantity the line bills (1 for the plan and the add-on; the seat or county-slot count for those items).
summary.invoices[].lines[].prorationbooleanalways present- True when the line is a proration (the part-period charge or credit of a mid-period change).
400 error
Bad request. Codes: bad_request (quantity missing, not a number, or not an integer 0 to 3194), surviving_counties_required (capacity, candidates; errors repeats it) when the decrease leaves fewer places than active counties and no earlier choice fits), annual_plan_required (only when the period-end state would re-price the API add-on onto a non-annual interval), malformed_json (the body is not valid JSON).
As application/problem+json.
401 error
Unauthenticated. Codes: unauthenticated (no valid API key or session); key_revoked (an API key that was revoked: revoked_at, and reason -- holder, admin, member_removed, seat_removed, api_disabled, addon_ended, account_closed, org_closed, retired, or null for a key revoked before T110 -- and a sentence saying when and why).
As application/problem+json.
403 error
Forbidden. Codes: role_required (only the owner, or a member flagged as billing contact, may manage billing; an admin only when also a billing contact; the problem carries required: [owner, billing_contact]), contract_managed (the organization is billing_mode: invoiced: its plan is managed under a contract by Data Tactical Group), no_membership (the account has no active organization), account_suspended (O56: the caller's own account is suspended by DTG), org_suspended (the organization is suspended), org_closed (the organization is closed), wrong_instance (a key of the mode this process does not serve: a sandbox key on the live API or a live key on the sandbox; base_url names the address that serves it). A sandbox key: sandbox_read_only (it may write only clusters).
As application/problem+json.
404 error
Not found. Codes: not_found (the X-DTG-Org header names an organization the caller does not belong to).
As application/problem+json.
409 error
Conflict. Codes: not_subscribed (the organization has no active subscription; use POST /v2/account/billing/subscribe), billing_in_progress (another billing change for this organization is running; the request waited 15 seconds; retry).
As application/problem+json.
413 error
Payload too large. Codes: body_too_large (the JSON body is over 4 KB; the problem carries limit_bytes).
As application/problem+json.
429 error
rate_limited (the per-minute ceiling, X-RateLimit-* say which), points_exhausted (the monthly points allowance; Retry-After to the end of the UTC month), server_busy or sandbox_busy (load; retry after Retry-After). A refused server_busy request is not metered.
As application/problem+json.
Retry-Afterheader- Seconds to wait before retrying.
X-RateLimit-Limitheader- The per-minute request ceiling that applies.
X-RateLimit-Remainingheader- Requests left in the current window.
X-RateLimit-Resetheader- Seconds until the window refills: on every answer, the time until the bucket is full again; on a refusal, until a request is allowed (as
Retry-After).
Problem codes: bad_request (400), surviving_counties_required (400), annual_plan_required (400), malformed_json (400), unauthenticated (401), key_revoked (401), account_closed (401), org_closed (401), role_required (403), contract_managed (403), no_membership (403), account_suspended (403), org_suspended (403), org_closed (403), wrong_instance (403), sandbox_read_only (403), not_found (404), not_subscribed (409), billing_in_progress (409), body_too_large (413). Every problem is a problem document.
POST /v2/account/addons
Buy the API add-on
Credentials: API key or App session. Operation id billAddAddon.
Adds the API add-on (live API keys) to the subscription. Sold only with an annual plan. Adding it mid-term restarts the whole subscription's term today: the new term is charged now and every item moves to the new renewal date. A declined card leaves the add-on ungranted (unlike other increases); check summary.addons. Price it first with POST /v2/account/billing/preview {addons: ["api"]}. Already holding it is a no-op. Writes no audit row of its own. Either credential (API key or session). Only the organization's owner or a member flagged as billing contact (an admin only when also a billing contact). Billing changes for one organization are serialized: a second one waits for the first and, after 15 seconds, answers 409 billing_in_progress.
Request body
Required; application/json.
addon"api"required- The add-on to buy: only
api.
Responses
200 success
The change applied.
As application/json.
applied"immediately" | "period_end"always presentimmediatelywhen an increase was applied now (and charged), elseperiod_end(the change, if any, is scheduled; also returned for a no-op).replacedBillPendingReplacedalways present- For each scheduled item a change would replace (a second change to the same quantity), the item it replaces, keyed by its kind (
plan,counties,seats,addon_removal). An empty object when it replaces nothing. replaced.planBillPendingItemPlan- A scheduled plan or interval move, applied at period end.
replaced.plan.kind"plan"always present- Always
plan. replaced.plan.plan_codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. replaced.plan.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. replaced.plan.effective_atstring (date-time) or nullalways present- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. replaced.countiesBillPendingItemCounties- A scheduled decrease of the paid county-slot quantity (a slot release), applied at period end, not credited; the slots stay usable until then.
replaced.counties.kind"counties"always present- Always
counties. replaced.counties.counties_purchasedintegeralways present- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) replaced.counties.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
replaced.seatsBillPendingItemSeats- A scheduled decrease of purchased seats, applied at period end, not credited; the seats stay usable until then.
replaced.seats.kind"seats"always present- Always
seats. replaced.seats.seats_purchasedintegeralways present- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) replaced.seats.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
replaced.addon_removalBillPendingItemAddonRemoval- A scheduled add-on removal, applied at period end. When the API add-on leaves, the organization's live API keys are revoked at that moment; sandbox keys stay.
replaced.addon_removal.kind"addon_removal"always present- Always
addon_removal. replaced.addon_removal.addonsarray of stringalways present- The add-ons that will be removed.
replaced.addon_removal.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
previewobjectalways present- The preview the change was decided on.
preview.currentBillStateSnapshotalways present- A billing state: plan, interval, add-ons and purchased quantities.
preview.current.plan_codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. preview.current.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. preview.current.addonsarray of stringalways present- Add-ons.
preview.current.seats_purchasednumberalways present- Purchased seats beyond the plan's included seats.
preview.current.counties_purchasednumberalways present- Paid county slots beyond the plan's included counties.
preview.targetobjectalways present- The state the request asks for (unnamed quantities at their current values).
preview.target.plan_codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. preview.target.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. preview.target.addonsarray of stringalways present- Add-ons.
preview.target.seats_purchasednumberalways present- Purchased seats beyond the plan's included seats.
preview.target.counties_purchasednumberalways present- Paid county slots beyond the plan's included counties.
preview.kind"upgrade" | "downgrade" | "mixed" | "none"always presentupgrade(only increases: applied now),downgrade(only decreases: scheduled for period end),mixed(both: the increases now at the current plan and interval, the decreases scheduled),none(no change).preview.effective"immediately" | "period_end"always presentimmediatelywhen anything applies now (upgrade or mixed), elseperiod_end(also fornone).preview.effective_atstring (date-time) or nullalways present- Now for an immediate change, else the current period end.
preview.proration_behavior"always_invoice" | "none"always presentalways_invoicewhen the change applies now: the prorated amount is invoiced and charged to the card at once.nonefor a period-end change: nothing is charged now and nothing is credited.preview.immediate_charge_centsintegeralways present- What the card is charged now, in US cents (the sum of the proration lines, never below 0); 0 for a period-end change. (at least 0)
preview.proration_linesarray of BillAmountLinealways present- The prorated lines charged now. When the API add-on is being added (term restart) these are every line of the restarted term.
preview.proration_lines[].descriptionstringalways present- The line's text as Stripe renders it (product, quantity, period).
preview.proration_lines[].amount_centsintegeralways present- Line amount in US cents; negative for a credit.
preview.proration_lines[].quantityintegeralways present- Quantity the line bills (1 for the plan and the add-on; the seat or county-slot count for those items).
preview.term_restartbooleanalways present- True when the change adds the API add-on: the WHOLE subscription restarts its term today, every item moving to the new anchor together; the new term is charged now.
preview.credit_centsinteger or nullalways present- Only when
term_restartis true: the magnitude, in US cents, of any credit lines Stripe returns for unused time (commonly 0, because Stripe nets a continuing item into one line). Null otherwise. preview.new_renewal_datestring (date-time) or nullalways present- Only when
term_restartis true: the renewal date after the restart. Null otherwise. preview.next_invoiceobjectalways present- The next renewal invoice, priced on the period-end state (what this change asks for plus what is already scheduled). Empty (
total_cents0, no lines) on a term restart, where everything is due now. preview.next_invoice.total_centsintegeralways present- Total of the next invoice in US cents.
preview.next_invoice.linesarray of BillAmountLinealways present- Its lines.
preview.next_invoice.lines[].descriptionstringalways present- The line's text as Stripe renders it (product, quantity, period).
preview.next_invoice.lines[].amount_centsintegeralways present- Line amount in US cents; negative for a credit.
preview.next_invoice.lines[].quantityintegeralways present- Quantity the line bills (1 for the plan and the add-on; the seat or county-slot count for those items).
preview.unit_prices_centsobjectalways present- Unit prices, in US cents per interval, for the target plan and interval, from the price catalog; 0 where the catalog holds no such price.
preview.unit_prices_cents.planintegeralways present- The plan price.
preview.unit_prices_cents.seatintegeralways present- One extra seat.
preview.unit_prices_cents.countyintegeralways present- One extra county slot; 0 when the plan sells none.
preview.unit_prices_cents.api_addonintegeralways present- The API add-on (0 on a monthly interval: it is sold annual only).
preview.counties_requiring_choiceobject or nullalways present- Set when the period-end county capacity is below the organization's active counties (counties already scheduled to leave are not counted): the change must then carry
surviving_fips. Null otherwise. preview.counties_requiring_choice.capacityintegeralways present- How many counties the period-end state holds (included plus paid slots).
preview.counties_requiring_choice.candidatesarray of BillCountyCandidatealways present- The active counties to choose from, in KEEP order: the first
capacityare the default choice. preview.counties_requiring_choice.candidates[].fipsstringalways present- Five-digit county FIPS code.
preview.counties_requiring_choice.candidates[].source"manual" | "state" | "msa"always present- How the county entered the active set:
manual(picked),stateormsa(added as part of a state or metro). preview.counties_requiring_choice.candidates[].added_atstring (date-time)always present- When it was added.
preview.counties_requiring_choice.candidates[].last_usedstring (date-time) or nullalways present- The organization's last data request touching this county in the past 90 days; null when none.
preview.county_slots_releasableintegeralways present- How many paid county slots the period-end state holds that the active set does not need (for example after a move to a plan with more included counties), so the customer could release them.
preview.seats_becoming_free_membersintegeralways present- How many seated members exceed the period-end seat count and would become free members.
preview.scheduledarray of BillPendingItemPlan or BillPendingItemCounties or BillPendingItemSeats or BillPendingItemAddonRemovalalways present- What is scheduled now, before this change.
preview.scheduled[].kind"plan"- Always
plan. preview.scheduled[].plan_codestring- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. preview.scheduled[].interval"month" | "year"- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. preview.scheduled[].effective_atstring (date-time) or null- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. preview.scheduled[].counties_purchasedinteger- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) preview.scheduled[].seats_purchasedinteger- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) preview.scheduled[].addonsarray of string- The add-ons that will be removed.
preview.scheduled_afterarray of BillPendingItemPlan or BillPendingItemCounties or BillPendingItemSeats or BillPendingItemAddonRemovalalways present- What this change would leave scheduled (in a mixed change, the plan move appears here).
preview.scheduled_after[].kind"plan"- Always
plan. preview.scheduled_after[].plan_codestring- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. preview.scheduled_after[].interval"month" | "year"- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. preview.scheduled_after[].effective_atstring (date-time) or null- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. preview.scheduled_after[].counties_purchasedinteger- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) preview.scheduled_after[].seats_purchasedinteger- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) preview.scheduled_after[].addonsarray of string- The add-ons that will be removed.
preview.replacesBillPendingReplacedalways present- For each scheduled item a change would replace (a second change to the same quantity), the item it replaces, keyed by its kind (
plan,counties,seats,addon_removal). An empty object when it replaces nothing. preview.replaces.planBillPendingItemPlan- A scheduled plan or interval move, applied at period end.
preview.replaces.plan.kind"plan"always present- Always
plan. preview.replaces.plan.plan_codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. preview.replaces.plan.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. preview.replaces.plan.effective_atstring (date-time) or nullalways present- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. preview.replaces.countiesBillPendingItemCounties- A scheduled decrease of the paid county-slot quantity (a slot release), applied at period end, not credited; the slots stay usable until then.
preview.replaces.counties.kind"counties"always present- Always
counties. preview.replaces.counties.counties_purchasedintegeralways present- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) preview.replaces.counties.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
preview.replaces.seatsBillPendingItemSeats- A scheduled decrease of purchased seats, applied at period end, not credited; the seats stay usable until then.
preview.replaces.seats.kind"seats"always present- Always
seats. preview.replaces.seats.seats_purchasedintegeralways present- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) preview.replaces.seats.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
preview.replaces.addon_removalBillPendingItemAddonRemoval- A scheduled add-on removal, applied at period end. When the API add-on leaves, the organization's live API keys are revoked at that moment; sandbox keys stay.
preview.replaces.addon_removal.kind"addon_removal"always present- Always
addon_removal. preview.replaces.addon_removal.addonsarray of stringalways present- The add-ons that will be removed.
preview.replaces.addon_removal.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
summaryBillSummaryalways present- The organization's billing state as Kelpie's seats-and-billing screen shows it.
summary.gateway"fake" | "test" | "live"always present- Which payment gateway this server runs:
live(Stripe live mode, production only),test(Stripe test mode) orfake(an in-process simulation used in development and tests). T153: the Stripe secret key's prefix decides betweentestandlive. summary.publishable_keystring or nullalways present- The Stripe publishable key to initialise Stripe.js and the Payment Element with.
summary.billing_mode"self_serve" | "invoiced"always presentself_serve(card subscription managed through these endpoints) orinvoiced(a contract managed by Data Tactical Group: every self-serve change answers 403contract_managed).summary.contractobject or nullalways present- The contract terms for an
invoicedorganization; null forself_serve. summary.contract.expires_atstring (date-time) or null- When the contract ends; null for no end date.
summary.contract.notesstring or null- DTG's notes on the contract.
summary.planobjectalways present- The plan the organization holds now.
summary.plan.codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. summary.plan.namestringalways present- The plan's display name (e.g. Local, Regional, National, Free).
summary.plan.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. summary.addonsarray of stringalways present- Active add-ons.
summary.seatsobjectalways present- Seats: the plan's included seats plus purchased extra seats.
summary.seats.includedintegeralways present- Seats the plan includes (the plan's allowance; see
GET /v2/plans), raised tograndfatheredwhile that is set. summary.seats.grandfatheredinteger or null- T163: an organization that had more seated members than its plan's new included count when Regional fell to 10 seats and National to 15 keeps that many included seats until its seated members fall to the plan's count or its plan changes. This is that count; null for every other organization.
summary.seats.purchasedintegeralways present- Extra seats the organization holds beyond
included. A scheduled decrease does not lower this until period end. summary.seats.billed_quantityintegeralways present- The seat quantity on the Stripe subscription (for an
invoicedorganization, the contracted extra seats; 0 with no subscription). Can differ frompurchasedbriefly while a scheduled decrease has been sent to Stripe ahead of the renewal. summary.seats.seat_price_usd_monthnumber or nullalways present- The plan's monthly price of one extra seat, in US dollars; null when the plan sells no extra seats.
summary.seats.proration"always_invoice"always present- How a seat increase is billed: always
always_invoice(prorated to the rest of the period and charged to the card at purchase). summary.seats.proration_notestringalways present- A sentence stating the seat billing rule for display.
summary.countiesobjectalways present- County slots: the plan's included counties plus paid county slots. The county SET is managed at
/v2/account/counties; this is the billing quantity behind it. summary.counties.includedintegeralways present- Counties the plan includes; -1 means every county (National).
summary.counties.purchasedintegeralways present- Paid county slots beyond
included. summary.counties.billed_quantityintegeralways present- The county-slot quantity on the Stripe subscription (for an
invoicedorganization, the contracted slots; 0 with no subscription). summary.counties.activeintegeralways present- Counties currently in the organization's active set, not counting a trial county.
summary.counties.county_price_usd_monthnumber or nullalways present- The plan's monthly price of one extra county slot, in US dollars; null when the plan sells no extra counties.
summary.counties.proration"always_invoice"always present- How a slot increase is billed: always
always_invoice(prorated and charged at purchase). summary.counties.proration_notestringalways present- A sentence stating the county-slot billing rule for display.
summary.counties.anchor_dayinteger or nullalways present- Day of the month of the organization's change window (the subscription's anchor date), on which county set changes land; null before a first subscription. (1 to 31)
summary.subscriptionobject or nullalways present- The current Stripe subscription (status active, trialing, past_due or incomplete); null when there is none (Free, or contract-managed without one).
summary.subscription.idstring- Stripe subscription id (
sub_...). summary.subscription.status"active" | "trialing" | "past_due" | "incomplete"active;trialing;past_due(a renewal was declined: L18 pauses county detail, CSV/XLSX export, live API keys and cluster editing at once, while the plan and its capacity stay held; pay withPOST /v2/account/billing/retryafter fixing the card);incomplete(the first payment has not succeeded).summary.subscription.current_period_startstring (date-time) or null- Start of the current billing period.
summary.subscription.current_period_endstring (date-time) or null- End of the current billing period: where scheduled changes and a cancellation take effect.
summary.subscription.renewal_datestring (date-time) or null- When the subscription renews (the period end); null when it is set to cancel at period end.
summary.subscription.cancel_at_period_endboolean- True when the subscription ends at
current_period_endinstead of renewing. summary.subscription.past_due_sincestring (date-time) or null- When the subscription first became past due; null when it is not past due.
summary.subscription.dunning_grace_daysinteger- Days a past-due subscription has before it is cancelled and the organization drops to Free (the downgrade composite applies). Service is paused from the decline, not from the end of this window.
summary.pending_changeBillPendingChange or nullalways present- What is scheduled for the period end; null when nothing (and no cancellation) is scheduled.
summary.pending_change.plan_codestring or null- The plan the organization moves to at period end; null when no plan move is scheduled (an interval-only move leaves this null and sets
interval). summary.pending_change.interval"month" | "year" | null- The interval the organization moves to at period end; null when no interval move is scheduled.
summary.pending_change.seats_purchasedinteger or null- The purchased seat quantity from period end; null when no seat decrease is scheduled.
summary.pending_change.counties_purchasedinteger or null- The paid county-slot quantity from period end; null when no slot release is scheduled.
summary.pending_change.remove_addonsarray of string- Add-ons removed at period end; empty when none.
summary.pending_change.cancelboolean- True when the subscription is set to cancel at period end (
POST /v2/account/billing/cancel);POST /v2/account/billing/resumeclears it and nothing else. summary.pending_change.effective_atstring (date-time)- The period end at which everything here takes effect.
summary.pending_change.changesarray of BillPendingItemPlan or BillPendingItemCounties or BillPendingItemSeats or BillPendingItemAddonRemoval- The scheduled set, one item per quantity. A cancellation is not an item here (see
cancel). summary.pending_change.changes[].kind"plan"- Always
plan. summary.pending_change.changes[].plan_codestring- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. summary.pending_change.changes[].interval"month" | "year"- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. summary.pending_change.changes[].effective_atstring (date-time) or null- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. summary.pending_change.changes[].counties_purchasedinteger- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) summary.pending_change.changes[].seats_purchasedinteger- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) summary.pending_change.changes[].addonsarray of string- The add-ons that will be removed.
summary.payment_methodBillPaymentMethod or nullalways present- The default payment method; null when none is set.
summary.payment_method.idstring- Stripe PaymentMethod id (
pm_...). summary.payment_method.brandstring- Card brand as Stripe reports it, e.g.
visa,mastercard. summary.payment_method.last4string- Last four digits of the card number.
summary.payment_method.exp_monthinteger- Card expiry month. (1 to 12)
summary.payment_method.exp_yearinteger- Card expiry year (four digits).
summary.invoicesarray of BillInvoicealways present- Up to the 12 most recent invoices, newest first.
summary.invoices[].idstringalways present- Stripe invoice id (
in_...). summary.invoices[].numberstring or nullalways present- The invoice number printed on it; null while a draft.
summary.invoices[].status"draft" | "open" | "paid" | "void" | "uncollectible"always presentopenis unpaid and collectable (a declined renewal staysopenwhile the subscription ispast_due;POST /v2/account/billing/retrypays it);paid;void;uncollectible;draftnot yet finalized.summary.invoices[].total_centsintegeralways present- Invoice total in US cents.
summary.invoices[].amount_due_centsintegeralways present- Amount still owed, in US cents.
summary.invoices[].amount_paid_centsintegeralways present- Amount paid, in US cents.
summary.invoices[].createdstring (date-time)always present- When the invoice was created.
summary.invoices[].due_datestring (date-time) or nullalways present- Due date for a
send_invoice(contract) invoice; null for card-charged invoices. summary.invoices[].periodobjectalways present- The service period the invoice covers.
summary.invoices[].period.startstring (date-time)always present- Period start.
summary.invoices[].period.endstring (date-time)always present- Period end.
summary.invoices[].hosted_invoice_urlstring (uri) or nullalways present- Stripe's hosted page for viewing and paying the invoice; null when Stripe has none.
summary.invoices[].collection_method"charge_automatically" | "send_invoice"always presentcharge_automatically(charged to the card on file: self-serve) orsend_invoice(sent for payment by its due date: contract-managed organizations).summary.invoices[].descriptionstring or nullalways present- Free-text memo on the invoice (contract invoices), else null.
summary.invoices[].linesarray of BillInvoiceLinealways present- The invoice's lines.
summary.invoices[].lines[].descriptionstringalways present- The line's text as Stripe renders it (product, quantity, period).
summary.invoices[].lines[].amount_centsintegeralways present- Line amount in US cents; negative for a credit.
summary.invoices[].lines[].quantityintegeralways present- Quantity the line bills (1 for the plan and the add-on; the seat or county-slot count for those items).
summary.invoices[].lines[].prorationbooleanalways present- True when the line is a proration (the part-period charge or credit of a mid-period change).
400 error
Bad request. Codes: annual_plan_required (the plan is not annual), bad_request (addon is not api), malformed_json (the body is not valid JSON).
As application/problem+json.
401 error
Unauthenticated. Codes: unauthenticated (no valid API key or session); key_revoked (an API key that was revoked: revoked_at, and reason -- holder, admin, member_removed, seat_removed, api_disabled, addon_ended, account_closed, org_closed, retired, or null for a key revoked before T110 -- and a sentence saying when and why).
As application/problem+json.
403 error
Forbidden. Codes: role_required (only the owner, or a member flagged as billing contact, may manage billing; an admin only when also a billing contact; the problem carries required: [owner, billing_contact]), contract_managed (the organization is billing_mode: invoiced: its plan is managed under a contract by Data Tactical Group), no_membership (the account has no active organization), account_suspended (O56: the caller's own account is suspended by DTG), org_suspended (the organization is suspended), org_closed (the organization is closed), wrong_instance (a key of the mode this process does not serve: a sandbox key on the live API or a live key on the sandbox; base_url names the address that serves it). A sandbox key: sandbox_read_only (it may write only clusters).
As application/problem+json.
404 error
Not found. Codes: not_found (the X-DTG-Org header names an organization the caller does not belong to).
As application/problem+json.
409 error
Conflict. Codes: not_subscribed (the organization has no active subscription; use POST /v2/account/billing/subscribe), billing_in_progress (another billing change for this organization is running; the request waited 15 seconds; retry).
As application/problem+json.
413 error
Payload too large. Codes: body_too_large (the JSON body is over 4 KB; the problem carries limit_bytes).
As application/problem+json.
429 error
rate_limited (the per-minute ceiling, X-RateLimit-* say which), points_exhausted (the monthly points allowance; Retry-After to the end of the UTC month), server_busy or sandbox_busy (load; retry after Retry-After). A refused server_busy request is not metered.
As application/problem+json.
Retry-Afterheader- Seconds to wait before retrying.
X-RateLimit-Limitheader- The per-minute request ceiling that applies.
X-RateLimit-Remainingheader- Requests left in the current window.
X-RateLimit-Resetheader- Seconds until the window refills: on every answer, the time until the bucket is full again; on a refusal, until a request is allowed (as
Retry-After).
Problem codes: annual_plan_required (400), bad_request (400), malformed_json (400), unauthenticated (401), key_revoked (401), account_closed (401), org_closed (401), role_required (403), contract_managed (403), no_membership (403), account_suspended (403), org_suspended (403), org_closed (403), wrong_instance (403), sandbox_read_only (403), not_found (404), not_subscribed (409), billing_in_progress (409), body_too_large (413). Every problem is a problem document.
DELETE /v2/account/addons/{addon}
Remove the API add-on at period end
Credentials: API key or App session. Operation id billRemoveAddon.
Schedules the API add-on's removal for the period end (never restarts the term, not credited; withdraw it with DELETE /v2/account/billing/pending/addon_removal). When the removal takes effect the organization's LIVE API keys are revoked; sandbox keys stay. Not holding it is a no-op. Writes no audit row of its own. Either credential (API key or session). Only the organization's owner or a member flagged as billing contact (an admin only when also a billing contact). Billing changes for one organization are serialized: a second one waits for the first and, after 15 seconds, answers 409 billing_in_progress.
Parameters
addonpath · "api"required- The add-on to remove: only
api.
Responses
200 success
The removal scheduled.
As application/json.
applied"immediately" | "period_end"always presentimmediatelywhen an increase was applied now (and charged), elseperiod_end(the change, if any, is scheduled; also returned for a no-op).replacedBillPendingReplacedalways present- For each scheduled item a change would replace (a second change to the same quantity), the item it replaces, keyed by its kind (
plan,counties,seats,addon_removal). An empty object when it replaces nothing. replaced.planBillPendingItemPlan- A scheduled plan or interval move, applied at period end.
replaced.plan.kind"plan"always present- Always
plan. replaced.plan.plan_codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. replaced.plan.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. replaced.plan.effective_atstring (date-time) or nullalways present- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. replaced.countiesBillPendingItemCounties- A scheduled decrease of the paid county-slot quantity (a slot release), applied at period end, not credited; the slots stay usable until then.
replaced.counties.kind"counties"always present- Always
counties. replaced.counties.counties_purchasedintegeralways present- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) replaced.counties.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
replaced.seatsBillPendingItemSeats- A scheduled decrease of purchased seats, applied at period end, not credited; the seats stay usable until then.
replaced.seats.kind"seats"always present- Always
seats. replaced.seats.seats_purchasedintegeralways present- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) replaced.seats.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
replaced.addon_removalBillPendingItemAddonRemoval- A scheduled add-on removal, applied at period end. When the API add-on leaves, the organization's live API keys are revoked at that moment; sandbox keys stay.
replaced.addon_removal.kind"addon_removal"always present- Always
addon_removal. replaced.addon_removal.addonsarray of stringalways present- The add-ons that will be removed.
replaced.addon_removal.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
previewobjectalways present- The preview the change was decided on.
preview.currentBillStateSnapshotalways present- A billing state: plan, interval, add-ons and purchased quantities.
preview.current.plan_codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. preview.current.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. preview.current.addonsarray of stringalways present- Add-ons.
preview.current.seats_purchasednumberalways present- Purchased seats beyond the plan's included seats.
preview.current.counties_purchasednumberalways present- Paid county slots beyond the plan's included counties.
preview.targetobjectalways present- The state the request asks for (unnamed quantities at their current values).
preview.target.plan_codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. preview.target.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. preview.target.addonsarray of stringalways present- Add-ons.
preview.target.seats_purchasednumberalways present- Purchased seats beyond the plan's included seats.
preview.target.counties_purchasednumberalways present- Paid county slots beyond the plan's included counties.
preview.kind"upgrade" | "downgrade" | "mixed" | "none"always presentupgrade(only increases: applied now),downgrade(only decreases: scheduled for period end),mixed(both: the increases now at the current plan and interval, the decreases scheduled),none(no change).preview.effective"immediately" | "period_end"always presentimmediatelywhen anything applies now (upgrade or mixed), elseperiod_end(also fornone).preview.effective_atstring (date-time) or nullalways present- Now for an immediate change, else the current period end.
preview.proration_behavior"always_invoice" | "none"always presentalways_invoicewhen the change applies now: the prorated amount is invoiced and charged to the card at once.nonefor a period-end change: nothing is charged now and nothing is credited.preview.immediate_charge_centsintegeralways present- What the card is charged now, in US cents (the sum of the proration lines, never below 0); 0 for a period-end change. (at least 0)
preview.proration_linesarray of BillAmountLinealways present- The prorated lines charged now. When the API add-on is being added (term restart) these are every line of the restarted term.
preview.proration_lines[].descriptionstringalways present- The line's text as Stripe renders it (product, quantity, period).
preview.proration_lines[].amount_centsintegeralways present- Line amount in US cents; negative for a credit.
preview.proration_lines[].quantityintegeralways present- Quantity the line bills (1 for the plan and the add-on; the seat or county-slot count for those items).
preview.term_restartbooleanalways present- True when the change adds the API add-on: the WHOLE subscription restarts its term today, every item moving to the new anchor together; the new term is charged now.
preview.credit_centsinteger or nullalways present- Only when
term_restartis true: the magnitude, in US cents, of any credit lines Stripe returns for unused time (commonly 0, because Stripe nets a continuing item into one line). Null otherwise. preview.new_renewal_datestring (date-time) or nullalways present- Only when
term_restartis true: the renewal date after the restart. Null otherwise. preview.next_invoiceobjectalways present- The next renewal invoice, priced on the period-end state (what this change asks for plus what is already scheduled). Empty (
total_cents0, no lines) on a term restart, where everything is due now. preview.next_invoice.total_centsintegeralways present- Total of the next invoice in US cents.
preview.next_invoice.linesarray of BillAmountLinealways present- Its lines.
preview.next_invoice.lines[].descriptionstringalways present- The line's text as Stripe renders it (product, quantity, period).
preview.next_invoice.lines[].amount_centsintegeralways present- Line amount in US cents; negative for a credit.
preview.next_invoice.lines[].quantityintegeralways present- Quantity the line bills (1 for the plan and the add-on; the seat or county-slot count for those items).
preview.unit_prices_centsobjectalways present- Unit prices, in US cents per interval, for the target plan and interval, from the price catalog; 0 where the catalog holds no such price.
preview.unit_prices_cents.planintegeralways present- The plan price.
preview.unit_prices_cents.seatintegeralways present- One extra seat.
preview.unit_prices_cents.countyintegeralways present- One extra county slot; 0 when the plan sells none.
preview.unit_prices_cents.api_addonintegeralways present- The API add-on (0 on a monthly interval: it is sold annual only).
preview.counties_requiring_choiceobject or nullalways present- Set when the period-end county capacity is below the organization's active counties (counties already scheduled to leave are not counted): the change must then carry
surviving_fips. Null otherwise. preview.counties_requiring_choice.capacityintegeralways present- How many counties the period-end state holds (included plus paid slots).
preview.counties_requiring_choice.candidatesarray of BillCountyCandidatealways present- The active counties to choose from, in KEEP order: the first
capacityare the default choice. preview.counties_requiring_choice.candidates[].fipsstringalways present- Five-digit county FIPS code.
preview.counties_requiring_choice.candidates[].source"manual" | "state" | "msa"always present- How the county entered the active set:
manual(picked),stateormsa(added as part of a state or metro). preview.counties_requiring_choice.candidates[].added_atstring (date-time)always present- When it was added.
preview.counties_requiring_choice.candidates[].last_usedstring (date-time) or nullalways present- The organization's last data request touching this county in the past 90 days; null when none.
preview.county_slots_releasableintegeralways present- How many paid county slots the period-end state holds that the active set does not need (for example after a move to a plan with more included counties), so the customer could release them.
preview.seats_becoming_free_membersintegeralways present- How many seated members exceed the period-end seat count and would become free members.
preview.scheduledarray of BillPendingItemPlan or BillPendingItemCounties or BillPendingItemSeats or BillPendingItemAddonRemovalalways present- What is scheduled now, before this change.
preview.scheduled[].kind"plan"- Always
plan. preview.scheduled[].plan_codestring- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. preview.scheduled[].interval"month" | "year"- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. preview.scheduled[].effective_atstring (date-time) or null- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. preview.scheduled[].counties_purchasedinteger- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) preview.scheduled[].seats_purchasedinteger- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) preview.scheduled[].addonsarray of string- The add-ons that will be removed.
preview.scheduled_afterarray of BillPendingItemPlan or BillPendingItemCounties or BillPendingItemSeats or BillPendingItemAddonRemovalalways present- What this change would leave scheduled (in a mixed change, the plan move appears here).
preview.scheduled_after[].kind"plan"- Always
plan. preview.scheduled_after[].plan_codestring- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. preview.scheduled_after[].interval"month" | "year"- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. preview.scheduled_after[].effective_atstring (date-time) or null- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. preview.scheduled_after[].counties_purchasedinteger- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) preview.scheduled_after[].seats_purchasedinteger- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) preview.scheduled_after[].addonsarray of string- The add-ons that will be removed.
preview.replacesBillPendingReplacedalways present- For each scheduled item a change would replace (a second change to the same quantity), the item it replaces, keyed by its kind (
plan,counties,seats,addon_removal). An empty object when it replaces nothing. preview.replaces.planBillPendingItemPlan- A scheduled plan or interval move, applied at period end.
preview.replaces.plan.kind"plan"always present- Always
plan. preview.replaces.plan.plan_codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. preview.replaces.plan.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. preview.replaces.plan.effective_atstring (date-time) or nullalways present- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. preview.replaces.countiesBillPendingItemCounties- A scheduled decrease of the paid county-slot quantity (a slot release), applied at period end, not credited; the slots stay usable until then.
preview.replaces.counties.kind"counties"always present- Always
counties. preview.replaces.counties.counties_purchasedintegeralways present- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) preview.replaces.counties.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
preview.replaces.seatsBillPendingItemSeats- A scheduled decrease of purchased seats, applied at period end, not credited; the seats stay usable until then.
preview.replaces.seats.kind"seats"always present- Always
seats. preview.replaces.seats.seats_purchasedintegeralways present- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) preview.replaces.seats.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
preview.replaces.addon_removalBillPendingItemAddonRemoval- A scheduled add-on removal, applied at period end. When the API add-on leaves, the organization's live API keys are revoked at that moment; sandbox keys stay.
preview.replaces.addon_removal.kind"addon_removal"always present- Always
addon_removal. preview.replaces.addon_removal.addonsarray of stringalways present- The add-ons that will be removed.
preview.replaces.addon_removal.effective_atstring (date-time) or nullalways present- When the change takes effect (the end of the current period). Same date for every scheduled item.
summaryBillSummaryalways present- The organization's billing state as Kelpie's seats-and-billing screen shows it.
summary.gateway"fake" | "test" | "live"always present- Which payment gateway this server runs:
live(Stripe live mode, production only),test(Stripe test mode) orfake(an in-process simulation used in development and tests). T153: the Stripe secret key's prefix decides betweentestandlive. summary.publishable_keystring or nullalways present- The Stripe publishable key to initialise Stripe.js and the Payment Element with.
summary.billing_mode"self_serve" | "invoiced"always presentself_serve(card subscription managed through these endpoints) orinvoiced(a contract managed by Data Tactical Group: every self-serve change answers 403contract_managed).summary.contractobject or nullalways present- The contract terms for an
invoicedorganization; null forself_serve. summary.contract.expires_atstring (date-time) or null- When the contract ends; null for no end date.
summary.contract.notesstring or null- DTG's notes on the contract.
summary.planobjectalways present- The plan the organization holds now.
summary.plan.codestringalways present- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. summary.plan.namestringalways present- The plan's display name (e.g. Local, Regional, National, Free).
summary.plan.interval"month" | "year"always present- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. summary.addonsarray of stringalways present- Active add-ons.
summary.seatsobjectalways present- Seats: the plan's included seats plus purchased extra seats.
summary.seats.includedintegeralways present- Seats the plan includes (the plan's allowance; see
GET /v2/plans), raised tograndfatheredwhile that is set. summary.seats.grandfatheredinteger or null- T163: an organization that had more seated members than its plan's new included count when Regional fell to 10 seats and National to 15 keeps that many included seats until its seated members fall to the plan's count or its plan changes. This is that count; null for every other organization.
summary.seats.purchasedintegeralways present- Extra seats the organization holds beyond
included. A scheduled decrease does not lower this until period end. summary.seats.billed_quantityintegeralways present- The seat quantity on the Stripe subscription (for an
invoicedorganization, the contracted extra seats; 0 with no subscription). Can differ frompurchasedbriefly while a scheduled decrease has been sent to Stripe ahead of the renewal. summary.seats.seat_price_usd_monthnumber or nullalways present- The plan's monthly price of one extra seat, in US dollars; null when the plan sells no extra seats.
summary.seats.proration"always_invoice"always present- How a seat increase is billed: always
always_invoice(prorated to the rest of the period and charged to the card at purchase). summary.seats.proration_notestringalways present- A sentence stating the seat billing rule for display.
summary.countiesobjectalways present- County slots: the plan's included counties plus paid county slots. The county SET is managed at
/v2/account/counties; this is the billing quantity behind it. summary.counties.includedintegeralways present- Counties the plan includes; -1 means every county (National).
summary.counties.purchasedintegeralways present- Paid county slots beyond
included. summary.counties.billed_quantityintegeralways present- The county-slot quantity on the Stripe subscription (for an
invoicedorganization, the contracted slots; 0 with no subscription). summary.counties.activeintegeralways present- Counties currently in the organization's active set, not counting a trial county.
summary.counties.county_price_usd_monthnumber or nullalways present- The plan's monthly price of one extra county slot, in US dollars; null when the plan sells no extra counties.
summary.counties.proration"always_invoice"always present- How a slot increase is billed: always
always_invoice(prorated and charged at purchase). summary.counties.proration_notestringalways present- A sentence stating the county-slot billing rule for display.
summary.counties.anchor_dayinteger or nullalways present- Day of the month of the organization's change window (the subscription's anchor date), on which county set changes land; null before a first subscription. (1 to 31)
summary.subscriptionobject or nullalways present- The current Stripe subscription (status active, trialing, past_due or incomplete); null when there is none (Free, or contract-managed without one).
summary.subscription.idstring- Stripe subscription id (
sub_...). summary.subscription.status"active" | "trialing" | "past_due" | "incomplete"active;trialing;past_due(a renewal was declined: L18 pauses county detail, CSV/XLSX export, live API keys and cluster editing at once, while the plan and its capacity stay held; pay withPOST /v2/account/billing/retryafter fixing the card);incomplete(the first payment has not succeeded).summary.subscription.current_period_startstring (date-time) or null- Start of the current billing period.
summary.subscription.current_period_endstring (date-time) or null- End of the current billing period: where scheduled changes and a cancellation take effect.
summary.subscription.renewal_datestring (date-time) or null- When the subscription renews (the period end); null when it is set to cancel at period end.
summary.subscription.cancel_at_period_endboolean- True when the subscription ends at
current_period_endinstead of renewing. summary.subscription.past_due_sincestring (date-time) or null- When the subscription first became past due; null when it is not past due.
summary.subscription.dunning_grace_daysinteger- Days a past-due subscription has before it is cancelled and the organization drops to Free (the downgrade composite applies). Service is paused from the decline, not from the end of this window.
summary.pending_changeBillPendingChange or nullalways present- What is scheduled for the period end; null when nothing (and no cancellation) is scheduled.
summary.pending_change.plan_codestring or null- The plan the organization moves to at period end; null when no plan move is scheduled (an interval-only move leaves this null and sets
interval). summary.pending_change.interval"month" | "year" | null- The interval the organization moves to at period end; null when no interval move is scheduled.
summary.pending_change.seats_purchasedinteger or null- The purchased seat quantity from period end; null when no seat decrease is scheduled.
summary.pending_change.counties_purchasedinteger or null- The paid county-slot quantity from period end; null when no slot release is scheduled.
summary.pending_change.remove_addonsarray of string- Add-ons removed at period end; empty when none.
summary.pending_change.cancelboolean- True when the subscription is set to cancel at period end (
POST /v2/account/billing/cancel);POST /v2/account/billing/resumeclears it and nothing else. summary.pending_change.effective_atstring (date-time)- The period end at which everything here takes effect.
summary.pending_change.changesarray of BillPendingItemPlan or BillPendingItemCounties or BillPendingItemSeats or BillPendingItemAddonRemoval- The scheduled set, one item per quantity. A cancellation is not an item here (see
cancel). summary.pending_change.changes[].kind"plan"- Always
plan. summary.pending_change.changes[].plan_codestring- A plan code as
GET /v2/planslists it (starteris Local,prois Regional,nationalis National;freeis the unpaid tier and is never purchasable). The plans, their allowances and prices are inGET /v2/plans. summary.pending_change.changes[].interval"month" | "year"- Billing interval:
month(monthly) oryear(annual). The API add-on is sold only withyear. summary.pending_change.changes[].effective_atstring (date-time) or null- When the change takes effect: the end of the current subscription period. Every scheduled item shares this date. Null only in a preview's
scheduled_afterwhen nothing would be left scheduled. summary.pending_change.changes[].counties_purchasedinteger- The paid county-slot quantity the organization will hold from
effective_at(slots beyond the plan's included counties). (at least 0) summary.pending_change.changes[].seats_purchasedinteger- The purchased (extra) seat quantity the organization will hold from
effective_at, beyond the plan's included seats. (at least 0) summary.pending_change.changes[].addonsarray of string- The add-ons that will be removed.
summary.payment_methodBillPaymentMethod or nullalways present- The default payment method; null when none is set.
summary.payment_method.idstring- Stripe PaymentMethod id (
pm_...). summary.payment_method.brandstring- Card brand as Stripe reports it, e.g.
visa,mastercard. summary.payment_method.last4string- Last four digits of the card number.
summary.payment_method.exp_monthinteger- Card expiry month. (1 to 12)
summary.payment_method.exp_yearinteger- Card expiry year (four digits).
summary.invoicesarray of BillInvoicealways present- Up to the 12 most recent invoices, newest first.
summary.invoices[].idstringalways present- Stripe invoice id (
in_...). summary.invoices[].numberstring or nullalways present- The invoice number printed on it; null while a draft.
summary.invoices[].status"draft" | "open" | "paid" | "void" | "uncollectible"always presentopenis unpaid and collectable (a declined renewal staysopenwhile the subscription ispast_due;POST /v2/account/billing/retrypays it);paid;void;uncollectible;draftnot yet finalized.summary.invoices[].total_centsintegeralways present- Invoice total in US cents.
summary.invoices[].amount_due_centsintegeralways present- Amount still owed, in US cents.
summary.invoices[].amount_paid_centsintegeralways present- Amount paid, in US cents.
summary.invoices[].createdstring (date-time)always present- When the invoice was created.
summary.invoices[].due_datestring (date-time) or nullalways present- Due date for a
send_invoice(contract) invoice; null for card-charged invoices. summary.invoices[].periodobjectalways present- The service period the invoice covers.
summary.invoices[].period.startstring (date-time)always present- Period start.
summary.invoices[].period.endstring (date-time)always present- Period end.
summary.invoices[].hosted_invoice_urlstring (uri) or nullalways present- Stripe's hosted page for viewing and paying the invoice; null when Stripe has none.
summary.invoices[].collection_method"charge_automatically" | "send_invoice"always presentcharge_automatically(charged to the card on file: self-serve) orsend_invoice(sent for payment by its due date: contract-managed organizations).summary.invoices[].descriptionstring or nullalways present- Free-text memo on the invoice (contract invoices), else null.
summary.invoices[].linesarray of BillInvoiceLinealways present- The invoice's lines.
summary.invoices[].lines[].descriptionstringalways present- The line's text as Stripe renders it (product, quantity, period).
summary.invoices[].lines[].amount_centsintegeralways present- Line amount in US cents; negative for a credit.
summary.invoices[].lines[].quantityintegeralways present- Quantity the line bills (1 for the plan and the add-on; the seat or county-slot count for those items).
summary.invoices[].lines[].prorationbooleanalways present- True when the line is a proration (the part-period charge or credit of a mid-period change).
400 error
Bad request. Codes: annual_plan_required (only when a scheduled plan move would re-price the add-on onto a non-annual interval in the state this request produces).
As application/problem+json.
401 error
Unauthenticated. Codes: unauthenticated (no valid API key or session); key_revoked (an API key that was revoked: revoked_at, and reason -- holder, admin, member_removed, seat_removed, api_disabled, addon_ended, account_closed, org_closed, retired, or null for a key revoked before T110 -- and a sentence saying when and why).
As application/problem+json.
403 error
Forbidden. Codes: role_required (only the owner, or a member flagged as billing contact, may manage billing; an admin only when also a billing contact; the problem carries required: [owner, billing_contact]), contract_managed (the organization is billing_mode: invoiced: its plan is managed under a contract by Data Tactical Group), no_membership (the account has no active organization), account_suspended (O56: the caller's own account is suspended by DTG), org_suspended (the organization is suspended), org_closed (the organization is closed), wrong_instance (a key of the mode this process does not serve: a sandbox key on the live API or a live key on the sandbox; base_url names the address that serves it). A sandbox key: sandbox_read_only (it may write only clusters).
As application/problem+json.
404 error
Not found. Codes: not_found (no such add-on: addon is not api), not_found (the X-DTG-Org header names an organization the caller does not belong to).
As application/problem+json.
409 error
Conflict. Codes: not_subscribed (the organization has no active subscription; use POST /v2/account/billing/subscribe), billing_in_progress (another billing change for this organization is running; the request waited 15 seconds; retry).
As application/problem+json.
429 error
rate_limited (the per-minute ceiling, X-RateLimit-* say which), points_exhausted (the monthly points allowance; Retry-After to the end of the UTC month), server_busy or sandbox_busy (load; retry after Retry-After). A refused server_busy request is not metered.
As application/problem+json.
Retry-Afterheader- Seconds to wait before retrying.
X-RateLimit-Limitheader- The per-minute request ceiling that applies.
X-RateLimit-Remainingheader- Requests left in the current window.
X-RateLimit-Resetheader- Seconds until the window refills: on every answer, the time until the bucket is full again; on a refusal, until a request is allowed (as
Retry-After).
Problem codes: annual_plan_required (400), unauthenticated (401), key_revoked (401), account_closed (401), org_closed (401), role_required (403), contract_managed (403), no_membership (403), account_suspended (403), org_suspended (403), org_closed (403), wrong_instance (403), sandbox_read_only (403), not_found (404), not_subscribed (409), billing_in_progress (409). Every problem is a problem document.
Generated from taigan/openapi.yaml at catahoula 77925fab712f(API document version 2.0).