Appearance
reseller-settings
17 endpoints.
GET /api/v1/reseller-settings/profile
Get Profile
Scoped per-reseller (_profile_key): once a reseller saves their own profile it's authoritative for THEM going forward, never affecting (or affected by) another reseller's saved profile. Before that first save, pre-populate from the signed-in reseller's own tc AccCustomer record rather than showing a blank form — falls back to the bare model default (e.g. "Cloud Tools") for superusers / logins with no linked reseller.
200 — Successful Response
json
{
"properties": {
"company_name": {
"type": "string",
"maxLength": 120,
"title": "Company Name",
"default": "Cloud Tools"
},
"contact_name": {
"type": "string",
"maxLength": 120,
"title": "Contact Name",
"default": ""
},
"contact_email": {
"type": "string",
"maxLength": 200,
"title": "Contact Email",
"default": ""
},
"contact_phone": {
"type": "string",
"maxLength": 40,
"title": "Contact Phone",
"default": ""
},
"address": {
"type": "string",
"maxLength": 500,
"title": "Address",
"default": ""
},
"vat_number": {
"type": "string",
"maxLength": 60,
"title": "Vat Number",
"default": ""
},
"registration_number": {
"type": "string",
"maxLength": 60,
"title": "Registration Number",
"default": ""
},
"website": {
"type": "string",
"maxLength": 200,
"title": "Website",
"default": ""
},
"account_number": {
"type": "string",
"maxLength": 64,
"title": "Account Number",
"default": ""
}
},
"type": "object",
"title": "ResellerProfile",
"description": "Company profile of the reseller operating this portal."
}PUT /api/v1/reseller-settings/profile
Update Profile
Request body
json
{
"properties": {
"company_name": {
"type": "string",
"maxLength": 120,
"title": "Company Name",
"default": "Cloud Tools"
},
"contact_name": {
"type": "string",
"maxLength": 120,
"title": "Contact Name",
"default": ""
},
"contact_email": {
"type": "string",
"maxLength": 200,
"title": "Contact Email",
"default": ""
},
"contact_phone": {
"type": "string",
"maxLength": 40,
"title": "Contact Phone",
"default": ""
},
"address": {
"type": "string",
"maxLength": 500,
"title": "Address",
"default": ""
},
"vat_number": {
"type": "string",
"maxLength": 60,
"title": "Vat Number",
"default": ""
},
"registration_number": {
"type": "string",
"maxLength": 60,
"title": "Registration Number",
"default": ""
},
"website": {
"type": "string",
"maxLength": 200,
"title": "Website",
"default": ""
},
"account_number": {
"type": "string",
"maxLength": 64,
"title": "Account Number",
"default": ""
}
},
"type": "object",
"title": "ResellerProfile",
"description": "Company profile of the reseller operating this portal."
}200 — Successful Response
json
{
"properties": {
"company_name": {
"type": "string",
"maxLength": 120,
"title": "Company Name",
"default": "Cloud Tools"
},
"contact_name": {
"type": "string",
"maxLength": 120,
"title": "Contact Name",
"default": ""
},
"contact_email": {
"type": "string",
"maxLength": 200,
"title": "Contact Email",
"default": ""
},
"contact_phone": {
"type": "string",
"maxLength": 40,
"title": "Contact Phone",
"default": ""
},
"address": {
"type": "string",
"maxLength": 500,
"title": "Address",
"default": ""
},
"vat_number": {
"type": "string",
"maxLength": 60,
"title": "Vat Number",
"default": ""
},
"registration_number": {
"type": "string",
"maxLength": 60,
"title": "Registration Number",
"default": ""
},
"website": {
"type": "string",
"maxLength": 200,
"title": "Website",
"default": ""
},
"account_number": {
"type": "string",
"maxLength": 64,
"title": "Account Number",
"default": ""
}
},
"type": "object",
"title": "ResellerProfile",
"description": "Company profile of the reseller operating this portal."
}422 — Validation Error
json
{
"properties": {
"detail": {
"items": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
}GET /api/v1/reseller-settings/branding
Get Branding
This reseller's OWN white label, plus what each unset field falls through to.
Scoped per reseller (_branding_key) exactly as the profile above is. A superuser with no linked reseller still edits the unscoped row — the platform operator's own Cloud Tools identity, which is the channel default every reseller inherits until it overrides it.
200 — Successful Response
json
{
"properties": {
"title": {
"type": "string",
"maxLength": 120,
"title": "Title",
"default": ""
},
"subtitle": {
"type": "string",
"maxLength": 120,
"title": "Subtitle",
"default": ""
},
"logo_url": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Logo Url"
},
"favicon_url": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Favicon Url"
},
"primary_color": {
"anyOf": [
{
"type": "string",
"maxLength": 64
},
{
"type": "null"
}
],
"title": "Primary Color"
},
"primary_foreground": {
"anyOf": [
{
"type": "string",
"maxLength": 64
},
{
"type": "null"
}
],
"title": "Primary Foreground"
},
"background_color": {
"anyOf": [
{
"type": "string",
"maxLength": 64
},
{
"type": "null"
}
],
"title": "Background Color"
},
"font_family": {
"anyOf": [
{
"type": "string",
"maxLength": 200
},
{
"type": "null"
}
],
"title": "Font Family"
},
"reseller_uuid": {
"type": "string",
"title": "Reseller Uuid",
"default": ""
},
"reseller_name": {
"type": "string",
"title": "Reseller Name",
"default": ""
},
"scoped": {
"type": "boolean",
"title": "Scoped",
"default": false
},
"inherited": {
"additionalProperties": true,
"type": "object",
"title": "Inherited"
}
},
"type": "object",
"title": "ResellerBrandingOut",
"description": ":class:`ResellerBranding` plus the read-only context the editor needs to\nexplain itself: WHOSE record this is, and what the fields fall through to\nwhen left blank. ``scoped`` is False for the platform operator's own\nunscoped \"Cloud Tools\" record (a superuser with no linked reseller), which\nis the one row a save here can still affect estate-wide."
}PUT /api/v1/reseller-settings/branding
Update Branding
Request body
json
{
"properties": {
"title": {
"type": "string",
"maxLength": 120,
"title": "Title",
"default": ""
},
"subtitle": {
"type": "string",
"maxLength": 120,
"title": "Subtitle",
"default": ""
},
"logo_url": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Logo Url"
},
"favicon_url": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Favicon Url"
},
"primary_color": {
"anyOf": [
{
"type": "string",
"maxLength": 64
},
{
"type": "null"
}
],
"title": "Primary Color"
},
"primary_foreground": {
"anyOf": [
{
"type": "string",
"maxLength": 64
},
{
"type": "null"
}
],
"title": "Primary Foreground"
},
"background_color": {
"anyOf": [
{
"type": "string",
"maxLength": 64
},
{
"type": "null"
}
],
"title": "Background Color"
},
"font_family": {
"anyOf": [
{
"type": "string",
"maxLength": 200
},
{
"type": "null"
}
],
"title": "Font Family"
}
},
"type": "object",
"title": "ResellerBranding",
"description": "Visual identity of ONE reseller — the white label its customers see.\n\nField-for-field a superset of the site-wide :class:`app.schemas.branding.Branding`\nso the two merge by name with no translation table: ``api.branding._current``\nlays this record OVER ``branding`` / ``branding:<site>`` taking only the\nfields actually set, exactly as the per-site override already works. A\nreseller that fills in nothing inherits the platform skin unchanged; one\nthat fills in a logo and a colour changes those two things and nothing else.\n\nSame URL shapes as Branding.logo_url (http(s) or an inline data: URL) — and,\nlike it, a single logo that must read on dark, the app having no light mode.\n\nWidened 2026-09-01 (was logo/favicon/primary pair only). The narrow shape\nwas why a reseller could recolour the sidebar but never drop the platform's\nNAME off the login screen, which is the one thing a white label has to do."
}200 — Successful Response
json
{
"properties": {
"title": {
"type": "string",
"maxLength": 120,
"title": "Title",
"default": ""
},
"subtitle": {
"type": "string",
"maxLength": 120,
"title": "Subtitle",
"default": ""
},
"logo_url": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Logo Url"
},
"favicon_url": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Favicon Url"
},
"primary_color": {
"anyOf": [
{
"type": "string",
"maxLength": 64
},
{
"type": "null"
}
],
"title": "Primary Color"
},
"primary_foreground": {
"anyOf": [
{
"type": "string",
"maxLength": 64
},
{
"type": "null"
}
],
"title": "Primary Foreground"
},
"background_color": {
"anyOf": [
{
"type": "string",
"maxLength": 64
},
{
"type": "null"
}
],
"title": "Background Color"
},
"font_family": {
"anyOf": [
{
"type": "string",
"maxLength": 200
},
{
"type": "null"
}
],
"title": "Font Family"
},
"reseller_uuid": {
"type": "string",
"title": "Reseller Uuid",
"default": ""
},
"reseller_name": {
"type": "string",
"title": "Reseller Name",
"default": ""
},
"scoped": {
"type": "boolean",
"title": "Scoped",
"default": false
},
"inherited": {
"additionalProperties": true,
"type": "object",
"title": "Inherited"
}
},
"type": "object",
"title": "ResellerBrandingOut",
"description": ":class:`ResellerBranding` plus the read-only context the editor needs to\nexplain itself: WHOSE record this is, and what the fields fall through to\nwhen left blank. ``scoped`` is False for the platform operator's own\nunscoped \"Cloud Tools\" record (a superuser with no linked reseller), which\nis the one row a save here can still affect estate-wide."
}422 — Validation Error
json
{
"properties": {
"detail": {
"items": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
}POST /api/v1/reseller-settings/users
Create Reseller User
Create a sub-account under the SIGNED-IN reseller: a real portal login (password set here directly, no invite email — the reseller is vouching for this person) plus an AccCustomer row on the books site (tc) with reseller_id pointing at the signed-in reseller's own account (customer_group="Reseller User" — the 2026-07-28 reseller_users -> acc_customer migration; end-users are no longer a separate table). Reseller-only (not superuser — there's no "logged in reseller" for a platform admin to create under).
Request body
json
{
"properties": {
"name": {
"type": "string",
"maxLength": 255,
"minLength": 1,
"title": "Name"
},
"email": {
"type": "string",
"format": "email",
"title": "Email"
},
"phone": {
"anyOf": [
{
"type": "string",
"maxLength": 64
},
{
"type": "null"
}
],
"title": "Phone"
},
"password": {
"type": "string",
"maxLength": 200,
"minLength": 8,
"title": "Password"
}
},
"type": "object",
"required": [
"name",
"email",
"password"
],
"title": "NewResellerUser",
"description": "A reseller's own sub-account, created directly with a password (not the\ninvite-email flow the tc->portal sync uses for direct customers) — the\nreseller is vouching for this person themselves, so it takes effect\nimmediately rather than waiting on an activation email."
}201 — Successful Response
json
{
"additionalProperties": true,
"type": "object",
"title": "Response Create Reseller User Api V1 Reseller Settings Users Post"
}422 — Validation Error
json
{
"properties": {
"detail": {
"items": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
}PUT /api/v1/reseller-settings/users/{ru_id}
Update Reseller User
Edit a sub-account under the SIGNED-IN reseller (name/email/phone/status). The row lives on tc as an AccCustomer (see create_reseller_user) — scoped so a reseller can only ever touch a row whose reseller_id matches their OWN account's integer id, never another reseller's. Doesn't touch the linked portal login (if any) — see UpdateResellerUser.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
ru_id | path | yes | string |
Request body
json
{
"properties": {
"name": {
"type": "string",
"maxLength": 255,
"minLength": 1,
"title": "Name"
},
"email": {
"anyOf": [
{
"type": "string",
"format": "email"
},
{
"type": "null"
}
],
"title": "Email"
},
"phone": {
"anyOf": [
{
"type": "string",
"maxLength": 64
},
{
"type": "null"
}
],
"title": "Phone"
},
"status": {
"type": "string",
"maxLength": 32,
"title": "Status",
"default": "active"
}
},
"type": "object",
"required": [
"name"
],
"title": "UpdateResellerUser",
"description": "Editing an existing sub-account under the signed-in reseller. Only the\nResellerUser record on tc is touched — the linked portal login (if any,\nsee ResellerUser.portal_tenant_id) is out of scope here."
}200 — Successful Response
json
{
"type": "object",
"additionalProperties": true,
"title": "Response Update Reseller User Api V1 Reseller Settings Users Ru Id Put"
}422 — Validation Error
json
{
"properties": {
"detail": {
"items": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
}GET /api/v1/reseller-settings/domains
List Domains
This reseller's hostnames plus the CNAME target to point them at.
cname_target is returned even when the list is empty — it is the one instruction the reseller needs before they can add anything, and the page shows it whether or not they have started.
200 — Successful Response
json
{
"additionalProperties": true,
"type": "object",
"title": "Response List Domains Api V1 Reseller Settings Domains Get"
}POST /api/v1/reseller-settings/domains
Add Domain
Register a hostname and start provisioning it in the background.
Returns immediately with the pending row: verification waits on the reseller's registrar and issuance on Let's Encrypt, neither of which belongs inside a request. The page polls :func:list_domains for the outcome.
Request body
json
{
"properties": {
"host": {
"type": "string",
"maxLength": 253,
"minLength": 4,
"title": "Host"
}
},
"type": "object",
"required": [
"host"
],
"title": "NewResellerDomain",
"description": "A host the reseller wants to serve their portal on. Only the name is\ntheirs to choose; the CNAME target, status and certificate are ours."
}201 — Successful Response
json
{
"additionalProperties": true,
"type": "object",
"title": "Response Add Domain Api V1 Reseller Settings Domains Post"
}422 — Validation Error
json
{
"properties": {
"detail": {
"items": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
}POST /api/v1/reseller-settings/domains/{host}/check
Check Domain
Re-run verification and issuance for one host — the "Check again" button.
Idempotent, so a reseller who has just fixed their CNAME can press it as often as they like; certbot's --keep-until-expiring makes a re-issue on an already-live host a no-op.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
host | path | yes | string |
200 — Successful Response
json
{
"type": "object",
"additionalProperties": true,
"title": "Response Check Domain Api V1 Reseller Settings Domains Host Check Post"
}422 — Validation Error
json
{
"properties": {
"detail": {
"items": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
}POST /api/v1/reseller-settings/domains/{host}/primary
Make Domain Primary
Choose which live host is this reseller's canonical address — the one its outbound e-mail links back to.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
host | path | yes | string |
200 — Successful Response
json
{
"type": "object",
"additionalProperties": true,
"title": "Response Make Domain Primary Api V1 Reseller Settings Domains Host Primary Post"
}422 — Validation Error
json
{
"properties": {
"detail": {
"items": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
}DELETE /api/v1/reseller-settings/domains/{host}
Delete Domain
Stop serving this reseller's portal on host. The certificate is kept (Let's Encrypt rate-limits issuance, not storage) so re-adding is instant.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
host | path | yes | string |
200 — Successful Response
json
{
"type": "object",
"additionalProperties": true,
"title": "Response Delete Domain Api V1 Reseller Settings Domains Host Delete"
}422 — Validation Error
json
{
"properties": {
"detail": {
"items": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
}GET /api/v1/reseller-settings/clients
List Clients
The reseller's own customers with a usable email address.
The same reseller_id ownership boundary the My Customers grid enforces — read here rather than through the grid because the compose screen needs addresses, not a paged view, and because the send path re-checks this exact list anyway.
Answers 200 with a reason rather than 403 when this login has no reseller account of its own (a platform superuser is the usual case: there is no "logged in reseller" for an operator to compose as). "You are signed in as an operator" is a fact about the page, not a failure of the request, and returning it as an error made the screen render a red "Failed to load" where an explanation belonged. Same shape as GET /domains, which was already doing this. The SEND path still refuses outright — see :func:email_clients.
200 — Successful Response
json
{
"additionalProperties": true,
"type": "object",
"title": "Response List Clients Api V1 Reseller Settings Clients Get"
}POST /api/v1/reseller-settings/clients/email
Email Clients
Send one message to the selected customers.
Every recipient is re-resolved against reseller_id here rather than trusted from the request body: the ids arrive from a browser, and a reseller must never be able to mail a row it does not own by editing the payload.
Sent one message per recipient (not one Bcc blast) so each is addressed personally, each gets its own Email Log row, and one bad address cannot stop the rest.
Request body
json
{
"properties": {
"customer_ids": {
"items": {
"type": "string"
},
"type": "array",
"maxItems": 500,
"title": "Customer Ids"
},
"subject": {
"type": "string",
"maxLength": 255,
"minLength": 1,
"title": "Subject"
},
"body": {
"type": "string",
"maxLength": 100000,
"minLength": 1,
"title": "Body"
},
"copy_self": {
"type": "boolean",
"title": "Copy Self",
"default": false
}
},
"type": "object",
"required": [
"subject",
"body"
],
"title": "ResellerClientEmail",
"description": "A free-form message from a reseller to its own customers.\n\n``customer_ids`` are ``AccCustomer`` uuids on the books site; every one is\nre-checked against ``reseller_id`` at send time, so a reseller can only ever\nmail rows it actually owns (see ``_require_own_reseller``). Sent from the\nchannel mailbox with the reseller's own name and reply-to on it — see\n:mod:`app.services.reseller_email_branding`."
}200 — Successful Response
json
{
"properties": {
"ok": {
"type": "boolean",
"title": "Ok",
"default": true
},
"sent": {
"type": "integer",
"title": "Sent",
"default": 0
},
"failed": {
"type": "integer",
"title": "Failed",
"default": 0
},
"errors": {
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array",
"title": "Errors"
},
"from_addr": {
"type": "string",
"title": "From Addr",
"default": ""
},
"from_name": {
"type": "string",
"title": "From Name",
"default": ""
},
"reply_to": {
"type": "string",
"title": "Reply To",
"default": ""
}
},
"type": "object",
"title": "ResellerClientEmailResult"
}422 — Validation Error
json
{
"properties": {
"detail": {
"items": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
}GET /api/v1/reseller-settings/pricing
Get Pricing
Every item this reseller is actually billed for, with our price, their cost, and what they charge.
Scoped to items that appear on this reseller's own invoices rather than the whole catalogue: a reseller sells a handful of products and a full item list would be a few thousand rows they have to search rather than a page they can read.
200 — Successful Response
json
{
"additionalProperties": true,
"type": "object",
"title": "Response Get Pricing Api V1 Reseller Settings Pricing Get"
}PUT /api/v1/reseller-settings/pricing
Update Pricing
Save this reseller's retail prices. A rate of null clears the override and drops that item back to our price.
Request body
json
{
"properties": {
"prices": {
"items": {
"properties": {
"item_id": {
"type": "integer",
"title": "Item Id"
},
"rate": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"title": "Rate"
},
"item_code": {
"anyOf": [
{
"type": "string",
"maxLength": 140
},
{
"type": "null"
}
],
"title": "Item Code"
},
"item_name": {
"anyOf": [
{
"type": "string",
"maxLength": 255
},
{
"type": "null"
}
],
"title": "Item Name"
}
},
"type": "object",
"required": [
"item_id"
],
"title": "ResellerRetailPrice",
"description": "One item's retail price for this reseller.\n\n``rate=None`` is not \"free\" — it clears the override so the item falls back\nto our own Customer price. That distinction is why the field is nullable\nrather than defaulting to 0."
},
"type": "array",
"maxItems": 2000,
"title": "Prices"
}
},
"type": "object",
"title": "ResellerRetailPricingUpdate"
}200 — Successful Response
json
{
"additionalProperties": true,
"type": "object",
"title": "Response Update Pricing Api V1 Reseller Settings Pricing Put"
}422 — Validation Error
json
{
"properties": {
"detail": {
"items": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
}GET /api/v1/reseller-settings/billing
Get Billing Settings
Whether this reseller issues its customers' invoices through the portal, plus the payment wording those invoices carry.
200 — Successful Response
json
{
"additionalProperties": true,
"type": "object",
"title": "Response Get Billing Settings Api V1 Reseller Settings Billing Get"
}PUT /api/v1/reseller-settings/billing
Update Billing Settings
Request body
json
{
"properties": {
"enabled": {
"type": "boolean",
"title": "Enabled",
"default": false
},
"payment_terms": {
"type": "string",
"maxLength": 2000,
"title": "Payment Terms",
"default": ""
},
"footer_note": {
"type": "string",
"maxLength": 2000,
"title": "Footer Note",
"default": ""
}
},
"type": "object",
"title": "ResellerBillingSettings",
"description": "Whether this reseller issues its customers' invoices through the portal.\n\nOff until switched on: a reseller billing in its own accounting system must\nnot have us start sending documents to its customers because a feature\nshipped.\n\n``payment_terms`` is the only place a bank account may appear. We do not\ncollect on a reseller's behalf, so the document carries no payment link and\nnone of our details — if the reseller's customer is to pay them, this text\nis what says how."
}200 — Successful Response
json
{
"additionalProperties": true,
"type": "object",
"title": "Response Update Billing Settings Api V1 Reseller Settings Billing Put"
}422 — Validation Error
json
{
"properties": {
"detail": {
"items": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
}