Cloud loyalty, support, and product operations
Mockarty Cloud keeps customer and operator actions on separate authorization surfaces. Customer methods always use the signed-in account and an explicit Space. Operator methods require a narrowly scoped API token: operator:support:read, operator:support:write, or operator:analytics:read. Do not use wildcard tokens for automation.
Customer loyalty
List the current account’s redemption history or redeem one published promotion:
page, err := client.CloudCustomer().ListLoyaltyRedemptions(ctx, spaceID, "", 25)
redemption, err := client.CloudCustomer().RedeemLoyalty(ctx, spaceID, "WELCOME", "RU", "redeem-welcome-01")
page = client.cloud_customer.list_loyalty_redemptions(space_id, limit=25)
redemption = client.cloud_customer.redeem_loyalty(space_id, "WELCOME", "RU", "redeem-welcome-01")
Map<String, Object> page = client.cloudCustomer().listLoyaltyRedemptions(spaceId, "", 25);
Map<String, Object> redemption = client.cloudCustomer().redeemLoyalty(spaceId, "WELCOME", "RU", "redeem-welcome-01");
mockarty-cli cloud-customer loyalty-list --space "$SPACE_ID" --limit 25
mockarty-cli cloud-customer loyalty-redeem --space "$SPACE_ID" --code WELCOME --region RU --idempotency-key redeem-welcome-01
Keep the idempotency key unchanged only for an exact retry of the same redemption.
Customer support
Open and continue a private support case inside an explicit Space:
opened, err := client.CloudCustomer().OpenSupportCase(ctx, spaceID, mockarty.CloudSupportOpenRequest{
Subject: "Runner is unavailable", Category: "runtime", Priority: "normal",
Message: "The issue is reproducible after reconnect.", IdempotencyKey: "support-open-01",
})
opened = client.cloud_customer.open_support_case(
space_id, "Runner is unavailable", "runtime", "normal",
"The issue is reproducible after reconnect.", "support-open-01",
)
Map<String, Object> opened = client.cloudCustomer().openSupportCase(
spaceId, "Runner is unavailable", "runtime", "normal",
"The issue is reproducible after reconnect.", "support-open-01");
mockarty-cli cloud-customer support-open --space "$SPACE_ID" --subject 'Runner is unavailable' --category runtime --priority normal --message 'The issue is reproducible after reconnect.' --idempotency-key support-open-01
mockarty-cli cloud-customer support-reply "$CASE_ID" --space "$SPACE_ID" --message 'Additional diagnostic details.' --idempotency-key support-reply-01
Customer replies are always customer-visible. They cannot create internal notes or read another customer’s conversation.
Risk appeals
A signed-in customer can read or submit the appeal for a risk case that belongs to that account. Keep the idempotency key stable only when retrying the exact same reason:
appeal, err := client.CloudCustomer().GetRiskAppeal(ctx, caseID)
submitted, err := client.CloudCustomer().SubmitRiskAppeal(ctx, caseID,
"This decision needs review", "appeal-review-01")
appeal = client.cloud_customer.get_risk_appeal(case_id)
submitted = client.cloud_customer.submit_risk_appeal(
case_id, "This decision needs review", "appeal-review-01"
)
Map<String, Object> appeal = client.cloudCustomer().getRiskAppeal(caseId);
Map<String, Object> submitted = client.cloudCustomer().submitRiskAppeal(
caseId, "This decision needs review", "appeal-review-01");
mockarty-cli cloud-customer appeal-get "$CASE_ID"
mockarty-cli cloud-customer appeal-submit "$CASE_ID" --reason 'This decision needs review' --idempotency-key appeal-review-01
An appeal requests human review; it does not override the current risk decision by itself.
Operator support and analytics
Use a token carrying only the exact operation scope:
cases, err := client.CloudOperations().ListSupportCases(ctx, "open", "", 50)
overview, err := client.CloudOperations().ProductAnalytics(ctx, 30)
cases = client.cloud_operations.list_support_cases(status="open", limit=50)
overview = client.cloud_operations.product_analytics(days=30)
Map<String, Object> cases = client.cloudOperations().listSupportCases("open", "", 50);
Map<String, Object> overview = client.cloudOperations().productAnalytics(30);
mockarty-cli cloud-operations support-list --status open --limit 50
mockarty-cli cloud-operations support-assign "$CASE_ID" --assignee "$USER_ID" --generation 7
mockarty-cli cloud-operations support-transition "$CASE_ID" --status resolved --generation 8
mockarty-cli cloud-operations analytics --days 30
Assignment and lifecycle changes require the current case generation. On a conflict, read the case again and do not repeat a stale command. Product analytics contains consent-filtered aggregates, not raw customer event payloads.
The overview groups daily counts by event name:
| Event | What it counts | Dimensions |
|---|---|---|
account.created |
new accounts | — |
checkout.completed |
paid, failed and abandoned checkouts | plan_code, currency, result |
subscription.canceled |
plans the owner cancelled | plan_code, immediate |
subscription.reactivated |
cancelled plans reactivated before the period end | plan_code |
refund.completed |
refunds that reached the customer’s account (full or partial) | plan_code, full |
credit.issued |
billing credits issued by finance operators, by reason | reason_code |
subscription.expired |
plans that ended: trial ran out, grace period ended unpaid, cancellation took effect | plan_code, from_status |
runtime.completed |
runtime operations and their duration bucket | — |
desktop.connected |
desktop installs that connected | — |
support.case_opened |
support cases opened | — |
The embedded MCP server intentionally does not mirror these Cloud routes because it cannot prove a Cloud cabinet or operator principal. Swagger, the three SDKs, CLI, and integration tests are the supported automation surfaces.
Operator decisions that move money — resolving a stuck payment, retrying a renewal, granting or clawing back promotional balance — are different. They are deliberately absent from the customer CLI, SDKs, and MCP tools: each one is a judgement an operator makes once against a named case, not a step a customer repeats in a script.
To issue a one-month Team promotion, open Cloud cabinet → Operator → Loyalty. Choose Team package: 5 seats for 1 month, then select a published monthly Team price for five seats. The form shows its base price and region; the final price including tax is fixed by Cloud when the campaign is created and shown in the result. Set the campaign dates, redemption limit, and how many days the redeemed package remains usable. That validity must fit within the campaign window; a redemption near the end may have less time because the package cannot outlive the campaign. Create the draft and activate it. The operator cannot enter an arbitrary package amount. Give the code to the customer securely; they redeem it in their Personal Space and choose the resulting Team package under Billing. See Cloud promotions and rewards for that customer journey.