CloudArch HTTP API
Overview
The CloudArch REST API exposes the same surface used by the web app: scripts, comments, collections, profiles, quotas, billing, and account self-service. All requests are made over HTTPS to https://api.cloud-arch.ru and accept and return application/json. All resource identifiers are UUIDs unless noted.
This is a stable /v1 surface. Breaking changes ship under a new prefix.
Authentication
Generate an API key from /dashboard/api-keys and pass it as a Bearer token on every request:
Authorization: Bearer ca_<your-key>Each key is rate limited to 1000 requests per hour. Keys are user-scoped: a request authenticated with your key acts as you and is bound by your tier limits, quotas, and ownership rules.
When calling from the web origin you can also rely on the session cookie (credentials: 'include'). The Bearer token takes precedence when both are present.
Quickstart
List public scripts in the gallery:
curl -H "Authorization: Bearer ca_..." \
https://api.cloud-arch.ru/v1/scripts/gallerySuccessful responses look like { "items": [...], "totalCount": <int> }. Most endpoints return a single resource as { "item": {...} } and a write-only acknowledgement as { "ok": true }.
Scripts
GET /v1/scripts/gallery
Search and paginate the public + template gallery. Optional query: query, category, tag, page (default 1), pageSize.
curl "https://api.cloud-arch.ru/v1/scripts/gallery?query=kafka&page=1&pageSize=20"{
"items": [
{
"id": "8c7e...",
"name": "Kafka cluster",
"slug": "kafka-cluster",
"description": "Three-broker Kafka with ZooKeeper",
"type": "topology",
"category": "Infrastructure",
"isPublic": true,
"viewCount": 421,
"starCount": 7,
"tags": ["kafka", "messaging"]
}
],
"totalCount": 1
}GET /v1/scripts/:id
Fetch one script by UUID or by slug. Returns 404 if the script is private and the requester is not the owner.
curl -H "Authorization: Bearer ca_..." \
https://api.cloud-arch.ru/v1/scripts/kafka-cluster{
"item": {
"id": "8c7e...",
"name": "Kafka cluster",
"code": "const topology = new TopologyBuilder(true);\n...",
"type": "topology",
"isPublic": true
}
}POST /v1/scripts
Create a new script. Subject to draftsPerDay quota; publishPerDay is checked separately if isPublic is true. Topology scripts are validated server-side; validation failures return 422.
curl -X POST -H "Authorization: Bearer ca_..." \
-H "Content-Type: application/json" \
-d '{"name":"My diagram","type":"topology","code":"const t = new TopologyBuilder(true);","isPublic":false}' \
https://api.cloud-arch.ru/v1/scripts{
"item": {
"id": "f4d2...",
"name": "My diagram",
"type": "topology",
"isPublic": false
}
}PATCH /v1/scripts/:id
Update fields on a script you own. Body keys are optional; flipping isPublic: true re-checks the publish quota and stamps publishedAt.
curl -X PATCH -H "Authorization: Bearer ca_..." \
-H "Content-Type: application/json" \
-d '{"description":"Updated copy","isPublic":true}' \
https://api.cloud-arch.ru/v1/scripts/f4d2...{ "item": { "id": "f4d2...", "isPublic": true, "publishedAt": "2026-04-30T10:00:00.000Z" } }DELETE /v1/scripts/:id
Permanently delete a script you own.
curl -X DELETE -H "Authorization: Bearer ca_..." \
https://api.cloud-arch.ru/v1/scripts/f4d2...{ "ok": true }POST /v1/scripts/:id/star
Toggle a star on a script. Returns the new state.
curl -X POST -H "Authorization: Bearer ca_..." \
https://api.cloud-arch.ru/v1/scripts/8c7e.../star{ "starred": true }POST /v1/scripts/:id/view
Increment the view counter. No auth required. Use sparingly: this is intended for embed/viewer pages, not crawlers.
curl -X POST https://api.cloud-arch.ru/v1/scripts/8c7e.../view{ "ok": true, "viewCount": 422 }Comments
GET /v1/scripts/:id/comments
List comments on a script. Optional query: targetType (script | node | edge) and targetId to filter to a specific node/edge anchor.
curl "https://api.cloud-arch.ru/v1/scripts/8c7e.../comments?targetType=node&targetId=broker-1"{
"items": [
{
"id": "a91b...",
"scriptId": "8c7e...",
"userId": "u-123",
"content": "Why three brokers and not five?",
"targetType": "node",
"targetId": "broker-1",
"createdAt": "2026-04-29T08:21:00.000Z",
"author": { "username": "ada", "fullName": "Ada Lovelace", "avatarUrl": null }
}
]
}POST /v1/scripts/:id/comments
Add a comment. Subject to commentsPerHour quota. targetType is required; targetId is required for node and edge targets and ignored for script.
curl -X POST -H "Authorization: Bearer ca_..." \
-H "Content-Type: application/json" \
-d '{"content":"Nice diagram!","targetType":"script"}' \
https://api.cloud-arch.ru/v1/scripts/8c7e.../comments{ "item": { "id": "a91c...", "content": "Nice diagram!", "targetType": "script" } }DELETE /v1/comments/:commentId
Delete one of your own comments. The user-scoped variant is preferred over the legacy DELETE /v1/scripts/:id/comments/:commentId — both work.
curl -X DELETE -H "Authorization: Bearer ca_..." \
https://api.cloud-arch.ru/v1/comments/a91c...{ "ok": true }Collections
Collections are private folders that group scripts owned or starred by the user.
GET /v1/collections
List your collections, including the script count for each.
curl -H "Authorization: Bearer ca_..." \
https://api.cloud-arch.ru/v1/collections{
"items": [
{ "id": "c1...", "name": "Messaging", "color": "#7c3aed", "scriptCount": 3, "createdAt": "2026-04-01T00:00:00.000Z" }
]
}POST /v1/collections
Create a new collection. Body: { name, description?, color? }.
curl -X POST -H "Authorization: Bearer ca_..." \
-H "Content-Type: application/json" \
-d '{"name":"Messaging","color":"#7c3aed"}' \
https://api.cloud-arch.ru/v1/collections{ "item": { "id": "c1...", "name": "Messaging", "scriptCount": 0 } }POST /v1/collections/:id/scripts
Attach a script to a collection. Body: { scriptId }. The script must be owned by you or public.
curl -X POST -H "Authorization: Bearer ca_..." \
-H "Content-Type: application/json" \
-d '{"scriptId":"8c7e..."}' \
https://api.cloud-arch.ru/v1/collections/c1.../scripts{ "ok": true }DELETE /v1/collections/:id/scripts/:scriptId
Remove a script from a collection. The script itself is not deleted.
curl -X DELETE -H "Authorization: Bearer ca_..." \
https://api.cloud-arch.ru/v1/collections/c1.../scripts/8c7e...{ "ok": true }Profiles
GET /v1/profiles/by-username/:username
Public profile lookup. Returns 404 if no profile with that username exists.
curl https://api.cloud-arch.ru/v1/profiles/by-username/ada{
"item": {
"id": "u-123",
"username": "ada",
"fullName": "Ada Lovelace",
"avatarUrl": null,
"createdAt": "2026-01-04T11:30:00.000Z"
}
}Quota
GET /v1/quota/me
Current usage and effective limits for the authenticated user. Used by the dashboard widget. Returns tierId, isAdmin, and an array of { key, used, limit, windowSeconds } entries covering publishPerDay, draftsPerDay, commentsPerHour, and aiChatPerDay.
curl -H "Authorization: Bearer ca_..." \
https://api.cloud-arch.ru/v1/quota/me{
"tierId": "free",
"isAdmin": false,
"quotas": [
{ "key": "publishPerDay", "used": 1, "limit": 5, "windowSeconds": 86400 },
{ "key": "draftsPerDay", "used": 4, "limit": 20, "windowSeconds": 86400 },
{ "key": "commentsPerHour", "used": 0, "limit": 30, "windowSeconds": 3600 },
{ "key": "aiChatPerDay", "used": 0, "limit": 10, "windowSeconds": 86400 }
]
}Billing
All billing endpoints require authentication. CloudArch uses YooKassa as the payment provider; a 503 response means billing is not configured for the current deployment.
GET /v1/billing/me
Return the user’s active subscription (if any), the matching plan, and the 50 most recent payments.
curl -H "Authorization: Bearer ca_..." \
https://api.cloud-arch.ru/v1/billing/me{
"subscription": { "id": "s1...", "planId": "premium-monthly", "status": "active", "cancelAtPeriodEnd": false },
"plan": { "id": "premium-monthly", "priceKopeks": 49900, "intervalDays": 30 },
"payments": [
{ "id": "p1...", "amountKopeks": 49900, "status": "succeeded", "createdAt": "2026-04-01T00:00:00.000Z" }
]
}POST /v1/billing/subscribe
Start a subscription. Body: { planId }. Returns the new subscription id and a YooKassa confirmationUrl to redirect the user to. Returns 409 already_subscribed when an active subscription already exists.
curl -X POST -H "Authorization: Bearer ca_..." \
-H "Content-Type: application/json" \
-d '{"planId":"premium-monthly"}' \
https://api.cloud-arch.ru/v1/billing/subscribe{
"subscriptionId": "s1...",
"paymentId": "yk-pay-9f...",
"confirmationUrl": "https://yoomoney.ru/checkout/payments/v2/contract?orderId=..."
}PATCH /v1/billing/subscription
Toggle cancelAtPeriodEnd on the active subscription. The subscription stays active until the period ends; set the flag back to false to resume.
curl -X PATCH -H "Authorization: Bearer ca_..." \
-H "Content-Type: application/json" \
-d '{"cancelAtPeriodEnd":true}' \
https://api.cloud-arch.ru/v1/billing/subscription{ "subscription": { "id": "s1...", "cancelAtPeriodEnd": true, "status": "active" } }Account
DELETE /v1/account
Permanently delete the authenticated user. Cascades remove sessions, profiles, scripts, stars, comments, collections, AI usage, quota overrides, subscriptions, and payments. Audit-event rows survive with the actor email snapshot. This action cannot be undone.
curl -X DELETE -H "Authorization: Bearer ca_..." \
https://api.cloud-arch.ru/v1/account{ "ok": true }Reports
POST /v1/reports
File a content report against a public script. Body: { targetType: "script", targetId, reason }. The reason must be 10-2000 characters.
curl -X POST -H "Authorization: Bearer ca_..." \
-H "Content-Type: application/json" \
-d '{"targetType":"script","targetId":"8c7e...","reason":"This diagram contains spam links in the description."}' \
https://api.cloud-arch.ru/v1/reports{ "ok": true, "id": "r1..." }Rate limits and quotas
Two layers of throttling apply:
- Per-key rate limit: 1000 requests per hour per API key. Exceeded requests are rejected by the auth layer.
- Per-user quotas: each plan tier has separate caps for daily publishes, daily drafts, hourly comments, and daily AI chat calls. See
GET /v1/quota/mefor the current windows. Exceeding a quota returns429 quota_exceeded. See /pricing for the per-tier numbers.
Errors
All errors are JSON. Common shapes:
| Status | When |
|---|---|
401 | Missing or invalid credentials. |
403 | Authenticated but not allowed (wrong owner, non-admin route, non-public script). |
404 | Resource not found, or hidden from this requester. |
409 | Conflict, e.g. already_subscribed when starting a second subscription. |
413 | payload_too_large — script code or comment exceeds the per-tier byte limit. |
422 | Validation error. Body is a Zod issue list, or for topology scripts a structured DSL validation result. |
429 | { "error": "quota_exceeded", "quota": "<key>", "limit": <number> }. |
503 | Provider unavailable (e.g. billing_not_configured, S3 not configured for thumbnails). |
A typical Zod 422 response:
{
"error": "validation_failed",
"issues": [
{ "path": ["name"], "message": "String must contain at least 1 character(s)" }
]
}