REST API

Plan, currency and billing

The company's plan, the currency it sees prices in and the billing details.

  • Plan and currency (the Company → Plan screen; admins and owners only, 403 for others). Nothing is charged during the beta. Each company has a currency (BRL, USD, EUR, GBP, MXN, ARS, CLP or COP), set at creation from the country it was created in (without one, BRL), and each plan has a price defined in each currency, monthly and yearly, with no conversion. Amounts come in amount_minor, an integer in the currency's smallest unit (4990 is R$ 49.90; the Chilean peso has no decimals), with amount and formatted (as the screen shows it) next to it.
  • GET /billing (tracker:read): currency, currency_locked (with billing on, only the Aquarela team changes the currency), currencies, plan (key, name, description, ai_credits_per_cycle, null for the server default, storage_gb, file storage in GB, null for the default, features, what the plan includes, and prices in the company's currency), plan_source (subscription, or default when the default plan applies), price (the current one), subscription (status: trialing, active, past_due or canceled; interval: month or year; current_period_start, current_period_end, trial_ends_at and billing_provider, null while there's no billing), plans (the ones the company can have, with the price in its currency), billing_details and plan_request (the paid plan request waiting for the Aquarela team: plan, interval, requested_by and created_at; null without a request).
  • PATCH /billing (tracker:write), in JSON: {"currency": "USD"} changes the currency; {"billing_details": {...}} changes the billing details, only the fields sent (null clears): kind (company or individual), legal_name, email, country (two-letter ISO), address_line1, address_line2, city, state, postal_code, tax_id_type and tax_id. The tax id follows the country, with Stripe's types: br_cnpj (company) and br_cpf (individual), with the check digits verified, us_ein, eu_vat, gb_vat, mx_rfc, ar_cuit, cl_tin and co_nit; without tax_id_type, the country's applies. Returns the same as the GET; a refused rule returns 422.
  • POST /billing/plan (tracker:write), in JSON: {"plan": "pro", "interval": "year"} (plan is the key or id of one of the plans; interval, month by default). A free plan in the company's currency changes immediately (outcome: changed); a paid plan, or one without a price in the currency, becomes a request to the Aquarela team (requested), who arranges payment and puts the company on the plan; the current one returns unchanged. Asking for another plan replaces the request. Returns outcome, plan, interval and billing (the same as the GET). DELETE /billing/plan-request (tracker:write) cancels the request ({"cancelled": true}; false without a request). In the MCP: get_billing, update_billing, change_plan and cancel_plan_request.
  • File storage: each plan gives the company space for attachments (storage_gb; the default is 10 GB), adding up the attachments on tasks (including the ones on comments and the approval versions), the help desk and Chats, direct messages too. Profile photos, logos and project icons don't count. When the storage runs out, sending a new attachment (screen, API and MCP) returns 422 with the limit message; files a customer sends to the help desk still go in, so no ticket is lost. GET /billing brings storage: used_bytes, limit_bytes, plan_storage_gb (null on the default), state (ok, warning at 90% or more, full) and the total per place in tasks, tickets, chat and direct_messages (bytes and files).
  • Company files (the Company → Files screen; admins and owners only, 403 for others): GET /files (tracker:read) returns storage (as in GET /billing), total, has_more and files, newest first (?sort=size, largest first), each with id, origin (task, ticket or chat), name, type, size_bytes, created_at, uploaded_by, project (id, slug, name), issue (id, code, title, comment_id), ticket (id, number, subject) or chat_message (id, thread_id), depending on the origin, url (where it is in tracker), download_url, can_delete and locked (proof: a version sent for approval; trash: a task or project in the trash; null when it can be deleted). Filters: ?origin=, ?query= (part of the name), ?limit= up to 100 and ?offset=. Files in direct messages count toward the storage but aren't listed: only the two people in the conversation can see them. GET /files/{id} (tracker:read) downloads the file; DELETE /files/{id} (tracker:write) deletes the file from where it is and frees the space ({"deleted": true, "origin": ..., "name": ...}; a locked file returns 422). In the MCP: list_files and delete_file.