DEV Community

Fernando Azevedo
Fernando Azevedo

Posted on Edited on Originally published at fernando.moretes.com

One listing, many legal entities: AWS Marketplace subsidiaries in practice

Anyone who has operated a group with one entity per country knows the hidden cost of AWS Marketplace: the same listing recreated in every seller account, with descriptions and pricing dimensions that drift silently. On 10/29/2026 AWS made it possible to publish the product once in the primary account and authorize subsidiaries to sell it through direct private offers, each under its own tax identity, currencies and bank account. The announcement sells this as the end of duplication. I read it differently: duplication leaves the catalog and becomes an authorization problem, with states, defaults and a revocation that does not do what the name suggests.

The situation: the catalog was never the problem

In a group with a US entity, a Brazilian Ltda and an Indian subsidiary, the reason for three seller accounts is not technical, it is fiscal. Each entity has to be the seller of record in its market: it holds the customer contract, invoices in local currency, pays its own Marketplace fees and gets paid into its own bank account. The documentation is explicit about this, and the new capability does not change that premise. It only removes the obligation to maintain the product inside every account.

The expensive part was never creating the listing. It was keeping three copies in sync for years: every new pricing dimension, every description tweak, every product version multiplied by the number of entities, and every drift found by a customer before you found it. That is the maintenance cost this capability attacks, and it is real.

What it puts in its place deserves the same care. The primary account now issues authorizations, one per product and per subsidiary, stating in which countries and with which pricing dimensions that entity can sell. That is access control over revenue. In a regulated environment, anything that decides who sells what, to whom and where belongs in the same bucket as an IAM role: it needs an owner, an audit trail and periodic review.

One detail that tempers the optimism of anyone who already has duplicate listings: live agreements on a subsidiary's own listing stay there and cannot be moved to the primary account's product. The migration applies to new offers, not to the installed base. You will live with both models until the last legacy contract expires.

The model: two layers and nothing shared by default

Authorization has two layers, and mixing them up is the first mistake I would expect to see in production.

Connection: done in AWS Partner Central. The primary sends the request, with up to 10 account IDs per submission, and an administrator in the subsidiary accepts it. Acceptance has a side effect that needs legal sign-off: it records the subsidiary's consent to share partner attributed revenue and its Marketplace insights reports with the primary. The connection alone authorizes no sales at all.

Authorization: a SubsidiaryAuthorization@1.0 entity in the Catalog API, created by the primary with StartChangeSet and the CreateSubsidiaryAuthorization change type. It starts in Draft, becomes Active through UpdateAvailability and ends in Restricted. It carries the product ARN (immutable), the Dimensions list, the SubsidiaryAccountId (also immutable, it becomes the SubsidiaryTargetingRule) and a BuyerTargetingTerm with CountryCodes and OfferTargeting, which today accepts only PrivateOffer.

Service role: both accounts need AWSMarketplaceSubsidiaryAuthorizationServiceRole, which AWS uses to create the resource share between them. Without it, in the console the authorization is created and never becomes active, and the subsidiary sees nothing. Through the API the error shows up as INCOMPATIBLE_ACCOUNT_STATE on the primary or INCOMPATIBLE_SUBSIDIARY_ACCOUNT_STATE on the subsidiary, and only in DescribeChangeSet, because validation is asynchronous.

Human IAM: separate from the service role, and you need both. To authorize, the primary uses AWSMarketplaceSellerFullAccess or AWSMarketplaceSellerProductsFullAccess; to create an offer from the Private offers page, the subsidiary uses AWSMarketplaceSellerOfferManagement. Those managed policies are broad. In production I would write a custom policy restricted to the Catalog API actions each team actually uses.

Who controls what: product in the primary, contract and money in the subsidiary

The diagram answers one question: where the control boundary sits between accounts. The primary owns the product and the authorization; the subsidiary is the seller of record, sets the price and gets paid. The dashed line is reporting visibility only and moves no money. Simplification: the Partner Central connection and the service role are implicit in the sharing arrow.

Primary account

  • Authorization repo Catalog API (ci)
  • Product listing SaaSProduct (data)
  • SubsidiaryAuthorization Draft, Active, Restricted (security)
  • Marketplace insights consolidated (data)

