> For the complete documentation index, see [llms.txt](https://sdk.metamarket.tech/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://sdk.metamarket.tech/architecture-and-trust/production-operations.md).

# Production Operations

How the platform behaves once a game is live: the request contract you can build retry logic against, how errors are shaped, how changes roll out, and what is settled with the team during onboarding.

## Deployment shape

A game integrates against the edge gateway and does not have to reason about the services behind it. The environment it points at, and its production configuration, are provisioned during onboarding. The three services and how they relate are in [Architecture Overview](/architecture-and-trust/product-overview.md#the-three-layers).

## Idempotency and retries

Every action carries a client key, and each action's configuration sets a deduplication window of `unique`, `daily`, or `none`. For an action configured `unique`, resending the same client key for the same acting entity in the same app will not apply it twice, provided the first attempt completed. If the first attempt failed inside the engine the platform releases the key, so the retry is applied rather than silently swallowed, which is what you want. An action configured `none` is not idempotent: do not resend it blind. Read the resulting state (see [Reading State](/evaluate-and-integrate/reading-state.md)) to check whether the first attempt landed before deciding to send it again. The field is set per action in [App Configuration](/evaluate-and-integrate/app-configuration.md#which-actions-your-app-can-send-allowedactions).

Under `unique`, the key is scoped to the app, the acting entity, and the client key. The action type is not part of it, so the same client key reused for a different action on the same entity is treated as a repeat of the first one. For a root-scoped action the acting entity resolves to the player's root, so the scope is effectively per player; for a target-scoped action it is per entity, and the same client key used on two of a player's pets is two separate keys.

Under `daily`, the client key plays no part at all. The key is the app, the action type, the player, the entity, and the UTC day, so that action runs once per player and entity per day whatever key you send. A second, legitimately different `daily` action of the same type on the same day is dropped even with a fresh key.

Send a fresh key for a genuinely new action, and reuse the key only when retrying the same one. Whether the same key presented with a different payload is rejected or ignored is not formalised for external partners; confirm it during technical review rather than relying on a specific behaviour.

The .NET SDK renews an expired session before a call goes out. A client written against the raw HTTP API renews it itself, described in [Authentication](/evaluate-and-integrate/authentication.md).

This is the failure-handling contract to build a client against:

| Situation                                                                        | Retry?              | Idempotency key                                   | What to do                                                                                                                                                                 |
| -------------------------------------------------------------------------------- | ------------------- | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Timeout or `5xx`, deduplicated action (`unique`/`daily`)                         | Limited             | Reuse the same key, and the same `timestamp`      | Capped backoff with jitter, then stop and report                                                                                                                           |
| Timeout or `5xx`, non-deduplicated action (`none`)                               | Only after checking | n/a                                               | May have committed; read state and reconcile first                                                                                                                         |
| Timeout or `5xx`, a pool or inventory `use` (a purchase, or opening a pool item) | Only after checking | Send a `clientKey` on the first call and reuse it | May have committed; without a key on the first attempt, read state and reconcile first                                                                                     |
| Partial batch (some processed, then a failure)                                   | Only after checking | n/a                                               | Do not resend the processed part; reconcile, then resend only the rest                                                                                                     |
| Business-rule `400` (typed `code`)                                               | No                  | n/a                                               | Correct the input or state; do not retry                                                                                                                                   |
| Non-zero `skipped` on a `200`                                                    | No                  | Reuse the same key                                | The response gives a count, not which ones. Read state to establish what landed, fix the cause, then resend only those, reconciling first for any action configured `none` |
| Expired access token (`401`)                                                     | Once, after refresh | Same request                                      | Refresh the session and retry once                                                                                                                                         |

Creating a marketplace listing is an ordinary `list_item` action: it carries a client key and follows the action rows above, not the pool `use` row.

Two things the table cannot carry:

* **The `daily` window uses your timestamp, not ours.** The bucket comes from the `timestamp` your client puts in the action, and no skew bound is enforced, so your clock decides which day an action falls in. Send a UTC timestamp taken when the action happened, and keep it unchanged on a retry. A byte-identical retry deduplicates correctly hours later. A retry that re-stamps `timestamp` to now can cross into a new day and apply twice.
* **There are no rate limits today.** No `Retry-After` contract exists to honour, and edge rate limiting is on the [Roadmap](/releases-and-reference/roadmap.md). Apply your own capped backoff with jitter. Timeout and attempt-limit values are not published.

## Errors

Business-rule rejections return `400` with an RFC 7807 problem document and a stable `code` you can branch on, `business_logic`, `target_entity_required`, and the cases under them, listed in the [HTTP API](/evaluate-and-integrate/api-guide.md#errors). Unhandled failures return a generic `500` with no internal detail exposed. Because a rejection carries the `400` status and a stable `code`, a client distinguishes "the rules refused this" from "something broke" by status, and by `code` when it reads the API directly.

One failure mode does not surface as a status code: an action the engine does not accept comes back with HTTP 200 and a non-zero `skipped` count. Surface that as an integration failure in your monitoring, not a success; it points to a configuration or lane mistake and is not fixed by retrying (see [Sending Actions](/evaluate-and-integrate/events-and-directives.md#treat-a-non-zero-skipped-as-a-failure)).

## Change and compatibility

Configuration changes reach the running engine within a short refresh window, without a redeploy, which is what lets a studio tune an economy or adjust a quest as a live operation. How the API surface itself changes, and what happens when a change would break an existing client, is in [Compatibility](/releases-and-reference/compatibility.md#api-and-configuration).

## Security reporting

Report a suspected vulnerability privately, following the process in [SECURITY.md](/architecture-and-trust/security.md). Please do not open a public issue for a security matter.

## Support and production commitments

Onboarding, integration questions, and incidents are handled through the team; [get in touch](https://metamarket.tech/#contact). Because early integrations are run directly with the team, production requirements, monitoring, data handling, recovery, and the operating commitments around them are agreed per game during onboarding rather than offered as a single fixed tier. [Product availability](/overview/current-scope.md) is the current state of every capability, and the [Roadmap](/releases-and-reference/roadmap.md) shows where operational tooling is headed.
