Docs Cloud Product Operations

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.