Subsidiary account

  • Private offer seller of record (compute)
  • Disbursement local bank, currency (storage)

Buyer

  • Buyer account tax address (user)

Flows

  • pipe -> authz: StartChangeSet
  • authz -> prod: references ARN
  • authz -> offer: scopes countries and dimensions
  • offer -> buyer: private offer
  • buyer -> bank: pays via AWS
  • offer -> insights: reports

Where the risk lives: revoking is not switching off

The announcement says that revoking an authorization immediately stops the subsidiary from creating new offers. Correct, and incomplete for anyone designing a control. The documentation details four behaviors that change the runbook.

Published offers survive: revoking does not cancel offers already published. The buyer can still accept an offer the subsidiary published before revocation, and existing agreements continue under their agreed terms, including renewals and disbursements to the subsidiary. If the reason for revoking is the divestiture of the entity, a restriction in a country or a corporate dispute, the block does not reach the exposure already out in the market.

Restricted is terminal: there is no reactivation. To authorize again, you create a new authorization, which gets a new ID. Any system using the authorization ID as a business key breaks on the first accidental revocation.

The connection takes everything down: ending the connection in Partner Central ends every authorization between the two accounts. An analyst who removes a connection to fix revenue attribution takes down the selling capability of the whole entity.

Narrowing breaks drafts: removing a country or a dimension makes publishing fail for draft offers that used that scope. The offer stays parked and the local seller only finds out when trying to publish, usually the day before quarter close.

The practical lesson: revocation is a process, not a click. Revoke the authorization, list the subsidiary's published offers not yet accepted, decide what happens to each one, and only then touch the connection. To shorten the exposure window, use short expiration dates on the private offers subsidiaries publish.

Authorization as code: UpdateInformation replaces everything

With more than two subsidiaries, console-made authorizations drift within weeks. The Catalog API lets you treat each authorization as a versioned resource, and three details make that mandatory, not cosmetic.

Full replacement: UpdateInformation replaces Name, Description, Resource and Terms wholesale; anything you omit is removed. Synchronous validation returns 422 if Dimensions is empty, but a BuyerTargetingTerm without CountryCodes passes, and an empty list means all countries. A script that only meant to change the description can open the Brazilian entity's sales to the whole world. The only safe approach is to always send the complete state, read from a versioned file.

The default sits on the wrong side: buyer eligibility is evaluated against the buyer's tax address. An authorization with no countries contradicts the fiscal premise that justified the local entity in the first place. In the pipeline, I would block the merge of any authorization with an empty CountryCodes.

Products do not propagate: adding a dimension to the product does not reach the subsidiary; you have to call UpdateInformation with the new list. If the product has Metered or ExternallyMetered dimensions, all of them must be in the authorization, otherwise the change set fails with INCOMPATIBLE_PRODUCT_DIMENSIONS.

The rest is idempotency and observability. StartChangeSet is asynchronous: store the ChangeSetId, poll DescribeChangeSet until SUCCEEDED or FAILED, and read the ErrorDetailList. Two authorizations for the same product and subsidiary cannot overlap countries and dimensions (DUPLICATE_SUBSIDIARY_AUTHORIZATION), which gives you a natural key for your state: product, subsidiary and country set, not the ID. Reconcile daily with ListEntities using EntityType: SubsidiaryAuthorization and diff against the repository.

Playbook for tomorrow

  1. Map entity, country and currency: Build the entity by country by currency table and confirm every subsidiary has completed its tax interview, KYC and payment setup, with a bank account and at least one disbursement currency. Without payment setup the subsidiary cannot create offers, even with an active authorization. In India, the account must be standalone, outside AWS Organizations, disburses only in INR and sells only to buyers in India.

  2. Create the service role on both ends: In each account, in Partner Central, Settings, Service roles tab, create AWSMarketplaceSubsidiaryAuthorizationServiceRole before the first authorization. Without it the authorization never activates and the console gives no warning.

  3. Accept the connection with legal sign-off: Acceptance records consent to share attributed revenue and insights reports with the primary. In a group with minority shareholders or a joint venture, that is a corporate decision, not an IT one.

  4. Version every authorization: One file per product and subsidiary, with explicit CountryCodes and the complete Dimensions list. The pipeline sends the whole state via UpdateInformation, polls DescribeChangeSet and fails the build on any non-empty ErrorDetailList.

  5. Release in two steps: Create in Draft, review DescribeEntity against the file and only then call UpdateAvailability with Active. Activation takes a few minutes; do not promise the local team the offer goes out the same minute.

  6. Write the revocation runbook: Revoke the authorization, list published and unaccepted offers, decide what happens to each one, and only then touch the connection. Include who approves, because Restricted cannot be undone.

  7. Reconcile daily: ListEntities with SubsidiaryAuthorizationFilters by status and account, diffed against the repository. Use the primary's consolidated Marketplace insights to cross-check offers, agreements and renewals per subsidiary.

