Problem
POST /api/channels/registrations currently returns coarse provisioning failures such as:
channel_bot_id_request_failed
service_owner_forbidden
provisioning_failed
Those buckets are useful as broad Aevatar failure categories, and the HTTP status remains useful for transport-level classification. However, for known user-actionable failures they are not enough for a caller to understand what actually went wrong without checking server logs.
Examples observed during NyxID-backed channel registration:
- Channel bot quota exceeded is surfaced as a generic channel-bot request failure.
- Telegram bot credential rejection is surfaced as a generic channel-bot request failure.
- Distinct NyxID authorization/scope failures can be collapsed into a broad forbidden bucket.
The goal is not to redesign HTTP status handling or introduce a new response envelope. The goal is to expose one small, safe, client-visible detail value for known failures.
Current Contract
The channel registration response already includes fields such as:
status
registration_id
platform
nyx_provider_slug
nyx_channel_bot_id
nyx_agent_api_key_id
nyx_conversation_route_id
relay_callback_url
webhook_url
workflow_result_delivery_status
error
note
error should remain the existing coarse Aevatar-owned failure bucket. HTTP status should continue to classify the failure at the HTTP level.
Required Change
Add one optional response field:
error_detail is a stable, safe, client-visible reason for known channel-registration failures. It should be omitted for unknown or unsafe upstream failures.
Examples:
| Condition |
Existing error |
New error_detail |
HTTP status |
| Telegram/provider rejects submitted bot credential |
channel_bot_id_request_failed |
telegram_bot_credential_rejected |
400 |
| Channel bot quota reached |
channel_bot_id_request_failed |
channel_bot_limit_reached |
409 |
| Channel bot/app already exists |
channel_bot_id_request_failed |
channel_bot_already_exists |
409 |
| Caller lacks selected service/scope authorization |
service_owner_forbidden |
api_key_scope_forbidden or nearest safe known detail |
403 |
| Broker capability requires platform admin |
service_owner_forbidden |
broker_capability_admin_required |
403 |
| Scope plan route cannot resolve because the referenced node is inactive/wrong owner |
existing broad bucket |
scope_plan_route_unresolved |
409 or existing upstream-failure status, depending on current status convention |
| Unknown NyxID/provider/transport failure |
existing fallback |
omitted |
existing fallback status |
note may continue to carry a short human-readable remediation message when useful, but callers should be able to branch on error_detail for known failures.
Safety Rules
- Do not return raw NyxID/provider response bodies.
- Do not return bot tokens, authorization headers, secret references, vault locators, or raw upstream payloads.
- Do not move raw diagnostic text into
error_detail.
- Do not add multiple new diagnostic fields such as phase/source/upstream_status for this issue.
- Keep
error as the coarse Aevatar failure bucket for compatibility.
- Keep HTTP status mapping as the HTTP-level classification, not the only source of actionable failure detail.
Acceptance Criteria
- Known channel registration failures include
error_detail in the response body.
- Existing
error values remain coarse and compatible with the current response shape.
- Clients can distinguish at least these known failures without checking server logs:
- channel bot quota reached
- channel bot/app already exists
- submitted Telegram/channel bot credential rejected by the provider
- caller lacks NyxID service/scope authorization
- Unknown or unsafe NyxID/provider failures omit
error_detail and keep the existing fallback behavior.
- Raw NyxID/provider bodies and secrets are not returned to clients.
- Tests cover representative NyxID error envelopes and the final response body/status mapping.
Problem
POST /api/channels/registrationscurrently returns coarse provisioning failures such as:Those buckets are useful as broad Aevatar failure categories, and the HTTP status remains useful for transport-level classification. However, for known user-actionable failures they are not enough for a caller to understand what actually went wrong without checking server logs.
Examples observed during NyxID-backed channel registration:
The goal is not to redesign HTTP status handling or introduce a new response envelope. The goal is to expose one small, safe, client-visible detail value for known failures.
Current Contract
The channel registration response already includes fields such as:
errorshould remain the existing coarse Aevatar-owned failure bucket. HTTP status should continue to classify the failure at the HTTP level.Required Change
Add one optional response field:
error_detailis a stable, safe, client-visible reason for known channel-registration failures. It should be omitted for unknown or unsafe upstream failures.Examples:
errorerror_detailchannel_bot_id_request_failedtelegram_bot_credential_rejected400channel_bot_id_request_failedchannel_bot_limit_reached409channel_bot_id_request_failedchannel_bot_already_exists409service_owner_forbiddenapi_key_scope_forbiddenor nearest safe known detail403service_owner_forbiddenbroker_capability_admin_required403scope_plan_route_unresolved409or existing upstream-failure status, depending on current status conventionnotemay continue to carry a short human-readable remediation message when useful, but callers should be able to branch onerror_detailfor known failures.Safety Rules
error_detail.erroras the coarse Aevatar failure bucket for compatibility.Acceptance Criteria
error_detailin the response body.errorvalues remain coarse and compatible with the current response shape.error_detailand keep the existing fallback behavior.