Reference · fact-checked 2026-06-10
Engineering referenceListing, buying, and licensing a product on AWS Marketplace programmatically
Agent-readable version
Plain markdown at /recipes/aws-marketplace-api.md. Fetch with one curl, ingest with any LLM tool, license CC0.
curl -O https://agledger.ai/recipes/aws-marketplace-api.md
A complete, vendor-neutral reference for doing AWS Marketplace end-to-end through APIs instead of the console: assembling and publishing a container listing (Catalog API), buying it for testing (Discovery + Agreements APIs), and enforcing entitlement at runtime (License Manager or the Metering Service). Every operation, IAM permission, region constraint, and error mapping below is drawn from AWS documentation or confirmed against a live API run.
In short: which APIs do what
To operate an AWS Marketplace product programmatically you use four distinct services, not one:
- Catalog API (seller) — create and edit your listing through asynchronous change sets, and publish it (
UpdateVisibility). - Discovery API (buyer) — read offers and their terms to drive a purchase.
- Agreements API (buyer) — request and accept an agreement (the actual purchase), and inspect entitlements and charges.
- License Manager or Marketplace Metering Service (buyer runtime) — verify the customer is entitled, and (for usage pricing) meter usage. Which one is determined by your pricing model.
All AWS Marketplace API operations run in us-east-1.
Which service owns which operation?
| Service | SDK client / CLI | Side | Owns |
|---|---|---|---|
| Catalog API | @aws-sdk/client-marketplace-catalog · aws marketplace-catalog | Seller | StartChangeSet, DescribeChangeSet, ListChangeSets, CancelChangeSet, ListEntities, DescribeEntity, TagResource/UntagResource/ListTagsForResource |
| Discovery API (Apr 2026) | @aws-sdk/client-marketplace-discovery · aws marketplace-discovery(CLI ≥ 2.34.27) | Buyer | SearchListings, SearchFacets, GetListing, GetProduct, ListPurchaseOptions, GetOfferSet, GetOffer, GetOfferTerms, ListFulfillmentOptions |
| Agreements API (May 2026) | @aws-sdk/client-marketplace-agreement · boto3 marketplace-agreement | Buyer | CreateAgreementRequest, AcceptAgreementRequest, DescribeAgreement, SearchAgreements, GetAgreementTerms, GetAgreementEntitlements, ListAgreementCharges, UpdatePurchaseOrders, cancellation/payment requests |
| AWS License Manager | aws license-manager | Buyer runtime | CheckoutLicense, CheckInLicense, GetLicense, ListReceivedLicenses |
| Marketplace Metering Service | @aws-sdk/client-marketplace-metering · aws meteringmarketplace | Buyer runtime | RegisterUsage, MeterUsage, BatchMeterUsage |
| Marketplace Entitlement Service | aws marketplace-entitlement | Seller | GetEntitlements |
The Discovery and Agreements procurement APIs were absent from aws-cli 2.33.x and arrived in later releases: Discovery in aws marketplace-discovery(≥ 2.34.27), and the procurement calls (create-agreement-request / accept-agreement-request) in aws marketplace-agreement(≥ 2.34.43). The read-only agreement commands (describe-agreement, search-agreements, get-agreement-terms) predate both. SDK clients are an equivalent alternative on any version.
Do I need AWS License Manager or the Marketplace Metering Service?
It is determined by product type × pricing model, not by preference — and wiring to the wrong service for your pricing model fails in production even when unit tests pass.
| Product type | Pricing model | Integration | Entitlement check | Metering / drawdown |
|---|---|---|---|---|
| Container | Free / hourly / fixed-monthly | Metering Service | RegisterUsage (also gates startup) | AWS meters automatically |
| Container | Usage / custom dimensions | Metering Service | MeterUsage | you emit usage per dimension |
| Container | Contract (upfront) | License Manager | CheckoutLicense | units are floating, not metered |
| Container | Contract with consumption (drawdown) | License Manager | CheckoutLicense | each checkout draws down counted units |
| AMI | hourly / annual / BYOL / contract | Metering Service or License Manager | RegisterUsage / CheckoutLicense | MeterUsage for custom |
| SaaS | subscription / contract / usage | SaaS Fulfillment v2 + Metering Service | ResolveCustomer→ activate | BatchMeterUsage |
The two “not entitled” errors differ: the License Manager path returns NoEntitlementsAllowedException; the Metering Service path returns CustomerNotEntitledException. They are not interchangeable.
How do I list and update a product through the Catalog API?
Every seller-side change is an asynchronous change set against an entity (your product). The pattern is always: call StartChangeSet, get back a ChangeSetId, then poll DescribeChangeSet until it reaches a terminal status. Use DetailsDocument (native JSON); the older Details string form is legacy.
The change types you assemble a listing from:
UpdateInformation— listing copy (title, descriptions, highlights, support info, logo, additional resources). This is a PATCH: any field you omit keeps its previous value, so a targeted copy edit cannot accidentally blank your highlights or logo.UpdateDimensions— entitlement dimensions. The payload is a bare array of{Key, Types, Name, Description};Key+Typesidentify a row andTypesis immutable once set.UpdatePricingTerms— replaces pricing terms in their entirety. You must restate every rate card, or you delete the ones you omit. Legal, Support, and Renewal terms have their own change types and are untouched by it.AddDeliveryOptions— ships a new product version plus its container delivery option (EcrDeliveryOptionDetails: container images, deployment resources, usage instructions ≤ 4000 characters).
Field limits worth pre-validating: Title ≤ 72, ShortDescription ≤ 1000, LongDescription ≤ 5000, Highlights ≤ 3, SearchKeywords ≥ 1 (≤ 250 combined characters), Categories ≤ 3. The ChangeSetName must match ^[\w\s+=.:@-]{1,100}$— note that parentheses are not allowed.
What are the change-set status values, and when can I cancel?
DescribeChangeSet returns one of: PREPARING → APPLYING → SUCCEEDED, or CANCELLED / FAILED (a FailureCode such as CLIENT_ERROR, plus per-change ErrorDetailList).
- A change set can be cancelled (
CancelChangeSet) only while it isPREPARING. - A single
StartChangeSetaccepts up to 20 changes across one or multiple entities; the same change type cannot repeat on one entity in one set. - An entity is locked while a change set runs against it — a concurrent change returns
ResourceInUseException(HTTP 423).
Container-listing rules that reject change sets
- Marketplace ECR holds plain Image Manifest V2 images only. Pushing Sigstore signatures, SLSA/attestation artifacts, or OCI referrer artifacts breaks it (
UNSUPPORTED_CONTAINER_IMAGE_URI). Mirror the image by digest into Marketplace ECR; keep supply-chain artifacts on your public registry. - No
:latestor otherwise mutable tag is allowed; referenced images must live in Marketplace ECR, and usage instructions must deploy the Marketplace ECR image. (This is a documented policy; AWS does not surface it under a single named error code.) - Usage instructions must be ASCII-only. An em-dash, smart quotes, or other Unicode triggers
INVALID_USAGE_INSTRUCTIONS. - Every
AddDeliveryOptionstriggers an automated layer scan — CVEs, malware, end-of-life OS/packages, hardcoded secrets, root user — and the change set fails if any are found. AWS also continuously re-scans public listings and can pull non-compliant products from new subscriptions.
How do I publish a Limited product to Public?
Publishing is a single UpdateVisibility change on the product with DetailsDocument: {"TargetVisibility": "Public"} — but it is the step AWS gates most heavily:
- It must be alone in its own change set, and it locks the product against all other change sets for the entire review window, so land all copy, version, and pricing changes first.
- It triggers a manual Seller-Ops review of up to 37 days. The change set can be cancelled while it is still
PREPARING, before the audit begins; a failed review returnsAUDIT_ERROR. (AWS documents an explicit 24-hour change-your-mind window specifically for the Restrict transition.) - Pre-check: a public seller profile must exist on the account, or the change fails with
MISSING_SELLER_PROFILE_INFORMATION. - Once public: a 90-day price-increase lock applies, and existing delivery options freeze (version title, container images, delivery-option title, deployment resources) — add a new version rather than editing a published one.
The review checks copy completeness, logo, EULA and refund policy, real pricing, usage instructions that actually work end-to-end, and License Manager integration behavior. Because that last point is verified against a real purchase, it pays to test the buyer experience before submitting (next section).
How do I buy or test my own listing programmatically (no console)?
A seller can subscribe to its own Limited-visibility product (proposer and acceptor on the same account works), which is the supported way to test the full purchase-and-entitlement path. The documented cheap-test pattern: keep the product Limited, drop every rate card to $0.01 with one UpdatePricingTerms change set, buy it, validate, then restore the exact original pricing (save the full original terms JSON and re-apply it, since UpdatePricingTerms replaces wholesale).
The buyer flow combines Discovery (read) and Agreements (purchase):
GetOffer(offerId)(Discovery) → theagreementProposalId(at-…), seller of record, pricing model.GetOfferTerms(offerId)(Discovery) → the term IDs (pricing, legal, support, renewal) and live rate cards.CreateAgreementRequest({ intent: 'NEW', agreementProposalIdentifier, requestedTerms: [...] })(Agreements) → anagreementRequestId(ar-…) and achargeSummarythat shows the exact charge before you commit. The pricing term carries the selected duration and dimension quantity; legal/support terms are accepted bare; the renewal term sets auto-renew.AcceptAgreementRequest({ agreementRequestId })(Agreements) → theagreementId(agmt-…). This is the point money moves.
What is the readiness signal after purchase?
Poll GetAgreementEntitlements (Agreements API) until it reports PROVISIONED — typically about 90 seconds; the agreement itself is ACTIVE immediately on accept. Do not poll the seller-side marketplace-entitlement get-entitlements, which can lag much longer and make a ready entitlement look absent. The License Manager license and grant appear shortly after PROVISIONED.
A fresh buyer account also needs the License Manager service-linked role before any checkout succeeds, or every call fails with “Service role not found”:
aws iam create-service-linked-role --aws-service-name license-manager.amazonaws.com
How do I check entitlement at runtime (contract pricing / License Manager)?
For a container product with contract pricing, your software calls CheckoutLicense at startup to prove the running customer bought it. The semantics that trip up most integrations:
ProductSKUis the product ID (prod-…), not the product code (eq9fe4…). The issued license carries the product ID in itsProductSKU, andCheckoutLicensematches on it. AWS states this in one parenthetical: “the application's Product SKU (Product ID).”- Match
CheckoutTypeto the license. A floating/tiered contract license — configured with aProvisionalConfiguration(e.g. a 60-minuteMaxTimeToLiveInMinutes), the common entitlement-check pattern — checks out withPROVISIONAL; a drawdown/consumption license usesPERPETUAL. Checking out a floating license withPERPETUALreturnsNoEntitlementsAllowedException, so match the type to the license's configuration. - The entitlement is counted. Send the entitlement as
{ Name: '<dimension>', Unit: 'Count', Value: '1' }(theValueis required). - The
ClientTokenmust be fresh per attempt (randomUUID()). License Manager accepts a token once, then rejects every reuse for the rest of the UTC day — across processes. The SDK already reuses the token across its internal retries of a single send, which is the token's only job. - Check the license back in immediately. A successful checkout consumes the counted unit for the provisional TTL, so a second replica or a restart within the hour would get
NoEntitlementsAllowed. CallCheckInLicenseright after validating, and use the result purely as an entitlement probe rather than a seat lock. The license is not node-bound: any container on any node with the right credentials can check it out. Expirationin the response is the token TTL, not the contract end. Read the contract validity from the license'sValidity(Begin/End) viaGetLicense; mappingExpirationto “licensed through” displays an expiry of today on every install.
Runtime IAM needs license-manager:CheckoutLicense, CheckInLicense, GetLicense, ListReceivedLicenses, and ExtendLicenseConsumption(the last extends a floating checkout past its TTL), with credentials supplied by the runtime (ECS task role, EKS IRSA, or instance profile) — never baked into the image.
How do I check entitlement at runtime (usage pricing / Metering Service)?
For usage or hourly pricing, the Metering Service both verifies entitlement and meters usage:
- Use
RegisterUsagefor hourly and fixed-monthly pricing (AWS meters automatically) andMeterUsagefor custom dimensions you price yourself. Not-entitled returnsCustomerNotEntitledException(aRegisterUsagecall at container startup may instead returnCustomerNotSubscribedException). - Do not configure a static region — the call must run in the task's launch region (obtain it at runtime), or you get
InvalidRegionException. - Integrate metering into the running software, not the image
CMD/ENTRYPOINT, so buyers who can insert image layers cannot override it. If product codes are passed via overridable config (CloudFormation, Helm, manifests), maintain a trusted product-code allowlist. - Calls only work on AWS container services; local development raises
PlatformNotSupportedException.
What IAM permissions does each side need?
Seller (Catalog API): the AWSMarketplaceSellerFullAccess managed policy (full Catalog write) or AWSMarketplaceSellerProductsReadOnly (read-only). For least privilege, grant aws-marketplace:StartChangeSet on the entity ARN plus a ChangeSet ARN with a /* wildcard (a fresh change-set ID is minted per request, so the wildcard is required), and optionally scope by change type with the catalog:ChangeType condition key. Resource-level permissions for StartChangeSet work only through the Catalog API, not the Management Portal console.
Buyer (procurement): the aws-marketplace:* agreement/discovery actions (e.g. CreateAgreementRequest, AcceptAgreementRequest).
Buyer (runtime): for contract products, license-manager:CheckoutLicense, CheckInLicense, GetLicense, ListReceivedLicenses, and ExtendLicenseConsumption, plus the License Manager service-linked role; for usage products, the metering actions.
Error reference: what each Marketplace error actually means
AWS Marketplace errors are terse and often overloaded onto one string. The mappings:
| Error | Service / phase | What it means |
|---|---|---|
NoEntitlementsAllowedException | License Manager checkout | Several causes behind one string: wrong ProductSKU (must be the product ID), wrong Unit, a CheckoutType mismatched to the license (use PROVISIONAL for a floating license), the counted entitlement exhausted, or the entitlement not yet propagated |
CustomerNotEntitledException | Metering Service | Buyer not subscribed (usage/metering path) |
ValidationException: Invalid request client token | License Manager checkout | A ClientToken was reused; it is accepted once, then rejected for the rest of the UTC day. Use a fresh randomUUID() per attempt |
InvalidRegionException | Metering Service | SDK pinned to a region other than where the task launched. Obtain region at runtime |
PlatformNotSupportedException | Metering Service | Called off ECS/EKS/Fargate (e.g. local dev) |
ResourceInUseException (HTTP 423) | Catalog API | Entity is locked by an in-flight change set |
MISSING_SELLER_PROFILE_INFORMATION | Catalog UpdateVisibility | No public seller profile on the account |
AUDIT_ERROR | Catalog UpdateVisibility | Seller-Ops manual review failed |
UNSUPPORTED_CONTAINER_IMAGE_URI | Catalog AddDeliveryOptions | Image isn't a plain Docker Image Manifest V2 (e.g. a Sigstore/attestation artifact pushed to Marketplace ECR) |
INVALID_USAGE_INSTRUCTIONS | Catalog AddDeliveryOptions | Non-ASCII characters in usage-instruction text |
CLIENT_ERROR (FailureCode) | Catalog | Malformed change set; inspect per-change ErrorDetailList |
FAQ
Is the AWS Marketplace ProductSKU the product ID or the product code?
The product ID (prod-…), not the product code (eq9fe4…). The issued license carries the product ID in its ProductSKU field and CheckoutLicense matches on it — passing the product code returns NoEntitlementsAllowedException for every customer.
Why does CheckoutLicense return NoEntitlementsAllowedException?
Several causes behind one string: the product code instead of the product ID in ProductSKU; the wrong Unit (a floating entitlement is Count, not None); a CheckoutType mismatched to the license (a floating license needs PROVISIONAL); a counted entitlement still held by a prior checkout’s TTL; or an entitlement that has not propagated yet. Diagnose by calling GetLicense on the issued license and diffing the real ProductSKU, Entitlements, and ConsumptionConfiguration against your request.
Why does CheckoutLicense fail with Invalid request client token?
The ClientToken was reused. License Manager accepts a token once, then rejects every reuse for the rest of the UTC day, across processes. Generate a fresh randomUUID() per attempt.
What CheckoutType do AWS Marketplace contract licenses use?
It depends on the license configuration. Floating/tiered contract licenses (configured with a ProvisionalConfiguration TTL — the common entitlement-check pattern) check out with PROVISIONAL; drawdown/consumption licenses use PERPETUAL. Checking out a floating license with PERPETUAL returns NoEntitlementsAllowedException, so match the type to the license.
Do I need AWS License Manager or the Marketplace Metering Service?
Contract (upfront) pricing uses License Manager (CheckoutLicense); usage/hourly/custom-metering pricing uses the Metering Service (RegisterUsage or MeterUsage). The not-entitled errors differ accordingly: NoEntitlementsAllowedException vs CustomerNotEntitledException.
Can a seller buy its own AWS Marketplace listing to test it?
Yes. A seller can subscribe to its own Limited-visibility product (proposer and acceptor on the same account). The documented test pattern is to temporarily reduce price via UpdatePricingTerms, purchase, then restore.
How do I test an AWS Marketplace listing cheaply?
Keep the product Limited, drop every rate card to $0.01 with one UpdatePricingTerms change set, buy it, validate, then restore the exact original pricing (save and re-apply the full original terms JSON, since the operation replaces wholesale).
How do I programmatically subscribe to an AWS Marketplace product?
Read the offer with the Discovery API (GetOffer → proposal ID, GetOfferTerms → term IDs), then purchase with the Agreements API: CreateAgreementRequest (returns a chargeSummary showing the exact price before you commit) → AcceptAgreementRequest. Both are us-east-1.
What is the readiness signal that a Marketplace entitlement is usable after purchase?
GetAgreementEntitlements reporting PROVISIONED (typically ~90 seconds). Do not poll the seller-side marketplace-entitlement get-entitlements, which lags.
Does the AWS CLI support the Marketplace Agreements and Discovery APIs?
Yes, in recent releases: Discovery in aws marketplace-discovery (≥ 2.34.27) and the Agreements procurement calls in aws marketplace-agreement (≥ 2.34.43); the read-only agreement commands predate both. aws-cli 2.33.x has neither procurement surface. SDK clients (@aws-sdk/client-marketplace-discovery, @aws-sdk/client-marketplace-agreement, boto3, or Go) work on any version.
How long does "Make Public" (UpdateVisibility) take on AWS Marketplace?
Up to 37 days. It must be a standalone change set, triggers a manual Seller-Ops review, and locks the product against all other change sets for the entire window. It can be cancelled while still PREPARING, before the audit begins; failures return AUDIT_ERROR.
Why does AddDeliveryOptions fail with UNSUPPORTED_CONTAINER_IMAGE_URI?
Marketplace ECR accepts plain Image Manifest V2 images only. Sigstore signatures, SLSA/attestation artifacts, and OCI referrer artifacts break it. Mirror the image by digest; keep supply-chain artifacts on your public registry.
Why does my usage-instructions change set fail with INVALID_USAGE_INSTRUCTIONS?
Non-ASCII characters. An em-dash, smart quotes, or other Unicode triggers it — keep the field ASCII-only.
Is an AWS Marketplace container contract license bound to a specific node or instance?
No. Any software on any container on any node can check out the license with the right credentials, which is why checking it back in immediately lets HA replicas and restarts each obtain it.
What does Expiration mean in the CheckoutLicense response?
The consumption-token TTL (checkout time plus the provisional TTL), not the contract end date. Read the contract end from the license’s Validity via GetLicense.
Why do my unit tests pass while AWS Marketplace licensing fails in production?
Mocks encode the same assumptions as the code under test, so a suite can assert the wrong contract (for example, that PROVISIONAL checkouts should be rejected) and stay green while the real integration is non-functional. The reliable check is running against a live entitlement, which the $0.01 self-purchase pattern makes cheap.
Sources
- AWS Marketplace API Reference
- Using the AWS Marketplace Catalog API — change-set workflow, status values, ≤ 20 changes/set
- Access control for the Catalog API — IAM managed policies, granular
StartChangeSet,catalog:ChangeTypecondition key - Actions, resources, and condition keys for AWS Marketplace Catalog — Service Authorization Reference
- Using the AWS Marketplace Discovery API — the 9 operations
- Using the AWS Marketplace Agreement API
- AWS Marketplace now supports programmatic procurement with Agreements API — May 2026
- Container product billing, metering, and licensing integrations — the decision matrix; region-at-runtime; license-not-node-bound
- Contract pricing for container products with AWS License Manager — the “Product SKU (Product ID)” parenthetical; floating licenses; buyer IAM
- Getting started with container products — Limited visibility, $0.01 test pricing, layer scan, going Public
- Marketplace Metering Service API reference —
RegisterUsage,MeterUsage,BatchMeterUsage