The authorization name is an interface: The subsidiary picks the authorization by its Name (1 to 100 characters) when creating an offer. Put the product and scope in the name, for example Security Suite | BR, AR | users, api, and generate it from the versioned file. A hand-written name drifts from the real scope on the first change, and the local seller picks the wrong authorization without noticing.

Three ways to sell through more than one entity

Criterion Subsidiary authorization Resale authorization (CPPO) Duplicate listing
Who sells Another seller account of your own group Third-party Channel Partner Each account, with its own product
Price Subsidiary sets it; the authorization carries no price Markup over the wholesale set by the ISV Each account sets it
Currency Those configured in the subsidiary itself The one the ISV defines in the authorization The account's own
Offer types Direct private only Private through the partner Public and private
Maintenance cost 1 listing + N versioned authorizations 1 listing + one authorization per partner N listings synced by hand
Use when Local entity must be seller of record and sells through private offers A third party resells and needs margin The local entity needs a public offer or its own CPPO

Anti-patterns I would expect in the first quarter

  • Authorization without CountryCodes: an empty list means all countries, and the entity created for one fiscal market can now sell to any tax address.
  • Treating revocation as a kill switch: offers already published remain acceptable and agreements keep renewing; the block applies only to new offers.
  • Partial updates by script: UpdateInformation removes everything not sent, so a description patch can wipe countries and dimensions.
  • Removing the connection to fix attribution: ending the connection ends every authorization between the two accounts at once.
  • Authorization ID as a business key: Restricted is terminal and re-authorizing creates a new ID; key on product, subsidiary and countries.
  • Shipping a new dimension and forgetting the authorization: the subsidiary keeps selling the old product version until someone calls UpdateInformation.

Questions that will come up

Can the subsidiary create a CPPO for a local channel with the authorized product?

No. The Catalog API rejects a resale authorization created from a product the primary authorized. The subsidiary can only create CPPOs for products it owns.

Can I migrate agreements from the duplicate listing to the primary's product?

No. They stay on the original listing. Plan for coexistence until expiry and use the authorization at renewal time, as a new offer.

Can the primary create offers or complete KYC on the subsidiary's behalf?

No. Each account creates its own offers and completes its own tax interview and KYC. The service role also gives the primary no access to the subsidiary's offers, agreements or financial data.

Are Marketplace fees consolidated in the primary?

No. Listing and transaction fees are charged to the transacting subsidiary and are not pooled, netted or rebilled across accounts. Your transfer pricing model still lives outside the Marketplace.

What does it cost and where is it available?

No additional cost, in all Regions where AWS Marketplace is available, according to the 10/29/2026 announcement.

Curator's note: I would start with the lowest-volume subsidiary, a single product and two countries, and only move to the next one after running the revocation runbook end to end in a test setup. Before the first active authorization, the pipeline would already be blocking empty CountryCodes and partial updates. The hard-won lesson I bring from financial platforms: the control that causes the most trouble is not the one that blocks, it is the one that looks like it blocks and does not. Here, that control is called revocation, and its name promises more than it delivers.

Verdict

Adopt subsidiary authorization when the group has local entities that must be seller of record, sells mostly through private offers and maintains duplicate listings today: the maintenance gain is direct. Do it with authorizations in a repository, CountryCodes always explicit and a revocation runbook that handles published offers. Keep the local listing when the entity needs a public offer or its own CPPO, because neither is supported in this release.

Rating: Adote com runbook

References


Originally published at fernando.moretes.com. By Fernando F. Azevedo: Senior Solutions Architect.

Top comments (0)