← Files YCloud Developer KitARCHIVED FILE
skills/ycloud-whatsapp-groups/references/runtime.md
14.3 KB · Oct 5, 2026 · 18:33 UTC
<!-- Generated by scripts/build_public_docs_references.py; do not edit. -->
# Official runtime behavior
- Evidence retrieved: `2026-08-29`
- Scope: curated public YCloud documentation facts; no live API observation
- Precedence: exact operation path/schema stays with `openapi.md`; this file supplies cross-cutting runtime behavior. Conflicts fail closed.
## Sources
- [api-examples-overview](https://newdocs.ycloud.com/en/api-reference/guides/examples/overview) — observed update label: retrieve at use time; no cached payload
- [errors](https://docs.ycloud.com/reference/errors) — observed update label: over 1 year ago
- [rate-limits](https://docs.ycloud.com/reference/rate-limits) — observed update label: 3 months ago
- [request-ids](https://docs.ycloud.com/reference/request-ids) — observed update label: over 1 year ago
- [versioning](https://docs.ycloud.com/reference/versioning) — observed update label: about 1 year ago
- [webhook-guide-v2](https://newdocs.ycloud.com/en/guides/webhooks) — observed update label: modified 2026-07-16
- [pagination](https://docs.ycloud.com/reference/pagination) — observed update label: about 1 year ago
## Required live documentation lookup
- Before constructing or judging a provider-valid API request or response example, browse the latest official [API examples overview](https://newdocs.ycloud.com/en/api-reference/guides/examples/overview) and the relevant example page it links to.
- Before constructing or judging an event-specific Webhook payload, browse the latest official [Webhook guide](https://newdocs.ycloud.com/en/guides/webhooks) and its relevant linked example.
- The pinned `openapi.md` controls exact paths, methods, parameters, and structural schemas. Current official examples control demonstrated cross-field combinations. If they conflict, stop, report contract drift, and do not guess or merge the shapes.
- If live documentation cannot be reached, a model may draft only a best-effort `synthetic_unverified` fixture from the pinned contract. Label it explicitly, keep it out of live transport, and never claim it is provider-valid or that YCloud was reached.
### Test evidence levels
- Deterministic unit and pull-request tests must use an injected mock transport and synthetic data. They prove local request/response mapping and failure handling, not provider connectivity.
- Provider-shaped sandbox tests prove the local HTTP boundary and controlled lifecycle/failure scenarios, not production YCloud behavior.
- Claim `live_connected` only after a separate, explicitly authorized live smoke suite reaches YCloud with dedicated test resources and records sanitized request-ID/status evidence. Live writes must never run as the default test command or an ordinary pull-request gate.
### Live transport reachability evidence
- Entering a live transport, constructing a URL, or calling `fetch` proves only `request_prepared` or `request_attempted`; it does not prove the request reached YCloud.
- If no HTTP response headers were received, no YCloud error envelope was received, and no `YCloud-Request-ID` was received, report `provider_reachability_unconfirmed`. Do not say the request was sent to, received by, rejected by, or timed out at YCloud.
- A locally raised validation/error-handler response is project evidence, not a provider response. DNS, TLS, proxy, connect, socket, abort, and client-deadline failures must never be rewritten as provider HTTP 400 or represented as a YCloud error envelope.
- Map a confirmed local client deadline with no provider response to gateway timeout semantics (`504`). Map other pre-response upstream connectivity failures to bad-gateway semantics (`502`). Keep mutation outcomes ambiguous whenever the provider may have accepted bytes before the response was lost; require reconciliation before replay.
- Record a sanitized outbound attempt with `attemptedUrl`, `method`, `startedAt`, elapsed duration, best-known phase (`dns`, `tls`, `proxy`, `connect`, `request_write`, `response_headers`, `response_body`, `timeout`, or `unknown`), whether response headers were received, and `YCloud-Request-ID` only when actually present. Never record `X-API-Key`, Authorization values, secrets, sensitive query values, or request bodies by default.
- Runtime libraries such as `fetch` may not expose DNS/TLS/connect timing separately. Classify a precise phase only from supported telemetry or a concrete nested error code; otherwise preserve `unknown` instead of guessing.
- Receiving an HTTP response establishes that an upstream HTTP peer responded. A genuine `YCloud-Request-ID` is the preferred YCloud correlation evidence. Absence of that header does not authorize inventing a placeholder provider request ID.
## Confirmed facts
- A successful API request uses a 2xx status; documented failures use 4xx for client-caused errors and 5xx for YCloud server errors.
- The standard failure envelope is {error:{status,code,message?,target?,docUrl?,requestId?,whatsappApiError?}}. status and code are required; message is diagnostic text and must not be exposed directly to end users.
- YCloud-Request-ID is returned as a response header and is also mirrored by error.requestId when present; preserve it for correlation and support without logging credentials or customer payloads.
- Throttling is reported with HTTP 429. Retry-After is a delay in seconds; when present on any response, wait before a new request instead of treating it as a successful-delivery signal.
- RateLimit-Limit, RateLimit-Policy, RateLimit-Remaining, and RateLimit-Reset may be returned. The published header format is beta and based on an IETF draft, so parse defensively and do not make it a required response shape.
- The Management API table and example header publish 10000 requests per hour, while one explanatory sentence on the same page says 1000. Treat the table value as documented guidance, prefer runtime headers, and report source drift instead of hard-coding the conflicting prose.
- Documented 429 codes include ACCOUNT_RATE_LIMITED, SENDER_RATE_LIMITED, and TOO_MANY_REQUESTS; branch on the received HTTP status and error.code rather than error.message text.
- YCloud treats added optional request parameters, response properties, resources, enum values, and changes to opaque-string formats as backward-compatible. Clients must ignore unknown response properties and preserve an explicit unknown branch for enum or event-type values instead of failing exhaustive decoding.
- Treat YCloud-generated IDs as opaque, case-sensitive strings. Do not parse fixed prefixes; support values up to 255 characters as documented by the versioning policy.
- Use the exact selected operation for list behavior and preserve business-phone-number, group, participant, and join-request identifiers as opaque contract values.
## Still fail closed
- The public cross-cutting pages do not define a general client idempotency key or guarantee that replaying a mutating request is safe.
- Do not invent endpoint-specific errors, undocumented retry counts, or a generic retry policy when the selected operation/reference does not provide one.
- The reviewed cross-cutting pages do not define a general idempotency key or safe automatic replay for group or membership mutations.
## Machine-readable failure decision contract
- Contract: `failure-contract-v1` (`failure-contract.json`)
- Authority: provider evidence, Developer Kit policy, and project decisions remain separate. A derived retry decision is not a YCloud response field.
- Provider envelope requires `status, code` and may include `status, code, message, target, docUrl, requestId, whatsappApiError`. It does not define `retryable`; do not parse `message` for control flow.
- Automatic retry requires a transient failure, a replay-safe operation, an allowed project retry budget, and satisfaction of Retry-After. Failure transience alone never authorizes replay.
- Unknown YCloud or Meta codes preserve the original value and fail closed with `automaticRetry=false`.
- No general provider idempotency key or mutation replay guarantee is documented. `externalId` is application correlation and grants no replay safety. A project-owned key must define scope, durable command identity, request digest conflicts, retention/TTL, duplicate in-progress/completed results, and ambiguous-outcome reconciliation.
- Stable decisions: `correct_request, reauthenticate, reauthorize, reconcile, wait, retry_if_replay_safe, await_async_status, do_not_retry, escalate, unknown`. Transport timeout, connection loss, or a lost response produces `ambiguous_outcome` with automatic retry disabled and reconciliation required.
### Decision matrix
| Signal | Safe read | Mutation | Authority |
| --- | --- | --- | --- |
| `HTTP_400` | `correct_request` | `correct_request` | `developer_kit_policy` |
| `HTTP_401` | `reauthenticate` | `reauthenticate_then_reconcile_before_new_attempt` | `developer_kit_policy` |
| `HTTP_403` | `reauthorize_or_fix_precondition` | `reauthorize_or_fix_precondition` | `developer_kit_policy` |
| `HTTP_404` | `return_not_found` | `reconcile_if_previous_outcome_was_ambiguous` | `developer_kit_policy` |
| `HTTP_409` | `reconcile` | `reconcile_without_blind_replay` | `developer_kit_policy` |
| `HTTP_429` | `honor_retry_after_then_bounded_retry` | `honor_retry_after_for_new_traffic_do_not_replay` | `developer_kit_policy` |
| `HTTP_5XX_OR_503` | `bounded_retry_if_budget_allows` | `reconcile_ambiguous_outcome` | `developer_kit_policy` |
| `TIMEOUT_CONNECTION_LOSS_NO_RESPONSE` | `bounded_retry_if_budget_allows` | `ambiguous_outcome_reconcile_before_new_attempt` | `developer_kit_policy` |
| `QUEUED_ACCEPTED` | `not_applicable` | `await_retrieve_or_verified_message_updated_event` | `confirmed_provider_contract` |
| `UNKNOWN_CODE_OR_STATUS` | `preserve_and_fail_closed` | `preserve_and_fail_closed_no_replay` | `developer_kit_policy` |
### YCloud error-code catalog
| Code | HTTP | Class | Transience | Action |
| --- | ---: | --- | --- | --- |
| `ACCOUNT_LIMITED` | `403` | `authorization` | `conditional` | `reauthorize` |
| `ACCOUNT_RATE_LIMITED` | `429` | `rate_limit` | `transient` | `wait` |
| `ACCOUNT_UNAVAILABLE` | `403` | `availability` | `conditional` | `escalate` |
| `ALREADY_EXISTS` | `409` | `conflict` | `non_transient` | `reconcile` |
| `BAD_REQUEST` | `400` | `validation` | `non_transient` | `correct_request` |
| `BALANCE_INSUFFICIENT` | `403` | `precondition` | `conditional` | `do_not_retry` |
| `CONTENT_PROHIBITED` | `403` | `policy` | `non_transient` | `do_not_retry` |
| `CONTENT_TOO_LARGE` | `413` | `validation` | `non_transient` | `correct_request` |
| `EMAIL_DOMAIN_UNVERIFIED` | `403` | `precondition` | `conditional` | `wait` |
| `FORBIDDEN` | `403` | `authorization` | `non_transient` | `reauthorize` |
| `INTERNAL_SERVER_ERROR` | `500` | `server` | `transient` | `retry_if_replay_safe` |
| `MESSAGING_REGION_UNSUPPORTED` | `400` | `validation` | `non_transient` | `correct_request` |
| `NOT_FOUND` | `404` | `not_found` | `non_transient` | `reconcile` |
| `PARAM_INVALID` | `400` | `validation` | `non_transient` | `correct_request` |
| `PARAM_INVALID_LENGTH` | `400` | `validation` | `non_transient` | `correct_request` |
| `PARAM_MISSING` | `400` | `validation` | `non_transient` | `correct_request` |
| `PARAM_NOT_MATCH` | `400` | `validation` | `non_transient` | `correct_request` |
| `RECIPIENT_IN_BLOCK_LIST` | `403` | `recipient_policy` | `non_transient` | `do_not_retry` |
| `RECIPIENT_UNSUBSCRIBED` | `403` | `recipient_policy` | `non_transient` | `do_not_retry` |
| `SENDER_ID_UNAVAILABLE` | `403` | `precondition` | `conditional` | `do_not_retry` |
| `SENDER_RATE_LIMITED` | `429` | `rate_limit` | `transient` | `wait` |
| `SERVICE_UNAVAILABLE` | `503` | `server` | `transient` | `retry_if_replay_safe` |
| `SMS_SIGNATURE_UNAVAILABLE` | `403` | `precondition` | `conditional` | `do_not_retry` |
| `TOO_MANY_REQUESTS` | `429` | `rate_limit` | `transient` | `wait` |
| `UNAUTHORIZED` | `401` | `authentication` | `non_transient` | `reauthenticate` |
| `WHATSAPP_BUSINESS_ACCOUNT_UNAVAILABLE` | `403` | `authorization` | `conditional` | `reauthorize` |
| `WHATSAPP_DIRECT_SEND_UNSUPPORTED_COMPONENT` | `400` | `validation` | `non_transient` | `correct_request` |
| `WHATSAPP_PHONE_NUMBER_UNAVAILABLE` | `403` | `precondition` | `conditional` | `do_not_retry` |
| `WHATSAPP_TEMPLATE_UNAVAILABLE` | `403` | `precondition` | `conditional` | `do_not_retry` |
| `WHATSAPP_TEMPLATE_UNEDITABLE` | `403` | `precondition` | `non_transient` | `correct_request` |
| `WHATSAPP_WABA_UNAVAILABLE` | `403` | `authorization` | `conditional` | `reauthorize` |
### Operation replay profiles (12)
| Operation | Method | Side effect | Result channel | Replay safety | Auto retry | OpenAPI failure gap |
| --- | --- | --- | --- | --- | --- | --- |
| `whatsapp_group-approve-join-requests` | `POST` | `create` | `synchronous_acceptance_or_result` | `not_confirmed` | `never` | `false` |
| `whatsapp_group-create` | `POST` | `create` | `synchronous_acceptance_or_result` | `not_confirmed` | `never` | `false` |
| `whatsapp_group-delete` | `DELETE` | `delete` | `synchronous_acceptance_or_result` | `not_confirmed` | `never` | `false` |
| `whatsapp_group-list` | `GET` | `read` | `synchronous_read` | `replay_safe_read` | `conditional` | `false` |
| `whatsapp_group-list-join-requests` | `GET` | `read` | `synchronous_read` | `replay_safe_read` | `conditional` | `false` |
| `whatsapp_group-reject-join-requests` | `POST` | `create` | `synchronous_acceptance_or_result` | `not_confirmed` | `never` | `false` |
| `whatsapp_group-remove-participants` | `POST` | `create` | `synchronous_acceptance_or_result` | `not_confirmed` | `never` | `false` |
| `whatsapp_group-reset-invite-link` | `POST` | `create` | `synchronous_acceptance_or_result` | `not_confirmed` | `never` | `false` |
| `whatsapp_group-retrieve` | `GET` | `read` | `synchronous_read` | `replay_safe_read` | `conditional` | `false` |
| `whatsapp_group-retrieve-invite-link` | `GET` | `read` | `synchronous_read` | `replay_safe_read` | `conditional` | `false` |
| `whatsapp_group-send-invite-link-message` | `POST` | `send` | `synchronous_acceptance_or_result` | `not_confirmed` | `never` | `false` |
| `whatsapp_group-update-settings` | `PATCH` | `update` | `synchronous_acceptance_or_result` | `not_confirmed` | `never` | `false` |
The profile is conservative Kit policy. A mutation with a timeout, connection loss, or lost response is an ambiguous outcome: reconcile, retrieve, or await the documented asynchronous status before any new attempt.
SHA-256: 792f2a5c89c14548d752cffda686cb4947b2832482a9a59d61368e7855f22796