SINGULARITY SERVERS SUPPORT Format: plain text, agent-optimized. Base URL: https:// Companion to api-docs.txt (the full API reference). Read that first for auth and ordering. ## WHAT THIS IS One general-purpose portal for anything you want to say to us. It is not limited to outages or broken orders -- use it for all of: - Help: something is wrong and you are blocked (payment not confirmed, instance never came up, SSH won't connect, lost API key). - Questions: anything the docs don't answer -- pricing, limits, what's allowed on an instance, whether a workload fits, how a flow is supposed to behave. - Product suggestions: a spec, region, OS image, endpoint, or preset you wish existed. - Feedback: what worked, what was confusing, what wasted your time. Docs that misled you are a bug worth reporting; say which line. A human reads every ticket. You do not need a web browser, a login, or your operator present -- a ticket is an ordinary authenticated API call, the same as placing an order. ## AUTH Every endpoint here requires the API key you got from /api/activate, sent as one of: Authorization: Api-Key X-API-Key: Missing/invalid key -> 401 {"detail": "Invalid API key"} No key yet? Do the register -> activate flow in api-docs.txt first. If that flow itself is what's broken, ask your human operator to email support instead -- an unauthenticated agent cannot open a ticket. ## TICKET FIELDS category: help | billing | provisioning | network | account | suggestion | feedback | other (default "other") help -- you are blocked and need a person, and none of the specific ones fit billing -- payment, invoice, amount, refund, an order stuck in "pending" provisioning -- order is "completed" but the instance never appeared network -- instance exists but is unreachable, slow, or losing packets account -- API key, activation, registration, identity suggestion -- a feature or capability you want that doesn't exist yet feedback -- a comment on what does exist, including the docs other -- anything else priority: low | normal | high | urgent (default "normal") Use "urgent" only for a paid instance that is down or unreachable. A suggestion is never urgent; rating routine feedback as urgent gets tickets triaged more slowly, not faster. status: open | awaiting_agent | in_progress | resolved | closed open -- with us, waiting on a human awaiting_agent -- we replied and are waiting on YOU; read the reply and respond in_progress -- a human is actively working it resolved -- we finished it. Final: no further replies accepted closed -- you withdrew it. Final: no further replies accepted reference: a short handle like "SS-3F9A2B4C", stable for the life of the ticket. Quote it to your human operator when escalating. The integer id is what the API uses. ## HOW REPLIES REACH YOU Both channels, the same way order and instance notifications work: - Nostr DM, kind 4 (NIP-04), from the same server identity that sent your activation code. See "FETCHING THE ACTIVATION DM FROM NOSTR" in api-docs.txt for the subscription approach. - Email, to the human operator address on your account. Replies are also readable over HTTP, so you do not have to hold a relay subscription open -- poll GET /api/support/ticket/ instead. Polling once a minute is plenty; a human is on the other end, so expect a reply in hours, not seconds. --- ### POST /api/support/ticket Auth: required Purpose: log a ticket. Request: {"subject": "", "body": "", "category": "", "priority": "", "order_id": } order_id must be an order owned by the authenticated account. Include it whenever the ticket is about a specific order, so support sees the spec and status without asking. Response 201: the ticket object (see GET below), status "open". Errors: 400 {"order_id": ["Order not found for this account."]} 400 {"category": ["\"\" is not a valid choice."]} -- also for priority 401 -- missing or invalid API key Note: you also get a confirmation on both channels. Do not open a second ticket for the same issue while the first is unresolved; reply on the existing one instead. ### GET /api/support/tickets Auth: required Purpose: list your tickets, newest first. No pagination. Reply threads are omitted here -- fetch a single ticket for those. Query params: status= Response 200: [ {"id": , "reference": "", "subject": "", "body": "", "category": "", "priority": "", "status": "", "order_id": , "created_at": "", "updated_at": "", "resolved_at": ""}, ... ] Errors: 400 {"status": ["Must be one of: ..."]} ### GET /api/support/ticket/ Auth: required Purpose: one ticket with its full reply thread. Poll this for replies and status changes. Tickets owned by other accounts are invisible (IDOR-safe). Response 200: the list shape above plus "replies": [ {"id": , "author": "agent" | "support", "body": "", "created_at": ""}, ... ] (oldest first) "agent" is you; "support" is us. Errors: 404 {"detail": "Ticket not found."} ### POST /api/support/ticket//reply Auth: required Purpose: add a message to the thread -- answer a question we asked, add detail, or follow up. Sets the ticket back to "open" so we know it's our turn. Request: {"body": ""} Response 201: the updated ticket object, including the new reply. Errors: 404 {"detail": "Ticket not found."} 409 {"detail": "Ticket is ; open a new ticket instead."} -- resolved and closed tickets are final and take no further replies ### POST /api/support/ticket//close Auth: required Purpose: withdraw a ticket you no longer need answered (it resolved itself, you found the answer, you filed it by mistake). Idempotent; no request body. Closing is final -- a closed ticket cannot be reopened or replied to, so open a new one if the issue returns. Response 200: the updated ticket object, status "closed", resolved_at set. Errors: 404 {"detail": "Ticket not found."} --- ## WRITING A TICKET THAT GETS ANSWERED IN ONE ROUND TRIP Assume the human reading it cannot see your logs and has not read this conversation. Put the evidence in `body`: - the order_id (and set the order_id field too), plus what GET /api/order/ returns now - what you expected and what actually happened - exact error text, exit codes, and timestamps (UTC) -- not paraphrases - what you already tried A ticket that says only "it doesn't work" costs a round trip and a few hours. Check first, then file. Most "stuck" orders are answered by re-reading GET /api/order/: an order sits in "pending" until the payment confirms, and instance_ipv6 stays empty until provisioning finishes. Confirm the state is genuinely wrong before filing -- but if it is, file rather than retrying blindly. Repeatedly re-ordering to work around a problem costs you real bitcoin and does not fix anything. For a suggestion or feedback ticket none of the above applies -- just say the thing plainly. Say what you were trying to do and what you wanted instead. No order_id needed. ## TYPICAL FLOW 1. POST /api/support/ticket {subject, body, category, priority, order_id?} -> id, reference 2. poll GET /api/support/ticket/ (or watch for the Nostr DM / email) 3. when status is "awaiting_agent", read the last "support" reply and answer it with POST /api/support/ticket//reply {body} 4. repeat 2-3 until we mark it "resolved", or POST .../close if you no longer need it ## EXAMPLE curl -X POST https://singularityservers.com/api/support/ticket \ -H "Authorization: Api-Key $API_KEY" \ -H "Content-Type: application/json" \ -d '{"subject":"SSH refused on new instance", "body":"Order 42 went completed at 2026-09-16T04:10Z and instance_ipv6 is 2a01:...:f3c2, but ssh root@2a01:...:f3c2 times out after 30s. Tried from two networks. Key matches the ssh_public_key on the order.", "category":"network", "priority":"high", "order_id":42}'