Errors
Errors
Every error code the API can return, with its status and meaning.
Every error is an RFC 9457 problem details response whose type is the page of its code on this site, /errors/{code}. Codes are stable, dotted and lower snake case ({area}.{reason}), and part of the contract: branch on code. See Handling errors for the response shape.
The product API returns a small subset of these (listed on each endpoint of the API reference); the rest belong to the portals' APIs and are listed for completeness. A result code is never returned as a response: it is recorded on a resource, such as an operation's resultCode.
Platform and request
| Code | Status | When |
|---|---|---|
paging.cursor_invalid | 400 | Cursor malformed, issued by another endpoint, or used with different filters or sort. |
request.concurrency_conflict | 409 | The row changed while the request was processed (rowversion). |
request.csrf_header_missing | 400 | Unsafe cookie-authenticated request without X-Transakt-CSRF: 1. |
request.idempotency_in_progress | 409 | Same key still in flight. |
request.idempotency_key_required | 400 | **Idem** endpoint called without Idempotency-Key. |
request.idempotency_key_reused | 422 | Same key, different body. |
request.malformed_body | 400 | Body is not valid JSON, has an unknown property or a wrong type. |
request.method_not_allowed | 405 | Route exists with another method. |
request.not_found | 404 | No such route on this host. |
request.payload_too_large | 413 | Body larger than the endpoint limit. |
request.precondition_failed | 412 | If-Match does not match. |
request.precondition_required | 428 | **If-Match** endpoint called without If-Match. |
request.rate_limited | 429 | Rate-limit policy rejected the request. |
request.unsupported_media_type | 415 | Wrong Content-Type. |
request.validation_failed | 400 | Data annotation validation failed. |
server.error | 500 | Unexpected failure. |
server.unavailable | 503 | Database or storage unavailable. |
Authentication and access
| Code | Status | When |
|---|---|---|
access.organisation_context_required | 403 | Caller has no context (membership or implicit tenant member) in the organisation; unknown ids and other partners' ids answer the same, never 404. |
access.partner_membership_required | 403 | Admin session without an active membership in the resolved partner (for example an invitee before acceptance, or a disabled member). |
access.permission_required | 403 | Caller's context lacks the permission (Read, Purchase, ManageMembers, ManageSeats, ManagePayments); contextKind is Member or ImplicitTenantMember. |
access.tenant_mismatch | 403 | Acquisition for an unheld tenant other than the signed-in one. |
auth.consent_not_configured | 409 | Consent requested but no delegated API scope is configured. |
auth.credentials_invalid | 401 | Product API key or JWT invalid, expired, revoked, or client disabled; Marketplace JWT invalid. |
auth.forbidden | 403 | Policy not satisfied. |
auth.recent_sign_in_required | 401 | Break-glass requested more than 10 minutes after the operator's last sign-in (auth_time), or without the Conditional Access authentication context the operator tenant requires (acrs). |
auth.return_url_invalid | 400 | returnUrl not a same-host relative path. |
auth.session_expired | 401 | Server session revoked, idle-expired or absolute-expired. |
auth.unauthenticated | 401 | No session or credentials. |
auth.wrong_partner | 401 | A customer or admin session created for one partner was presented on another partner's host. The cookie is cleared. |
Partners, platform and support access
| Code | Status | When |
|---|---|---|
data_subject_request.export_expired | 409 | Downloading a data subject export after its 7-day availability. |
data_subject_request.not_completed | 409 | Downloading a data subject export that is not Completed. |
data_subject_request.not_found | 404 | Unknown data subject request. |
data_subject.not_found | 404 | No records match the subject in the requested scope. |
fleet.application_id_invalid | 400 | Not a Microsoft.Solutions/applications resource id. |
fleet.application_not_found | 422 | Azure Resource Manager has no such managed application. |
fleet.copy_exists | 409 | The managed application is registered already. |
fleet.copy_not_found | 404 | Fleet (hosted): no copy with that id in the registry. |
fleet.copy_not_ready | 409 | The copy is not installed yet (or is failed or deleted). |
fleet.copy_not_retryable | 409 | Only an installation that failed for good can be retried. |
fleet.maintenance_window_invalid | 400 | Ring outside 0 to 2; a window needs both its start hour (0 to 23) and length (1 to 24). |
fleet.newer_rollout_open | 409 | A newer release is rolling out. |
fleet.publisher_access_denied | 422 | The fleet automation principal was refused on the application. |
fleet.release_digest_invalid | 400 | The manifest is malformed (version major.minor.patch; digests sha256: and 64 hex characters; the minimum below the version; a template for a release that changes infrastructure). |
fleet.release_exists | 409 | The version is registered with other digests. |
fleet.release_hash_invalid | 400 | The manifest is malformed (version major.minor.patch; digests sha256: and 64 hex characters; the minimum below the version; a template for a release that changes infrastructure). |
fleet.release_minimum_invalid | 400 | The manifest is malformed (version major.minor.patch; digests sha256: and 64 hex characters; the minimum below the version; a template for a release that changes infrastructure). |
fleet.release_not_found | 404 | No such release. |
fleet.release_template_required | 400 | The manifest is malformed (version major.minor.patch; digests sha256: and 64 hex characters; the minimum below the version; a template for a release that changes infrastructure). |
fleet.release_version_invalid | 400 | The manifest is malformed (version major.minor.patch; digests sha256: and 64 hex characters; the minimum below the version; a template for a release that changes infrastructure). |
fleet.reporting_not_configured | 409 | A dedicated copy has no reporting settings from the fleet yet. |
fleet.ring_invalid | 400 | Ring outside 0 to 2; a window needs both its start hour (0 to 23) and length (1 to 24). |
fleet.rollout_closed | 409 | The rollout has completed or was cancelled. |
fleet.rollout_exists | 409 | The release is already rolling out. |
fleet.rollout_not_found | 404 | The fleet rollout does not exist. |
fleet.rollout_not_halted | 409 | Only a halted rollout resumes. |
fleet.setup_code_failed | 502 | The new code could not be set on the copy or emailed; the previous code may no longer work. |
fleet.setup_code_limit | 429 | Five setup codes were sent in the last 24 hours (Retry-After). |
fleet.setup_completed | 409 | The copy has completed its first-run setup. |
job.already_running | 409 | *Run now* while a run holds the lease. |
job.disabled | 409 | *Run now* or *Resume* on a job disabled by configuration (Jobs:<Job>:Enabled = false). |
job.not_found | 404 | Unknown job name. |
job.paused | 409 | *Run now* on a paused job. |
partner_export.expired | 409 | Downloading a workspace export after its 7-day availability. |
partner_export.in_progress | 409 | A workspace export of the partner is already Queued or Running. |
partner_export.not_found | 404 | Unknown partner workspace export, or not this partner's. |
partner_export.not_ready | 409 | Downloading a workspace export that is not Completed. |
partner_member.already_member | 409 | Inviting an address that already has a membership of this partner. |
partner_member.cannot_change_own_roles | 422 | A partner member cannot change their own roles. |
partner_member.cannot_disable_self | 422 | A partner member cannot disable or remove themselves. |
partner_member.last_partner_admin | 409 | Removing the PartnerAdmin role from, disabling, removing or erasing the last active PartnerAdmin of a partner. Protected by a conditional update. |
partner_member.not_found | 404 | Partner member not in this partner. |
partner_member.roles_required | 422 | A membership must keep at least one role. |
partner.capability_exceeded | 409 | The partner's plan does not include the feature (limit 0) or its limit is reached: products, publisher sources, active customer subscriptions, custom domains, white-label, outbound webhook endpoints, API clients. |
partner.not_found | 404 | The host is not an active host of any partner, the partner is Closed, or a Platform Console path names an unknown partner (args.partnerId on platform endpoints only). |
partner.plan_not_found | 404 | A plan override names a plan that is not a plan of the *Transakt* product in the platform owner's workspace (hosted) or of the Azure Application plan list (dedicated). |
partner.plan_override_not_found | 404 | Clearing an override when none is set. |
partner.restricted | 403 | A write refused because the partner is Restricted. |
partner.settings_would_lock_out | 422 | A PartnerAdmin tried to save member gate settings (allowed member tenants, guest members) that would exclude their own current sign-in. |
partner.slug_reserved | 422 | Partner slug is a reserved host label. |
partner.slug_taken | 409 | Partner creation with a slug already used on the platform. |
partner.transition_not_allowed | 409 | Restrict, reinstate or close not allowed from the current state (for example reinstating a partner whose paying subscription is still lapsed: reason: BillingLapsed; any change to a Closed partner). |
platform.dedicated_only | 422 | The feature is available only in dedicated mode: Mailjet provider template mapping, because hosted partners share the platform's Mailjet account. |
platform.service_stopped | 503 | Dedicated mode: the copy was stopped because Microsoft no longer bills its Azure Application (Platform:ServiceState = Stopped); its portals and API answer with this code until service resumes. |
platform.setup_pending | 503 | Dedicated mode: the copy's first-run setup has not completed, so every route except the setup page, the setup endpoints and the Platform Console sign-in answers with this code. |
platform.single_partner_mode | 409 | Creating a second partner in dedicated mode. |
setup.code_invalid | 422 | The setup code is unknown, already used or older than 7 days (one code, so codes cannot be probed; 6.4.3b). |
setup.entra_invalid | 422 | An Entra application id pasted from the setup script could not be validated against its OpenID metadata in the partner's tenant. |
setup.health_check_failed | 409 | The final health check of the setup failed; nothing is created and setup stays open. |
setup.session_required | 401 | A setup step was called without a verified setup code in this browser, or after the setup session expired. |
setup.step_not_ready | 409 | A setup step was called before the steps it depends on (for example finishing setup before the Entra applications are recorded). |
support_access.action_not_allowed | 403 | A break-glass support session called an endpoint that would show a credential or a raw subscription key once, or change partner roles other than restoring a PartnerAdmin. |
support_access.already_active | 409 | The operator already has an open grant of the same mode for the partner; end it first (break-glass grants cannot be extended). |
support_access.not_active | 409 | A handoff was requested for a grant that has ended or expired. |
support_access.not_found | 404 | Unknown support access or break-glass grant. |
support_access.read_only | 403 | A read-only support session on a partner's admin host called an endpoint that is not a GET. |
support_access.required | 403 | A partner-scoped platform data subject request was made without an open support access (read-only) or an active break-glass grant of this operator for that partner. |
Sign-in broker
| Code | Status | When |
|---|---|---|
broker.code_expired | Result code | The handoff code is older than 60 seconds. |
broker.code_invalid | Result code | The handoff code is unknown, already redeemed (a second redemption also revokes the session the code created), issued for another host, or the browser's __Host-transakt-handoff nonce cookie does not match (one code, so a stolen code cannot be probed). |
broker.invalid_target | 400 | target is not the host of the sign-in or sign-out request named by state, or that host is not a verified, active host of an active partner of the portal class the request is for. The broker never redirects to it. |
broker.state_invalid | Result code | The sign-in or sign-out request is unknown, already used or older than 10 minutes. |
Catalogue
| Code | Status | When |
|---|---|---|
catalogue.default_language_required | 400 | A write of partner content without a translation in the partner's default content culture. |
category.in_use | 409 | Delete of a category still assigned to products; deactivate it instead. |
category.inactive | 422 | Assigning an inactive category to a product. |
category.name_taken | 409 | Another category of the partner already has this name in the same culture. |
category.not_found | 404 | Unknown category slug; on public endpoints an inactive category is treated as unknown. |
category.order_mismatch | 422 | A category order does not list exactly the partner's categories. |
category.slug_taken | 409 | Create with an existing category slug. |
edition.capabilities_invalid | 400 | An edition capability key is not a dotted camelCase name of at most 100 characters, a value is neither a boolean nor a non-negative whole number, or an edition has more than 50 capabilities. |
edition.capability_overridden | 409 | An edition write removes a capability, or changes its kind, while plans of the edition override it. |
edition.limit_reached | 422 | A product already has 20 editions. |
edition.name_taken | 409 | Another edition of the product already has this name in the same culture. |
edition.not_empty | 409 | Delete of an edition that still has plans; move or delete them first. |
edition.not_found | 404 | Unknown edition slug within the product. |
edition.order_mismatch | 422 | An edition order does not list exactly the product's editions. |
edition.required | 400 | A plan create without editionSlug for a product with more than one edition. |
edition.slug_taken | 409 | Create with a slug another edition of the same product has. |
marketplace_catalogue_offer.not_found | 404 | Offer not in the synced catalogue. |
marketplace_catalogue_offer.not_saas | 422 | Auto-map of an offer that is not a SaaS product. |
marketplace_catalogue_plan.not_found | 404 | Plan not in the synced catalogue. |
marketplace_offer_mapping.not_found | 404 | Offer mapping not on this product. |
marketplace_offer.already_mapped | 409 | Offer already mapped to another product within the source. |
marketplace_offer.in_use | 409 | Unmapping an offer while live (pending, active or suspended) Marketplace subscriptions of the source use it; their lifecycle would no longer find a local plan. |
marketplace_plan_mapping.not_found | 404 | Plan mapping not on this plan. |
marketplace_plan.already_mapped | 409 | Marketplace plan already mapped to another local plan, or (localPlanAlreadyMapped) the local plan already maps another Marketplace plan of the source (the mapping is one to one within a source). The arguments name the conflicting mapping (the local product and plan slugs, the Marketplace offer and plan ids), so the message can say where the plan is already mapped. |
marketplace_plan.in_use | 409 | Unmapping a plan while live Marketplace subscriptions use it. |
marketplace_source.none_active | 422 | A sync or reconcile for every source, but the partner has no active publisher source. |
marketplace_source.unknown | 422 | No enabled publisher source of the partner has this name; there is no default source. |
plan_price.duplicate | 409 | An active price for the plan, currency and interval already exists. |
plan_price.in_use | 409 | Deleting a price used by a payment order or billing record; archive it instead. |
plan_price.not_found | 404 | Unknown plan price, or not on this plan. |
plan.capabilities_invalid | 400 | A capability override key is not a dotted camelCase name of at most 100 characters, or a plan has more than 50 overrides. |
plan.capability_override_kind_mismatch | 400 | A plan override gives a limit for a switch of the edition, or a switch for a limit. |
plan.capability_override_unknown | 400 | A plan override names a capability that the plan's edition (or, when moving the plan, the target edition) does not have. |
plan.in_use | 409 | Delete of a plan referenced by subscriptions, keys, requests or prices. |
plan.move_affects_subscriptions | 409 | *Move to edition* of a plan with live subscriptions without confirmLiveSubscriptions; their entitlement would report the new edition. |
plan.not_found | 404 | Unknown plan slug, or plan not in the product. |
plan.slug_taken | 409 | Create with an existing plan slug (plan slugs are unique within the partner). |
product_logo.dimensions_invalid | 422 | Raster image above 4096 × 4096 pixels. |
product_logo.empty | 400 | Uploaded file is empty. |
product_logo.not_found | 404 | Removing a logo from a product that has none. |
product_logo.too_large | 413 | Larger than 1 MiB. |
product_logo.unsafe_svg | 422 | SVG contains a DTD, scripts, event handlers, foreignObject, external references or javascript:/data: URLs; it is refused, never rewritten. |
product_logo.unsupported_type | 415 | Sniffed type not PNG, JPEG, WebP or SVG. |
product.in_use | 409 | Delete of a product referenced by subscriptions. |
product.not_found | 404 | Unknown product slug. |
product.slug_taken | 409 | Create with an existing slug. |
product.types_required | 400 | A product without any product type. |
Customers
| Code | Status | When |
|---|---|---|
invitation.already_accepted | 409 | Token already used. |
invitation.already_member | 409 | The signed-in person already has a membership of the organisation, even a disabled one (an invitation never re-enables a membership). |
invitation.already_pending | 409 | An unexpired pending invitation exists for the address; resend it instead. |
invitation.email_mismatch | 403 | Signed-in email is not verified or differs from the invited email. |
invitation.expired | 422 | Token past its 7-day expiry. |
invitation.not_found | 404 | Invitation not in the organisation (customer invitations) or not in the partner (partner invitations). The other invitation.* codes apply to both kinds. |
invitation.not_pending | 409 | Revoke or resend of an accepted or revoked invitation (an expired pending one can still be revoked or re-sent). |
invitation.revoked | 422 | Invitation withdrawn by an Owner, or automatically when the address was invited again after expiry. |
invitation.token_invalid | 422 | Unknown invitation token (including another partner's), or the organisation is no longer active. |
member.already_member | 409 | Inviting an address that a member of the organisation has as their email (a hint only: memberships are bound to identities). |
member.cannot_change_own_role | 422 | Members cannot change their own role. |
member.cannot_disable_self | 422 | Members cannot disable or remove themselves. |
member.last_owner | 409 | Demoting, disabling or removing the last active Owner. |
member.not_found | 404 | Member not in the organisation. |
organisation.already_active | 409 | Reactivating an organisation that is already Active. |
organisation.already_inactive | 409 | Deactivating an organisation that is already Inactive. |
organisation.already_member | 409 | Create while the caller already has a membership. |
organisation.has_active_subscriptions | 409 | Deactivating an organisation that still has subscriptions that have not ended. |
organisation.inactive | 403 | An organisation-scoped call on an organisation the partner has deactivated; the organisation stays listed among the member's organisations, without permissions. |
organisation.not_found | 404 | Admin lookup of an unknown organisation. |
organisation.tenant_already_covered | 409 | Creating an organisation while another organisation of the partner already holds the caller's tenant. A matching email domain never refuses creation; it only suggests that organisation. |
organisation.tenant_not_found | 404 | A tenantId filter or field names a tenant that is not an anchor of the organisation. |
organisation.work_account_required | 422 | Create with a personal Microsoft account (tenant 9188040d-6c67-4c5b-b112-36a304b66dad). |
tenant.already_claimed | 409 | The tenant already belongs to another organisation (when choosing the organisation of an activation, on acquisition, when another request claimed it first, or when reactivating an organisation whose released tenant another organisation of the partner claimed meanwhile). |
Activation
| Code | Status | When |
|---|---|---|
activation_session.already_completed | 409 | Session already Active. |
activation_session.completion_in_progress | 409 | Another completion of the same session is running. |
activation_session.declined | 409 | The partner declined the purchase, so the customer cannot complete it. |
activation_session.forbidden | 403 | Caller is neither the bound owner, nor the Marketplace buyer, nor a qualifying member. |
activation_session.not_awaiting_approval | 409 | The session is not waiting for the partner's approval (approve also accepts a declined session and a failed one already approved). |
activation_session.not_found | 404 | Unknown session. |
activation_session.organisation_choice_unavailable | 409 | Choosing an organisation when the session is not Resolved or the tenant is already held. |
activation_session.organisation_not_offered | 422 | The organisation is not among the caller's choices. |
activation.landing_token_invalid | 422 | No configured publisher could resolve the landing-page token (every source answered with a client error). |
activation.marketplace_activation_failed | 502 | The SaaS Fulfillment *activate* call failed and the subscription is not already Subscribed; the session is Failed and can be retried. |
activation.offer_not_mapped | 422 | The Marketplace offer and plan are not mapped to a local plan. |
activation.tenant_missing | 422 | Marketplace reported neither a beneficiary nor a purchaser tenant. |
marketplace.activation_unconfirmed | 502 | Microsoft still reported PendingFulfillmentStart at the confirmation deadline after the activation; the activation is Failed and the partner is alerted, and it is provisioned by *Refresh from Marketplace* or a sync as soon as Microsoft reports Subscribed. Recorded as the activation's result code, never returned as a problem. |
marketplace.unsubscribed | Result code | Recorded as a session's failureCode: Microsoft reports the purchase Unsubscribed (voided or cancelled) before it was provisioned. |
subscription.channel_conflict | 409 | Manual activation or key redemption would change a subscription owned by another channel (for example a Marketplace or online-purchase subscription). |
Subscriptions and lifecycle
| Code | Status | When |
|---|---|---|
marketplace_plan.billing_model_mismatch | 409 | A Marketplace plan mapped to a local plan of another billing model; the plan is canonical and a listing attaches only to a plan of its billing model. |
marketplace_plan.metering_not_supported | 409 | Dimensions set on a per-user Marketplace plan: Partner Center offers custom meters on flat-rate plans only. |
marketplace_plan.no_live_subscription | 409 | *Fetch from Marketplace* needs a live subscription on the plan, because F5 answers per subscription. |
marketplace_plan.not_mapped | 404 | The Marketplace plan is not mapped in the offer mapping. |
marketplace.operation_conflict | 409 | The operation finished with Microsoft status Conflict and the subscription is not at the target. |
marketplace.submission_blocked | 409 | Microsoft answered 409 ("subscription is locked due to pending operations") to the PATCH or DELETE; the operation is Blocked and may be retried later. |
marketplace.submission_unconfirmed | Result code | Recorded as the operation's resultCode, not returned by an endpoint: a submission whose outcome was uncertain could not be confirmed after four checks, so the operation is SubmissionFailed. |
metering.marketplace_subscription_missing | 409 | Metered subscription without a Marketplace subscription id. |
metering.not_metered | 422 | Recording usage for a subscription without a metered Marketplace plan. |
metering.reconciliation_not_found | 404 | The reconciliation run is not one of the partner's. |
metering.report_not_found | 404 | The metered usage report is not one of the subscription's. |
metering.report_not_rejected | 409 | Only a Rejected report can be re-queued. |
metering.schedule_exists | 409 | The subscription already has a usage schedule for the dimension of its current plan. |
metering.schedule_not_found | 404 | The usage schedule is not one of the subscription's. |
metering.schedule_plan_changed | 409 | The subscription is no longer on the plan mapping the schedule was made for (a run's reason). |
metering.subscription_ambiguous | 409 | More than one of the tenant's Marketplace subscriptions could take the usage; name the plan. |
metering.subscription_not_active | 409 | The subscription is not Active and Subscribed, or the window starts at or after its suspension or cancellation. |
metering.subscription_not_found | 404 | The tenant has no Marketplace subscription of the product (and plan) in the API client's partner. |
metering.unknown_dimension | 422 | The subscription's current Marketplace plan mapping does not list the dimension. |
metering.window_already_recorded | 409 | A usage schedule's occurrence found usage recorded another way for the hour and left it (a run's reason). |
metering.window_already_reported | 409 | The window was already sent to Marketplace and another quantity is recorded for it; reporting the same quantity again succeeds without change. |
metering.window_not_ended | 400 | The hour has not ended yet. |
metering.window_too_old | 422 | The hourly window can no longer be reported to Marketplace (older than 24 hours less the safety margin). |
subscription.already_cancelled | 409 | Cancel (or Unsubscribe) on a cancelled subscription. |
subscription.change_not_allowed | 422 | Microsoft does not allow the operation for this subscription (allowedCustomerOperations lacks it, a CSP purchase, a recently transferred subscription, or a multi-year term restriction). |
subscription.managed_by_billing | 422 | Lifecycle operation requested by a customer for an online-purchase subscription; plan, seat and cancellation changes go through the billing endpoints. |
subscription.marketplace_link_missing | 409 | Marketplace-backed subscription has no Marketplace subscription id. |
subscription.not_active | 409 | Change plan or change quantity on a subscription that is not active (Marketplace: not Subscribed). |
subscription.not_found | 404 | Unknown subscription, or not in the organisation. |
subscription.operation_in_progress | 409 | Any lifecycle operation of the subscription is non-terminal locally, **or** Microsoft's list of outstanding operations shows one InProgress ("another change is being processed by Microsoft"). |
subscription.operation_not_found | 404 | Unknown operation. |
subscription.operation_not_supported | 422 | Operation not offered to this audience or channel (for example Renew by a customer, Suspend by anyone, Renew or Reinstate on a Marketplace subscription, which Marketplace controls). |
subscription.plan_not_available | 422 | Target plan is not a plan of the product, is not mapped to a Marketplace plan of the **same offer and source**, or is not in Microsoft's listAvailablePlans for the subscription. |
subscription.plan_unchanged | 422 | Target plan equals the current plan. |
subscription.quantity_below_assigned_seats | 422 | Change quantity to fewer seats than are given out in the pool (the subscription's plan for the tenant, across its active subscriptions); revoke seats first. |
subscription.quantity_change_not_supported | 422 | Change quantity on a plan that is not per user. |
subscription.quantity_out_of_range | 422 | Target quantity outside the plan's minQuantity–maxQuantity (from listAvailablePlans), or equal to the current quantity. |
subscription.transition_not_allowed | 409 | The state machine refuses the transition. |
Entitlements and seats
| Code | Status | When |
|---|---|---|
api_client.product_not_allowed | 403 | API client not allowed to read this product. |
api_client.scope_not_allowed | 403 | The API client lacks the scope of the endpoint (entitlements:read, catalogue:read or usage:write), or its client-credentials token lacks the matching app role (Entitlement.Read.All, Catalogue.Read.All or Usage.Write.All): both are required. |
entitlement.consent_required | 409 | Customer licence check for a Microsoft-managed plan without the delegated token. |
entitlement.user_not_resolved | 422 | An eligibility question by email: the address does not match exactly one active member of the organisation that holds the tenant. Ask by userObjectId instead. |
entitlement.user_tenant_mismatch | 403 | Product API call with a user token whose tid differs from {tenantId}. |
seat.limit_reached | 409 | All seats assigned (enforced atomically). |
seat.microsoft_managed | 422 | Seats for a Microsoft-managed plan are assigned in the Microsoft 365 admin centre. |
seat.not_found | 404 | Unknown seat, or not in the organisation. |
seat.plan_mismatch | 422 | Requested plan is not an entitled plan. |
seat.plan_not_per_user | 422 | The entitlement is not per user. |
seat.plan_required | 422 | The tenant holds several active plans; name one. |
seat.tenant_not_entitled | 409 | Assigning a seat without an active entitlement. |
seat.user_not_resolved | 422 | A seat by email: the address does not match exactly one active member of the organisation that holds the tenant; give the person's object id instead. |
Direct sales
| Code | Status | When |
|---|---|---|
subscription_key_reveal.already_used | 409 | Reveal token already consumed. |
subscription_key_reveal.expired | 422 | Reveal token past its 14-day expiry. |
subscription_key_reveal.not_entitled | 403 | Signed-in email does not match and the caller holds no Purchase in the restricted tenant. |
subscription_key_reveal.token_invalid | 422 | Unknown reveal token. |
subscription_key.already_revoked | 409 | Revoking a revoked key. |
subscription_key.bound_to_other_tenant | 409 | Key restricted to another tenant. |
subscription_key.invalid | 422 | Key unknown, expired, revoked or fully redeemed (one code, so keys cannot be probed). |
subscription_key.not_found | 404 | Admin lookup of an unknown key. |
subscription_key.not_revealable | 409 | Re-issuing a reveal link for a revoked, expired or fully redeemed key. |
subscription_key.recipient_required | 422 | Re-issuing a reveal link for a key with no issued-to address and none supplied. |
subscription_request.duplicate_pending | 409 | A pending request for the same tenant and plan exists. |
subscription_request.not_found | 404 | Unknown request, or not in the organisation. |
subscription_request.not_pending | 409 | Issue key, decline or cancel when the request is no longer PendingReview. |
subscription_request.plan_has_no_trial | 422 | Trial requested for a plan without a trial. |
subscription_request.purchase_requests_not_offered | 422 | Purchase requests switched off. |
subscription_request.trials_not_offered | 422 | Trial requests switched off. |
trial.already_used | 422 | The tenant already had a direct trial of the plan with this partner (one trial per plan; an earlier Marketplace trial counts too when the partner turned that on), so a trial request, trial key issue or trial key redemption is refused unless the key was issued to allow a repeat trial. |
Payments
| Code | Status | When |
|---|---|---|
billing.change_not_allowed | 409 | A quote or confirmation for a billing record that is not Active (past due, suspended, ending or ended). |
billing.change_pending | 409 | A proration order for the subscription is still open. |
billing.no_change | 422 | Target plan, price and quantity equal the current ones. |
billing.no_outstanding_payment | 409 | Paying an outstanding amount when nothing is outstanding. |
billing.not_cancellable | 409 | Cancel when the billing record is Ending, Ended or Suspended. |
billing.not_resumable | 409 | Resume after the period ended or when not Ending. |
billing.outstanding_window_closed | 409 | Paying an outstanding renewal more than 30 days after suspension: the subscription has ended as Cancelled with reason NonPayment; buy again instead. |
billing.quote_expired | 409 | Confirming a quote after its 15-minute validity. |
billing.quote_not_found | 404 | Unknown quote. |
billing.quote_stale | 409 | The period, price, quantity or plan changed since the quote; request a new one. |
billing.scheduled_change_not_found | 404 | Undo when no change is scheduled. |
billing.seats_in_use | 409 | Seat decrease below the number of assigned seats. |
checkout.expired | 409 | Paying or cancelling a checkout whose Revolut order expired (expire_pending_after, the partner's checkoutExpiryMinutes, default 60). |
checkout.not_found | 404 | Unknown checkout, or not visible to the caller. |
checkout.not_pending | 409 | Cancelling a checkout that is completed, expired or cancelled. |
checkout.purpose_not_available | 422 | The checkout's purpose is not offered. Not returned any more: every purpose is available. |
checkout.subscription_conflict | 409 | The tenant already holds an active subscription for the product; change plan instead. |
checkout.terms_outdated | 409 | The checkout request accepted a terms version that is no longer the partner's current one (the partner changed its terms URL); show the new terms and ask again. |
payment_method.in_use | 409 | Removing the method used by billing records with auto-renewal on. |
payment_method.not_found | 404 | Unknown payment method, or not the organisation's. |
payment.currency_not_supported | 422 | Currency outside the partner's billing currencies (a subset of the platform's Payments:Currencies: GBP, EUR, USD), on a checkout, a plan price or the billing settings. |
payment.declined | Result code | Recorded as the resultCode of a local lifecycle operation (Failed) whose payment was declined, not returned by an endpoint. |
payment.dispute_open | 409 | A refund of a payment whose dispute is open (5.3.7 PaymentDisputes). |
payment.email_required | 422 | The signed-in person has no email address, which Revolut needs for the customer and the receipt. |
payment.existing_direct_subscription | 409 | The tenant holds a live key-based subscription of the product that is not a trial (an offline deal), so it cannot be bought online; a key-based trial is converted instead. |
payment.export_range_too_large | 422 | Export window longer than 366 days. |
payment.no_saved_method | 422 | Upgrade confirmation, resume, operator retry or renewal needs a saved merchant payment method and there is none. |
payment.not_found | 404 | Unknown payment order, or not in the organisation. |
payment.not_online_purchase | 422 | Billing endpoint called for a subscription that is not an online purchase. |
payment.online_purchase_disabled | 422 | The partner's allowOnlinePurchase setting is off. It is the only switch for online purchase and can be on only while the partner has an Active Revolut connection; the former Payments:Enabled key no longer exists. |
payment.order_not_completed | 409 | Refund of a payment order that is not Completed or PartiallyRefunded. |
payment.price_inactive | 422 | Checkout or quote with an archived price, or a price of another plan. |
payment.provider_unavailable | 502 | A Revolut call failed or the circuit breaker is open. |
payment.quantity_out_of_range | 422 | Quantity outside the price's seat range. |
payment.quantity_required | 422 | Per-seat price without a quantity. |
payment.receipt_not_available | 409 | Receipt requested for a payment order that is not Completed, PartiallyRefunded or Refunded. |
payment.refund_currency_mismatch | 422 | Refund currency differs from the payment currency. |
payment.refund_exceeds_amount | 422 | Refund above the amount still refundable. |
payment.retry_not_applicable | 409 | Operator retry when the billing record is not PastDue or Suspended, or a renewal order is still open. |
payment.terms_url_required | 422 | Turning on allowOnlinePurchase while the partner's branding has no termsUrl, or clearing termsUrl while online purchase is on: customers must accept the partner's terms at checkout. |
validation.default_currency | 400 | Field codes of the billing settings and of prices: the renewal retry offsets are 1 to 5 strictly increasing days of 1 to 30, the last not after the grace period (validation.retry_offsets); the default currency must be one of the currencies sold (validation.default_currency); a seat range is only for per-seat prices, with minQuantity ≥ 1 and maxQuantity ≥ minQuantity (validation.quantity_range). |
validation.quantity_range | 400 | Field codes of the billing settings and of prices: the renewal retry offsets are 1 to 5 strictly increasing days of 1 to 30, the last not after the grace period (validation.retry_offsets); the default currency must be one of the currencies sold (validation.default_currency); a seat range is only for per-seat prices, with minQuantity ≥ 1 and maxQuantity ≥ minQuantity (validation.quantity_range). |
validation.retry_offsets | 400 | Field codes of the billing settings and of prices: the renewal retry offsets are 1 to 5 strictly increasing days of 1 to 30, the last not after the grace period (validation.retry_offsets); the default currency must be one of the currencies sold (validation.default_currency); a seat range is only for per-seat prices, with minQuantity ≥ 1 and maxQuantity ≥ minQuantity (validation.quantity_range). |
Marketplace
| Code | Status | When |
|---|---|---|
marketplace.catalogue_empty | Result code | Recorded as a catalogue run's errorCode with status Succeeded: the read completed but returned no products, so nothing was changed (a lost Partner Center role looks exactly like this). |
marketplace.forbidden | Result code | Recorded as a sync run's errorCode: Product Ingestion answered 403 (the application lacks the Partner Center *Manager* role), the source's credential could not be read, Microsoft kept throttling, or a response or paging link was invalid. |
marketplace.invalid_response | Result code | Recorded as a sync run's errorCode: Product Ingestion answered 403 (the application lacks the Partner Center *Manager* role), the source's credential could not be read, Microsoft kept throttling, or a response or paging link was invalid. |
marketplace.listing_incomplete | Result code | Recorded as a subscription run's errorCode with status PartiallySucceeded: the listing failed after its first page, so no orphan flags changed; the records read were reconciled. |
marketplace.not_configured | Result code | Recorded as a sync run's errorCode: Product Ingestion answered 403 (the application lacks the Partner Center *Manager* role), the source's credential could not be read, Microsoft kept throttling, or a response or paging link was invalid. |
marketplace.request_failed | 502 | SaaS Fulfillment or Product Ingestion call failed. |
marketplace.sync_already_running | 409 | A sync of the same kind is queued or running for the source (UX_SyncRuns_OneActive). |
marketplace.sync_run_not_found | 404 | Unknown sync run. |
marketplace.throttled | Result code | Recorded as a sync run's errorCode: Product Ingestion answered 403 (the application lacks the Partner Center *Manager* role), the source's credential could not be read, Microsoft kept throttling, or a response or paging link was invalid. |
marketplace.token_unresolvable | 422 | Admin token resolve: no source resolved the token. |
marketplace.unauthorised | Result code | Recorded as a sync run's errorCode (per source), not returned by an endpoint: Microsoft refused the source's credential (token failure, 401 or 403). |
sync.abandoned | Result code | Recorded as a sync run's errorCode: a run left Running by a crashed worker was marked Failed by the next run. |
Notifications
| Code | Status | When |
|---|---|---|
email_outbox.body_purged | 409 | Retrying or sending again a message whose body was purged (secret-link kinds, or older than the 90-day retention); re-issue the invitation or reveal link instead. |
email_outbox.message_not_found | 404 | Unknown outbox message. |
email_outbox.not_cancellable | 409 | Cancelling a message that is not Pending or Failed. |
email_outbox.not_resendable | 409 | *Send again* on a message that is not Sent. |
email_outbox.not_retryable | 409 | Retrying a message that is not Failed or Cancelled, or changing a message in Sending. |
email_template.culture_unsupported | 404 | Culture not in the supported list. |
email_template.invalid | 422 | Template does not parse or render in the sandbox. message is the Scriban diagnostic, shown to operators as technical detail. |
email_template.kind_unknown | 404 | Unknown template kind. |
email_template.not_overridable | 409 | Saving or resetting a platform kind, which partners cannot override. |
email_template.not_sendable | 422 | Test send of Layout. |
email_template.stored_version_invalid | 422 | Restoring a version that no longer renders. |
email_template.version_not_found | 404 | Unknown version. |
email_template.versioning_disabled | 409 | Version history requested while versioning storage is disabled. |
email.provider_not_configured | Result code | Recorded as an outbox message's lastErrorCode: no email provider is configured (Email:Provider = None), so every send fails and is retried. |
email.sender_not_validated | Result code | Recorded as an outbox message's lastErrorCode: Mailjet refused the send because the partner's sender is not validated; the row is Failed and the sender becomes Unverified. |
email.template_render_failed | Result code | Recorded as an outbox message's lastErrorCode, not returned by an endpoint: the template did not render when the message was composed, so the row was written Failed without bodies. |
email.test_recipient_not_allowed | 422 | Test or sample recipient is neither the operator's own address nor in an allowed domain. |
marketing_preference.not_found | 404 | No preference row for the tenant. |
marketing_preference.not_opted_out | 409 | Opt-in for a tenant that is not opted out. |
provider_template_mapping.kind_not_mappable | 422 | Layout cannot be mapped. |
provider_template_mapping.not_found | 404 | No mapping to delete or test. |
provider_template_mapping.template_id_required | 422 | Enabling a mapping without a provider template id. |
provider_template_mapping.unknown_parameters | 422 | Variables reference parameters the kind does not have. |
provider.not_configured | 409 | Provider credentials missing for a call that needs them. |
provider.request_failed | 502 | Provider API call failed. |
provider.unknown | 404 | Unknown email provider. |
Auditing
| Code | Status | When |
|---|---|---|
audit_entry.not_found | 404 | Unknown audit entry, or not in this partner or not a platform entry. |
Branding and domains
| Code | Status | When |
|---|---|---|
branding_asset.dimensions_invalid | 422 | Favicon (raster or ICO) not square or smaller than 32 × 32 pixels, or an image above 4096 × 4096 pixels. |
branding_asset.empty | 400 | Uploaded logo or favicon is empty. |
branding_asset.not_found | 404 | Removing a logo or favicon that is not set. |
branding_asset.too_large | 413 | Logo above 1 MiB or favicon above 256 KiB. |
branding_asset.unsafe_svg | 422 | SVG refused by the safety checks, as for product logos. |
branding_asset.unsupported_type | 415 | Sniffed type not allowed (logo: PNG, JPEG, WebP or SVG; favicon: PNG, ICO or SVG). |
branding.insufficient_contrast | 422 | The primary colour, or a colour the shared theme generator derives from it, fails WCAG 2.2 AA (4.5:1 for text against its background, 3:1 for interface components and focus indicators) in the light theme, the only partner theme in the first release. |
domain.in_use | 409 | The host name is already registered on the platform (host names are unique platform-wide; which partner holds it is not disclosed). |
domain.invalid_host | 422 | The host name cannot be used: not a valid DNS name, an apex domain (a CNAME is required), a wildcard, a name under the platform's own domain, or a reserved name. |
domain.not_active | 409 | Making a domain primary before it is Active. |
domain.not_found | 404 | Unknown domain, or not this partner's. |
domain.not_removable | 409 | The domain is already being removed. |
domain.platform_subdomain | 409 | A platform subdomain cannot be removed. |
domain.provisioning_failed | 502 | Reported as the domain's lastError, not returned by an endpoint: Azure Front Door could not add the domain or issue its certificate. |
domain.too_many_pending | 409 | The partner already holds Platform:Domains:MaxPendingPerPartner (3) custom domains that are not yet Active (pending verification or provisioning). |
domain.validation_timeout | Result code | Reported as the domain's lastError (state Failed), not returned by an endpoint: the domain was not validated within 7 days. |
domain.verification_failed | 409 | *Check now* did not find the CNAME pointing directly at the Front Door endpoint host, or Front Door has not yet validated the _dnsauth TXT record. The background check keeps trying for 7 days. |
Integrations
| Code | Status | When |
|---|---|---|
connection_test.access_denied | Result code | FulfillmentList or ProductIngestion: Microsoft answered 401 or 403 (the application id is not entered on the offers' technical configuration, or lacks the Partner Center role the check needs). |
connection_test.credential_expired | Result code | TokenAcquisition: the client secret or certificate has expired. |
connection_test.credential_rejected | Result code | Microsoft Entra or Revolut refused the credential (the TokenAcquisition or Authentication check of a connection test). Recorded as a check's code in the connection test result, also inside publisher_source.test_failed and payment_connection.test_failed. |
connection_test.merchant_not_active | Result code | MerchantAccount: the Revolut merchant account cannot take payments. |
connection_test.tenant_or_application_not_found | Result code | TokenAcquisition: Microsoft Entra does not know the tenant or the application id. |
connection_test.unexpected_response | Result code | Any check: the provider answered with a status or body the platform cannot interpret. |
connection_test.unreachable | Result code | Any check: the provider did not answer in time or the network call failed. |
connection_test.webhook_missing | Result code | The platform's webhook is not registered with Revolut, or its URL or events differ (the WebhookRegistration check). Registering the webhook again from the Revolut connection page fixes it. |
connection_test.wrong_environment | Result code | Authentication: the Revolut key belongs to the other environment (Sandbox or Production). |
email_sender.domain_in_use | 409 | The sender domain is verified for another partner. |
email_sender.domain_not_allowed | 422 | Sender address on a public mailbox domain or on the platform's own domain. |
email_sender.not_available | 409 | Setting a sender while the platform's provider is not Mailjet (Graph or none): partner sender domains need Mailjet. |
email_sender.not_found | 404 | No custom sender is set. |
email_sender.verification_failed | 409 | *Check now* did not find the SPF or DKIM records; email keeps using the platform address with the partner's display name. |
payment_connection.already_connected | 409 | Connecting while a connection exists; rotate its key or disconnect first. |
payment_connection.environment_not_allowed | 422 | The environment is not in Payments:Revolut:AllowedEnvironments (production deployments accept Production only). |
payment_connection.in_use | 409 | Disconnecting while any payment order or refund is still pending, or any billing record is Active, PastDue or Ending with auto-renewal or dunning still to run; saved payment methods belong to this merchant account. |
payment_connection.merchant_mismatch | 422 | A rotated secret key belongs to a different Revolut merchant account; saved payment methods cannot move between accounts, so rotation must stay on the same account. |
payment_connection.not_found | 404 | The partner has no Revolut connection. |
payment_connection.required | 409 | Turning on allowOnlinePurchase while the partner has no Active Revolut connection. |
payment_connection.test_failed | 422 | The Revolut read call failed with the supplied secret key, so nothing was stored. |
payment_connection.unauthorised | Result code | Revolut refused the stored secret key, and the connection is Failing. Recorded as the outcome of a connection test or health check, never returned as a problem. |
payment_connection.webhook_registration_failed | 502 | Registering, rotating or deleting the platform's webhook with Revolut failed; the connection stays in its previous state. |
publisher_source.application_in_use | 409 | The Entra application (tenant and application id) is already a publisher source on the platform. |
publisher_source.credential_invalid | 422 | The certificate cannot be used (it must be valid for at least 30 more days). |
publisher_source.disabled | 409 | A sync, resolve or mapping action names a disabled source. |
publisher_source.in_use | 409 | Deleting a source that has subscriptions or catalogue mappings; disable it instead. |
publisher_source.name_taken | 409 | Another source of the partner has the name. |
publisher_source.not_found | 404 | Unknown publisher source, or not this partner's. |
publisher_source.test_failed | 422 | Token acquisition or the Fulfillment list call failed with the supplied credential, so nothing was stored. |
Outbound webhooks
| Code | Status | When |
|---|---|---|
webhook_endpoint.address_not_allowed | 422 | The host resolves only to blocked addresses. Checked on save and enable; at send time the same check fails the attempt (blocked_address) instead. Not applied to an exact development origin. |
webhook_endpoint.disabled | 409 | Test delivery or replay to an endpoint that is Disabled or AutoDisabled; enable it first. |
webhook_endpoint.failing_for_5_days | Result code | Shown as the endpoint's disabledReason, not returned by an endpoint: it became AutoDisabled after failing continuously for 5 days. |
webhook_endpoint.limit_reached | 409 | The API client already has 10 endpoints. |
webhook_endpoint.not_found | 404 | Unknown endpoint, or not on this API client. |
webhook_endpoint.url_invalid | 422 | The URL is not an absolute https URL on an allowed port (443 by default) with a DNS host name: no user information, fragment, IP literal, localhost, single-label name or .local, .localhost, .internal, .arpa suffix, at most 1,000 characters, and never a platform host or a partner domain served by the platform. In Development and Testing only, a URL on an exact origin of OutboundWebhooks:DevelopmentAllowedOrigins (https://host:port, for example the fakes' receiver of journey J30) skips the host, port, platform-host and address rules; https, user information, fragment and length are still checked. |
webhook_message.not_found | 404 | Unknown message, not on this endpoint, or older than the 30-day delivery log. |
webhook_message.not_replayable | 409 | Replaying a message that is still being delivered (Pending or Sending). |
webhook_replay.range_too_large | 422 | Bulk replay window longer than 30 days or matching more than 10,000 messages. |
Administration
| Code | Status | When |
|---|---|---|
api_client.application_already_linked | 409 | The Entra application is already an active or pending credential of an API client on the platform (application ids are unique platform-wide among active credentials). |
api_client.application_already_verified | 409 | Requesting a new challenge for an application credential that is already active. |
api_client.application_not_found | 404 | Application not linked to this client. |
api_client.application_verification_failed | 422 | Proof of control: the challenge is unknown or older than 24 hours, or the client-credentials token's tid or azp does not match the pending credential. |
api_client.name_taken | 409 | Another client has the name. |
api_client.not_disabled | 409 | Deleting a client that is still enabled. |
api_client.not_found | 404 | Unknown API client. |
api_key.already_revoked | 409 | Rotating or revoking a revoked key. |
api_key.limit_reached | 409 | The client already has the maximum number of active keys (5). |
api_key.not_found | 404 | Unknown key on this client. |
Webhooks
| Code | Status | When |
|---|---|---|
webhook_event.not_failed | 409 | Only a Failed delivery can be retried or dismissed. |
webhook_event.not_found | 404 | No Marketplace inbox row of the partner has this id. |
webhook.authentication_failed | 401 | Mailjet secret segment or basic credentials wrong. |
webhook.connection_not_found | 404 | The {connectionId} in a Revolut webhook path names no connection, or a Disconnected one, or one of a Closed partner (7a). |
webhook.inbox_unavailable | 503 | The inbox row could not be committed, so the provider must re-deliver (Marketplace retries for about eight hours, Revolut three times). This is the only server-side failure a webhook returns; verification and processing failures after the inbox commit are retried in the background. |
webhook.not_configured | 503 | Secret or signing key not configured (the Mailjet webhook secret, or a Revolut connection whose signing secret is not yet stored). |
webhook.payload_invalid | 400 | Body is not JSON at all (after successful verification), or a Marketplace notification lacks the operation id or the action, so it has no deduplication key (7). Notifications that parse and carry both but cannot be applied (action mismatch, unknown action) are **not** errors: they are stored, verified and reconciled, and answered 200. |
webhook.signature_invalid | 401 | No v1= value in Revolut-Signature matches any active signing secret of the connection in the path. |
webhook.source_not_allowed | 403 | Source address not in the platform's Payments:Revolut:AllowedWebhookSources when that allow-list is configured. |
webhook.source_not_found | 404 | The {sourceId} in a Marketplace webhook path names no existing source, or a source of a Closed partner (6.1.17, 7); no detail is given and no inbox row is written. |
webhook.timestamp_out_of_tolerance | 401 | Revolut-Request-Timestamp more than 5 minutes from now. |
Other codes
| Code | Status | When |
|---|---|---|
marketplace.sync_kind_unavailable | Result code | |
organisation.identity_required | Result code | |
subscription_key.repeat_trial_requires_trial | Result code | |
subscription.operation_not_open | Result code |