{"openapi":"3.1.0","info":{"title":"Total Stack Portal API","version":"1.0.0"},"servers":[{"url":"https:\/\/app.totalstacksolutions.com"}],"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer"}}},"security":[{"bearer":[]}],"paths":{"\/api\/v1\/operations\/clients.list":{"post":{"operationId":"clients_list","summary":"List client accounts with status, sales owner and monthly recurring revenue.","x-required-permission":"see-clients","requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"search":{"type":"string","description":"Match on client name."},"status":{"type":"string","enum":["lead","active","paused","closed"]}}}}}},"responses":{"200":{"description":"{\"status\":\"ok\",\"result\":\u2026}"},"202":{"description":"{\"status\":\"pending_approval\",\"request_id\":\u2026} \u2014 writes by agents"},"403":{"description":"The key\u2019s role cannot run this operation."},"422":{"description":"Validation failed."}}}},"\/api\/v1\/operations\/clients.get":{"post":{"operationId":"clients_get","summary":"Get one client: services and prices, sites, domains, open requests and invoice status. Staff keys also see cost and margin.","x-required-permission":"view-account","requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"client_id":{"type":"integer","description":"Required for staff keys; client keys always get their own account."}}}}}},"responses":{"200":{"description":"{\"status\":\"ok\",\"result\":\u2026}"},"202":{"description":"{\"status\":\"pending_approval\",\"request_id\":\u2026} \u2014 writes by agents"},"403":{"description":"The key\u2019s role cannot run this operation."},"422":{"description":"Validation failed."}}}},"\/api\/v1\/operations\/invoices.list":{"post":{"operationId":"invoices_list","summary":"List invoices (mirrored from Stripe). Filter by client or status; \"failed\" means open with a failed payment attempt.","x-required-permission":"view-account","requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"client_id":{"type":"integer"},"status":{"type":"string","enum":["open","paid","failed","void","uncollectible"]}}}}}},"responses":{"200":{"description":"{\"status\":\"ok\",\"result\":\u2026}"},"202":{"description":"{\"status\":\"pending_approval\",\"request_id\":\u2026} \u2014 writes by agents"},"403":{"description":"The key\u2019s role cannot run this operation."},"422":{"description":"Validation failed."}}}},"\/api\/v1\/operations\/metrics.get":{"post":{"operationId":"metrics_get","summary":"Business metrics: MRR, gross margin, outstanding balance, Hostinger cost and MRR by product line.","x-required-permission":"see-money","requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"{\"status\":\"ok\",\"result\":\u2026}"},"202":{"description":"{\"status\":\"pending_approval\",\"request_id\":\u2026} \u2014 writes by agents"},"403":{"description":"The key\u2019s role cannot run this operation."},"422":{"description":"Validation failed."}}}},"\/api\/v1\/operations\/catalog.list":{"post":{"operationId":"catalog_list","summary":"List catalog products with cost, list price, default margin, floor and Stripe sync status.","x-required-permission":"see-money","requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"{\"status\":\"ok\",\"result\":\u2026}"},"202":{"description":"{\"status\":\"pending_approval\",\"request_id\":\u2026} \u2014 writes by agents"},"403":{"description":"The key\u2019s role cannot run this operation."},"422":{"description":"Validation failed."}}}},"\/api\/v1\/operations\/domains.list":{"post":{"operationId":"domains_list","summary":"List domains in the TSS Hostinger account with client, expiry and auto-renew.","x-required-permission":"see-clients","requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"expiring_within_days":{"type":"integer"}}}}}},"responses":{"200":{"description":"{\"status\":\"ok\",\"result\":\u2026}"},"202":{"description":"{\"status\":\"pending_approval\",\"request_id\":\u2026} \u2014 writes by agents"},"403":{"description":"The key\u2019s role cannot run this operation."},"422":{"description":"Validation failed."}}}},"\/api\/v1\/operations\/dns.get":{"post":{"operationId":"dns_get","summary":"Get the DNS records for a domain hosted in the TSS Hostinger account.","x-required-permission":"provision","requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"domain":{"type":"string"}},"required":["domain"]}}}},"responses":{"200":{"description":"{\"status\":\"ok\",\"result\":\u2026}"},"202":{"description":"{\"status\":\"pending_approval\",\"request_id\":\u2026} \u2014 writes by agents"},"403":{"description":"The key\u2019s role cannot run this operation."},"422":{"description":"Validation failed."}}}},"\/api\/v1\/operations\/tasks.list":{"post":{"operationId":"tasks_list","summary":"List change requests and project tasks. Contractors only see tasks assigned to them, without client details.","x-required-permission":"view-tasks","requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["open","in_progress","review","done","canceled"]},"kind":{"type":"string","enum":["change_request","project_task"]}}}}}},"responses":{"200":{"description":"{\"status\":\"ok\",\"result\":\u2026}"},"202":{"description":"{\"status\":\"pending_approval\",\"request_id\":\u2026} \u2014 writes by agents"},"403":{"description":"The key\u2019s role cannot run this operation."},"422":{"description":"Validation failed."}}}},"\/api\/v1\/operations\/email.list_mailboxes":{"post":{"operationId":"email_list_mailboxes","summary":"List mailboxes on the TSS Hostinger account with their client, storage use and who can open them. Message contents are never available to agents.","x-required-permission":"manage-email","requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"client_id":{"type":"integer","description":"Omit for all clients; 0 for Total Stack\u2019s own mailboxes."}}}}}},"responses":{"200":{"description":"{\"status\":\"ok\",\"result\":\u2026}"},"202":{"description":"{\"status\":\"pending_approval\",\"request_id\":\u2026} \u2014 writes by agents"},"403":{"description":"The key\u2019s role cannot run this operation."},"422":{"description":"Validation failed."}}}},"\/api\/v1\/operations\/hosting.issues":{"post":{"operationId":"hosting_issues","summary":"What needs attention in Hostinger and billing: domains or sites not assigned to a client, client items not on any bill, renewals Total Stack will pay for a client who isn\u2019t paying, and invoices unpaid for over 30 days.","x-required-permission":"see-money","requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"{\"status\":\"ok\",\"result\":\u2026}"},"202":{"description":"{\"status\":\"pending_approval\",\"request_id\":\u2026} \u2014 writes by agents"},"403":{"description":"The key\u2019s role cannot run this operation."},"422":{"description":"Validation failed."}}}},"\/api\/v1\/operations\/change_requests.create":{"post":{"operationId":"change_requests_create","summary":"Submit a website change request for a client. Counts toward the plan\u2019s yearly allowance.","x-required-permission":"request-changes","requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"client_id":{"type":"integer","description":"Staff keys only."},"title":{"type":"string"},"body":{"type":"string","description":"What should change, and where."},"site_id":{"type":"integer"},"reason":{"type":"string","description":"Shown to the human approver."}},"required":["title","reason"]}}}},"responses":{"200":{"description":"{\"status\":\"ok\",\"result\":\u2026}"},"202":{"description":"{\"status\":\"pending_approval\",\"request_id\":\u2026} \u2014 writes by agents"},"403":{"description":"The key\u2019s role cannot run this operation."},"422":{"description":"Validation failed."}}}},"\/api\/v1\/operations\/clients.set_price":{"post":{"operationId":"clients_set_price","summary":"Set a custom price for one of a client\u2019s services. Checked against the product\u2019s default margin and floor.","x-required-permission":"set-client-price","requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"client_product_id":{"type":"integer"},"price_cents":{"type":"integer","description":"Per billing period, before tax."},"reason":{"type":"string","description":"Shown to the human approver."},"apply_now":{"type":"boolean","description":"Prorate immediately instead of from the next renewal."}},"required":["client_product_id","price_cents","reason","reason"]}}}},"responses":{"200":{"description":"{\"status\":\"ok\",\"result\":\u2026}"},"202":{"description":"{\"status\":\"pending_approval\",\"request_id\":\u2026} \u2014 writes by agents"},"403":{"description":"The key\u2019s role cannot run this operation."},"422":{"description":"Validation failed."}}}},"\/api\/v1\/operations\/quotes.create":{"post":{"operationId":"quotes_create","summary":"Draft a fixed-scope quote for a client with a deposit and a sign-off payment. Drafts are not sent until a person sends them.","x-required-permission":"manage-clients","requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"client_id":{"type":"integer"},"title":{"type":"string"},"scope":{"type":"string","description":"Markdown: what we will build."},"exclusions":{"type":"string"},"timeline":{"type":"string"},"total_cents":{"type":"integer","description":"Before tax."},"cost_cents":{"type":"integer","description":"Internal estimate; never shown to the client."},"deposit_percent":{"type":"integer","description":"Default 50."},"valid_days":{"type":"integer","description":"Default 14."},"reason":{"type":"string","description":"Shown to the human approver."}},"required":["client_id","title","scope","total_cents","reason"]}}}},"responses":{"200":{"description":"{\"status\":\"ok\",\"result\":\u2026}"},"202":{"description":"{\"status\":\"pending_approval\",\"request_id\":\u2026} \u2014 writes by agents"},"403":{"description":"The key\u2019s role cannot run this operation."},"422":{"description":"Validation failed."}}}},"\/api\/v1\/operations\/invoices.send_reminder":{"post":{"operationId":"invoices_send_reminder","summary":"Email the client a pay link for an open invoice (Stripe hosted invoice page).","x-required-permission":"manage-clients","requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"invoice_id":{"type":"integer"},"reason":{"type":"string","description":"Shown to the human approver."}},"required":["invoice_id","reason"]}}}},"responses":{"200":{"description":"{\"status\":\"ok\",\"result\":\u2026}"},"202":{"description":"{\"status\":\"pending_approval\",\"request_id\":\u2026} \u2014 writes by agents"},"403":{"description":"The key\u2019s role cannot run this operation."},"422":{"description":"Validation failed."}}}},"\/api\/v1\/operations\/invoices.refund":{"post":{"operationId":"invoices_refund","summary":"Refund all or part of a paid invoice through Stripe.","x-required-permission":"refund","requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"invoice_id":{"type":"integer"},"amount_cents":{"type":"integer","description":"Omit for a full refund."},"reason":{"type":"string","description":"Shown to the human approver."}},"required":["invoice_id","reason","reason"]}}}},"responses":{"200":{"description":"{\"status\":\"ok\",\"result\":\u2026}"},"202":{"description":"{\"status\":\"pending_approval\",\"request_id\":\u2026} \u2014 writes by agents"},"403":{"description":"The key\u2019s role cannot run this operation."},"422":{"description":"Validation failed."}}}},"\/api\/v1\/operations\/invoices.close":{"post":{"operationId":"invoices_close","summary":"Remove an unpaid invoice: void it (no longer owed) or write it off as uncollectible.","x-required-permission":"refund","requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"invoice_id":{"type":"integer"},"action":{"type":"string","description":"void = no longer owed; uncollectible = written off, kept on record.","enum":["void","uncollectible"]},"reason":{"type":"string","description":"Shown to the human approver."}},"required":["invoice_id","action","reason","reason"]}}}},"responses":{"200":{"description":"{\"status\":\"ok\",\"result\":\u2026}"},"202":{"description":"{\"status\":\"pending_approval\",\"request_id\":\u2026} \u2014 writes by agents"},"403":{"description":"The key\u2019s role cannot run this operation."},"422":{"description":"Validation failed."}}}},"\/api\/v1\/operations\/clients.set_status":{"post":{"operationId":"clients_set_status","summary":"Change a client to lead, active, paused (stop charging) or closed (cancel subscriptions).","x-required-permission":"manage-clients","requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"client_id":{"type":"integer"},"status":{"type":"string","enum":["lead","active","paused","closed"]},"reason":{"type":"string","description":"Shown to the human approver."},"cancel_now":{"type":"boolean","description":"Closing only: cancel subscriptions now instead of at period end."},"disable_logins":{"type":"boolean","description":"Closing only: switch off the client\u2019s portal logins."}},"required":["client_id","status","reason","reason"]}}}},"responses":{"200":{"description":"{\"status\":\"ok\",\"result\":\u2026}"},"202":{"description":"{\"status\":\"pending_approval\",\"request_id\":\u2026} \u2014 writes by agents"},"403":{"description":"The key\u2019s role cannot run this operation."},"422":{"description":"Validation failed."}}}},"\/api\/v1\/operations\/hosting.rebill_charge":{"post":{"operationId":"hosting_rebill_charge","summary":"Invoice a client once for a past Hostinger charge (a domain or plan bought for them).","x-required-permission":"set-client-price","requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"hostinger_subscription_id":{"type":"integer","description":"Portal id of the Hostinger subscription (hosting.issues \/ Assign & bill)."},"client_id":{"type":"integer"},"price_cents":{"type":"integer","description":"Pre-tax price; omit for the suggested cost-plus price."},"description":{"type":"string","description":"What the client reads on the invoice; omit for item + term."},"reason":{"type":"string","description":"Shown to the human approver."}},"required":["hostinger_subscription_id","client_id","reason"]}}}},"responses":{"200":{"description":"{\"status\":\"ok\",\"result\":\u2026}"},"202":{"description":"{\"status\":\"pending_approval\",\"request_id\":\u2026} \u2014 writes by agents"},"403":{"description":"The key\u2019s role cannot run this operation."},"422":{"description":"Validation failed."}}}},"\/api\/v1\/operations\/dns.update_record":{"post":{"operationId":"dns_update_record","summary":"Set (replace) or add a DNS record on a domain in the TSS Hostinger account. Validated with Hostinger before it is applied.","x-required-permission":"provision","requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"domain":{"type":"string"},"name":{"type":"string","description":"Subdomain label, or \"@\" for the root."},"type":{"type":"string","enum":["A","AAAA","CNAME","ALIAS","MX","TXT","SRV","CAA"]},"content":{"type":"string"},"ttl":{"type":"integer"},"mode":{"type":"string","description":"replace (default) swaps existing records of this name and type.","enum":["replace","append"]},"reason":{"type":"string","description":"Shown to the human approver."}},"required":["domain","name","type","content","reason"]}}}},"responses":{"200":{"description":"{\"status\":\"ok\",\"result\":\u2026}"},"202":{"description":"{\"status\":\"pending_approval\",\"request_id\":\u2026} \u2014 writes by agents"},"403":{"description":"The key\u2019s role cannot run this operation."},"422":{"description":"Validation failed."}}}},"\/api\/v1\/operations\/sites.provision":{"post":{"operationId":"sites_provision","summary":"Create a new PHP website for a client on the TSS Hostinger Agency plan. Setup finishes in the background; the site shows as live after the next sync.","x-required-permission":"provision","requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"client_id":{"type":"integer"},"domain":{"type":"string"},"reason":{"type":"string","description":"Shown to the human approver."}},"required":["client_id","domain","reason"]}}}},"responses":{"200":{"description":"{\"status\":\"ok\",\"result\":\u2026}"},"202":{"description":"{\"status\":\"pending_approval\",\"request_id\":\u2026} \u2014 writes by agents"},"403":{"description":"The key\u2019s role cannot run this operation."},"422":{"description":"Validation failed."}}}},"\/api\/v1\/operations\/vps.power":{"post":{"operationId":"vps_power","summary":"Start, stop, restart or snapshot a Hostinger VPS.","x-required-permission":"provision","requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"vps_id":{"type":"integer","description":"Hostinger virtual machine id."},"action":{"type":"string","enum":["start","stop","restart","snapshot"]},"reason":{"type":"string","description":"Shown to the human approver."}},"required":["vps_id","action","reason"]}}}},"responses":{"200":{"description":"{\"status\":\"ok\",\"result\":\u2026}"},"202":{"description":"{\"status\":\"pending_approval\",\"request_id\":\u2026} \u2014 writes by agents"},"403":{"description":"The key\u2019s role cannot run this operation."},"422":{"description":"Validation failed."}}}},"\/api\/v1\/operations\/email.create_mailbox":{"post":{"operationId":"email_create_mailbox","summary":"Create a mailbox on a domain that already has a Hostinger email service. For a client domain this adds one mailbox to their Business email bill. The password is not returned; a person resets it in the portal when a mail app needs one.","x-required-permission":"manage-email","requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"domain":{"type":"string","description":"Domain with an active email service."},"local_part":{"type":"string","description":"The part before the @."},"for_user_id":{"type":"integer","description":"Portal user who should be able to open it."},"reason":{"type":"string","description":"Shown to the human approver."}},"required":["domain","local_part","reason"]}}}},"responses":{"200":{"description":"{\"status\":\"ok\",\"result\":\u2026}"},"202":{"description":"{\"status\":\"pending_approval\",\"request_id\":\u2026} \u2014 writes by agents"},"403":{"description":"The key\u2019s role cannot run this operation."},"422":{"description":"Validation failed."}}}},"\/api\/v1\/operations\/email.order_seats":{"post":{"operationId":"email_order_seats","summary":"Buy a Hostinger Business Email service with a number of mailboxes. This charges the Total Stack Hostinger payment method. The domain is attached in Hostinger afterwards, then the service appears in the portal.","x-required-permission":"provision","requestBody":{"content":{"application\/json":{"schema":{"type":"object","properties":{"seats":{"type":"integer","description":"Number of mailboxes."},"reason":{"type":"string","description":"Shown to the human approver."}},"required":["seats","reason"]}}}},"responses":{"200":{"description":"{\"status\":\"ok\",\"result\":\u2026}"},"202":{"description":"{\"status\":\"pending_approval\",\"request_id\":\u2026} \u2014 writes by agents"},"403":{"description":"The key\u2019s role cannot run this operation."},"422":{"description":"Validation failed."}}}}}}