Skip to main content

ELTA Amazon plugin 0.22.0

0.22.0 — listing image slots: add, remove and its undo (IMG-3)

Backend 0.32.1 vendors it. One plugin level and three Seller actions in the existing amazon.seller.listings family; no contract or core change, and existing actions keep their bytes.

  • Level LISTING_IMAGE (parent LISTING): the entity is the slot attribute name (main_product_image_locator, other_product_image_locator_1..8), the parent the SKU.
  • amazon.seller.add_listing_image (ADD on the listing, creates the slot, ListingImageAdd {slot, url}, HTTPS only): an empty slot is ACCEPTED after Amazon's VALIDATION_PREVIEW; an occupied slot (MAIN included) refuses ALREADY_EXISTS / IMAGE_SLOT_OCCUPIED (use Change listing details to replace it). Apply sends one patchListingsItem op=add on /attributes/<slot> with [{media_location, marketplace_id}] (RFC 6902 add creates an absent member; replace requires it). No automatic undo (fidelity NONE): Amazon re-hosts the image, so ELTA cannot prove the slot still holds its upload; use Remove image.
  • amazon.seller.remove_listing_image (REMOVE on the slot, ANY_WITH_SNAPSHOT, drift REFUSE): MAIN refuses PROTECTED_TARGET ("Amazon needs a main image; replace it instead") before any request; an empty slot is NO_CHANGE. The snapshot ListingImageSnapshot {slot, media_location} keeps Amazon's exact as-read URL bytes; the drift token covers only that slot's value. Apply sends op=delete with only the marketplace selector.
  • amazon.seller.restore_listing_image (revert-only ADD, BEST_EFFORT, "Restores Amazon's copy; Amazon may re-process it") writes the snapshot back with op=add, and refuses ALREADY_EXISTS when the slot is occupied again; it never overwrites.
  • Apply's final listing read re-checks the slot after ELTA's gate: an add or restore into a slot filled since then refuses ALREADY_EXISTS / IMAGE_SLOT_OCCUPIED, and a remove whose slot token no longer equals its gated base_version (changed or emptied) refuses BASE_CHANGED; neither sends a PATCH. A change between that read and the PATCH is not caught: Amazon has no conditional write, so this narrows the race and is not atomic.
  • A 5xx answer to any image patch is UNKNOWN (labelled, never resent); UNKNOWN adds and restores always reconcile UNKNOWN: an occupied slot (and Amazon's re-hosted URL) proves no writer, so a seller's image is never recorded as ELTA's created entity.
  • Known gap (core): ELTA's conflict keys do not overlap a LISTING_IMAGE ref with a set_listing_attribute on the same slot attribute (different targets in ChangeKey.overlaps), so only the apply-time re-read and drift tokens separate them.
  • Catalog: additions only (the level and three actions); authz digest unchanged (generation 5).

0.21.1 — A+ create sends a document language

Backend 0.31.1 vendors it. Amazon requires contentDocument.locale on createContentDocument; 0.21.0 always sent null, so every live A+ create was refused before anything was saved.

  • CreateAplusDocument.locale (optional AplusLocale, Amazon's LanguageTag pattern ^[a-z]{2,}-[A-Z0-9]{2,}$, hyphen form such as en-US or es-US; the underscore form that publish records report is refused). An unset locale is omitted from every dump, so stored creates keep their bytes and hashes.
  • Apply sends locale, else the marketplace's primary language from APLUS_MARKETPLACE_LOCALES (US en-US, CA en-CA, MX es-MX, BR pt-BR, UK en-GB, DE de-DE, FR fr-FR, IT it-IT, ES es-ES, NL nl-NL, SE sv-SE, PL pl-PL, TR tr-TR, IN en-IN, AU en-AU, SG en-SG, JP ja-JP). Multi-language or unverified marketplaces (BE, IE, ZA, EG, SA, AE) are absent: an unset locale there refuses the row in preview and apply before any request (PROVIDER_VALIDATION, /locale LOCALE_REQUIRED), never sending null.
  • The create preview and outcome label is <name> (<locale>), so the approval shows the language even when it is the default; the undo target's label stays the bare name.
  • Catalog adds only the optional locale property; no authz change. Rollback floor: a stored create with a set locale cannot decode on 0.21.0.

0.21.0 — A+ writes are submitted for review; real A+ documents edit losslessly; A+ create undo

Backend 0.31.0 vendors it. Three changes ship together: every A+ write is submitted for Amazon review, the A+ read projects real documents typed so a SET resends them without loss, and an A+ create can be undone by unlinking all its products (Amazon keeps the document).

Real A+ documents read typed and round-trip

  • One AplusModuleProjection.to_provider owns both the SET wire body and the read/SET-current round-trip guard. A module is typed only when its round trip equals the normalized provider JSON; otherwise it stays the opaque {module_type, raw, supported: false} marker (for example a STANDARD_COMPANY_LOGO with companyLogo: null). Every body leaf (body, block.body, ...) is written as a textList paragraph, and a path the generated module model does not declare is refused rather than sent as an extra.
  • AplusImageField.crop (AplusImageCrop {size, offset?} of AplusImageLength {value, units}) carries Amazon's imageCropSpecification: read as-is and written back byte-identical. An unset crop or offset is omitted from every dump, so pre-crop proposals keep their bytes, hashes and model_version.
  • An undecorated empty text component in a declared optional TextComponent property of a known module type (live headline: {"value": "", "decoratorSet": []}) reads as absent and a SET omits it, because Amazon's schema requires value minLength 1. Any other {value: ""} field keeps the module opaque. Required body text keeps min_length=1; an empty body row or decorated empty headline stays opaque.
  • Exact-key aplus_documents reads wrap each typed module as AplusReadModule {module, images}; images holds one read-only AplusImagePreview {name, preview_url} per image field. preview_url is set only for aplus-media-library-service-media/<id>.(jpg|jpeg|png|gif) asset IDs and is never part of a write model, hash or SET version.
  • Conversion runs inside the existing module-shape problem boundary for lookup and SET preview reads: a SET preview whose current document has a module the typed SET cannot rebuild exactly returns the existing MALFORMED_RESPONSE issue instead of a lossy undo value, and never raises.

A+ writes are submitted for Amazon review

Every A+ write now ends with one postContentDocumentApprovalSubmission (POST /aplus/2020-11-01/contentDocuments/{key}/approvalSubmissions?marketplaceId=…). APPLIED = saved and submitted for Amazon review (async: SUBMITTED → APPROVED/REJECTED via aplus_documents status); with no ASIN, create saves a draft only.

  • create_aplus_document: create → relations → submission. Amazon needs one or more ASINs before submission (create-edit-publish-aplus-content, Prerequisites), so a create with no ASIN is APPLIED with the label <name>: saved as draft; attach a product to submit for review.
  • set_aplus_content: update → submission. Its BEST_EFFORT undo runs the same apply, so it resubmits too.
  • set_aplus_asins: relations → submission for a non-empty set, because posting relations resets an approved document to DRAFT and Amazon says to submit again (a-plus-troubleshooting, "An approved document went back to DRAFT"); the empty detach set submits nothing.
  • A submission that fails after a successful write (non-2xx, transport error, timeout, or an unreadable 2xx body) is UNKNOWN with the label <name or key>: content saved, but the review submission is unconfirmed; check status in Seller Central, or edit and re-file. The content is written exactly once and nothing is resent.

The DRAFT/equal-content "submit only" retry is deferred: an unchanged SET still previews as NO_CHANGE. The submission is behaviour only: no gate, comparison, current/version, stored-shape or contract change; its only catalog change is the three A+ action changeSchema.description texts.

create_aplus_document now has an undo, the revert-only REMOVE detach_aplus_document (ELTA_CREATED, REFUSE). Amazon cannot delete A+ content, so undo posts the empty ASIN set (no submission), re-reads it to prove it empty, and the document stays in the account. Create is EXACT (the contract's fidelity for a revertible ADD) with a revert note saying so. An APPLIED create records created_version, the token of its sorted ASIN set; once the seller links other products the undo refuses CHANGED_SINCE_APPLY, and a draft with nothing linked is NO_CHANGE. An unlink whose re-read still shows products is UNKNOWN and never resent; so is an unlink answered by a 5xx, transport error, timeout or unreadable body, because it may have landed (only a 4xx refusal is REJECTED). A relation page missing Amazon's required asinMetadataSet or a row's asin is MALFORMED_RESPONSE, never an empty set, so it cannot bypass the changed-ASIN guard or falsely confirm an unlink. The undo reads only the relations and names the document from the created target's label (older targets show the document key), so no module content can block it. Direct proposals of the detach refuse REVERT_ONLY.

Creates stored before 0.31.0 or reconciled from UNKNOWN carry no created_version, so their undo is guarded only by the preview's product count and REFUSE drift.

Catalog for 0.21.0: the three descriptions above, the crop leaves under the create/SET change schemas, the crop/preview/read-module leaves under the aplus_documents result schema, the new detach_aplus_document action, and create's fidelity (EXACT), revertActionKey and revertNote. A stored proposal that carries a crop or a detach cannot decode on 0.20.0 (extra-forbid / unknown action), so once one is stored the rollback floor is backend 0.31.0. The detach reuses family amazon.seller.aplus, so the authz manifest is unchanged by it.

0.20.0 — an UNKNOWN keyword ADD reconciles by its natural key

amazon.ads.add_keyword and amazon.ads.add_negative_keyword reconcile an UNKNOWN send once from the natural key apply reports: the ad group plus the exact, case-sensitive keyword text and match type, listed with adGroupIdFilter, keywordTextFilter (EXACT_MATCH), matchTypeFilter and stateFilter ENABLED/PAUSED only. Exactly one live match returns its provider keyword id as created, so archive_keyword passes the ELTA-created gate; zero, several, a case variant, an archived-only row or a failed read stays UNKNOWN. A duplicate positive keyword ADD now previews as NO_CHANGE when an equal ENABLED/PAUSED row exists, so that create is never sent, while an archived equal row still allows a fresh ADD. No action, family, declaration, catalog or stored-byte change: the two ADDs still declare no created_from.

0.19.0 — current listing and bounded published A+ facts on previews

The four listing actions declare ListingTargetFacts: current is the unchanged snake_case ListingCurrentFacts projection already returned by listing_items, from the same listing read. Every row whose target read obtained that listing retains its facts even when validation, a prior value or inventory check refuses it. A row without a successful listing read never fabricates facts.

aplus performs one contentPublishRecords page read per SKU's own-summary ASIN, retaining only that account's marketplace. Its state is PUBLISHED for an observed matching reference, NOT_PUBLISHED only for an exhausted page with none (a draft may still exist), or UNREAD for an empty continuation, missing ASIN or failed/skipped read. records keeps only reference key, raw content type and locale. No metadata, workflow status, draft scan or ASIN relation read; A+ failure cannot reject the listing preview or discard current. Same-SKU attribute rows share the read. A no-try boundary records transport, built-in timeout and payload failures as UNREAD, warning with only the exception type; unexpected defects and cancellations propagate without hiding them.

Facts describe preview-time observations and refresh on re-preview. They are display-only, separate from the write's current value, version, undo baseline and approval/replay hashes.

Repins plugin-contract >=0.16.0,<0.17; ship with backend 0.29.0 after BE readers accept contract 4.5.0. No action key, family, permission or authz-generation change.

0.18.1 — a refused listing row still names the product

A SET_LISTING_ATTRIBUTE row whose shared VALIDATION_PREVIEW returns a provider issue became present=False with the issue and no display, so the change-list preview showed a nameless, imageless row although the same request had already read the listing. The listing_display projection is now taken once from that read and kept on every issue state the same method returns: the failed validation, the listing that omitted its product type, and the row whose prior attribute is missing. No extra provider call, contract or change-schema field: label and image_url already existed on TargetState and stay display-only, outside versions and hashes. Stored previews keep their bytes.

0.18.0 — current A+ content and typed listing reads

amazon.seller.aplus_documents exact-key reads now include ordered current modules, content type, locale, update time and badges. The shared GET sends includedDataSet=CONTENTS,METADATA as one CSV parameter, including SET content previews. Supported modules reuse the existing write converter; unknown or unsupported modules remain read-only {module_type, raw: true, supported: false} markers, so they cannot hide the rest of the document. Lookup-only envelopes accept raw Amazon content types EBC (Seller Central A+), EMC (Vendor Central A+), BrandStory and future values. Generated models are not edited; strict write models and write acceptance remain unchanged.

The existing asin query now uses contentPublishRecords, not an all-document relation scan. It finds published documents only; drafts remain reachable by exact name or reference key. All A+ metadata/relation/publish continuations send Amazon's pageToken alone, as required. ASIN/name pages omit module content; a matched reference supplies live metadata and current ASIN relations. rejection_reasons is removed: Amazon exposes workflow status and badges, not document rejection explanations. Those explanations must be checked in Seller Central.

A+ image modules still expose uploaded asset references, not guessed URLs. getMedia can return a mediaUrl for a known mediaId, but this model supplies no read-only mapping from an image module's uploadDestinationId to that mediaId. The documented resolver is the mutating createMedia POST; no media lookup or mutation is added. ASIN-relation eligibility validation remains a follow-up.

amazon.seller.listing_items adds optional typed current from the same provider response while retaining all raw groups. It includes marketplace-language text, ordered bullets, HTTPS image slots, a current B2C amount/currency and minimal product attributes. Marketplace-scoped values win then unscoped values; scalar values use the first applicable row, with no translation. Price is None if the exact-marketplace B2C offer is missing or ambiguous; no B2B or scheduled-price fallback.

No action/family key, permission, authz generation, hash algorithm or stored write schema changes. The corrected A+ dataset request can change newly observed SET content versions when Amazon now includes metadata/content; existing proposals retain their stored preview/hash bytes. Listing display helpers are shared without changing their existing write-side selection or versions.

0.17.2 — Ads accounts name their country

One advertiser's per-country Ads profiles share one name, so every choice read "Asiboan". Ads discovery now titles a profile "name · country" ("Asiboan · US") with the same elta_amz.regions.account_title rule as Seller's "store · marketplace" ("Asiboan · Amazon.com"). The plugin holds no marketplace-name table, so Ads uses the profile's country code; a profile without one keeps its name. Titles are display only and enter no hash, version or identity. A stored connection keeps its old titles until it is rediscovered: a capture request ("sync now"), a reconnect, or a changed permission declaration.

0.17.1 — new and restored listing rows show the product

add_listing and restore_listing previews target a SKU that does not exist yet, so they used to label the row with the SKU only. They now take the row's own item_name (this marketplace's entry, else the unscoped one; SKU fallback) and, for a create, its MAIN image URL; a restore snapshot keeps no images, so it shows none. Their marketplace-mismatch refusals show the same. SET and REMOVE rows already carried the live title and image since 0.16.0. The label is part of the preview hash, so only newly read create and restore previews hash differently; a stored proposal re-hashes from its stored previews. No action, change schema or refusal key changed.

0.17.0 — FBA placement and carrier confirms, committed-plan cancel, shipment labels

BL-16 finishes the FBA inbound steps after packing, behind the new default-off amazon.seller.fba_inbound_shipments family: these three calls charge the seller, so a store with the fee-free amazon.seller.fba_inbound_plans switch on never gains them. amazon.seller.confirm_fba_placement is an ADD of the plan's one placement option (created_from the option id): an identical resend once it is accepted is NO_CHANGE, a different option after confirmation is WINDOW_CLOSED, and Amazon offers no undo. amazon.seller.confirm_fba_transportation is an ADD of one carrier per shipment (selections) plus one top-level private freight contact for pallets, quoted with the carrier cost and the void deadline Amazon returns only after the confirm; the contact is copied into every selection at apply and never lives under an array item. amazon.seller.cancel_confirmed_fba_inbound_plan is the REMOVE that voids a committed plan, a forward filing in the same charged family whose read allows it only inside Amazon's window. Both confirms refuse on drift; the cancel applies anyway.

The same release adds three lookups: amazon.seller.fba_placement_options (a plan's options with their shipment split, placement fees, discounts, expiry and one options_version, generating free on the first page while no unexpired option is offered or accepted), amazon.seller.fba_transportation_options (one placement's options per shipment with carrier, mode, quoted cost and expiry, generating only with a configuration and never once transport is confirmed) and amazon.seller.fba_shipment_documents (box labels, pallet labels or bill of lading with READY and a short-lived link, AWAITING_PLACEMENT/AWAITING_TRANSPORT, or NOT_APPLICABLE without pallets; the link expires in seconds and is never stored). The levels INBOUND_PLACEMENT and INBOUND_TRANSPORT join INBOUND_PLAN, the inbound plan status reading gains accepted_placement_option_id and shipments, and two issue codes are new: PLACEMENT_OPTION_NOT_FOUND and INBOUND_SHIPMENT_NOT_FOUND. No new refusal key. The floor is 0.25.1 for every record stored today and 0.26.0 once a proposal holding one of the three new action keys is stored, because 0.16.1 refuses that row with UnknownKey.

0.16.1 — the packing preview returns Amazon's current, so the core SET gate accepts it

amazon.seller.set_fba_inbound_packing is a SET whose target read returned presence without a current, so the core gate refused every packing row as REQUEST_REJECTED. The read now returns the typed current: the ACCEPTED packing option's id, else none, plus the saved boxes from listPackingGroupBoxes in the option's packingGroups order, mapped into the request's own FbaPackingBox shape. An identical resend is NO_CHANGE; nothing saved yet gives the empty SetFbaInboundPacking(), accepted as a new change. A saved box missing a usable field keeps the option and claims no boxes, so it can only cause a resend, never a false NO_CHANGE. The current admits that empty shape, so the change schema widens: packing_option_id is optional and groupings may be empty. A request in that shape is refused as PROVIDER_VALIDATION at preview and at apply, before any read or write. Quote and version are computed from the same inputs and are unchanged. No new kind, family or refusal key. The rollback floor stays 0.25.0 for every record stored today, but a filed packing proposal keeps the empty current in its preview (packing_option_id: null, groupings: []), which 0.16.0 refuses: never roll ELTA below 0.25.1 once such a proposal is stored.

0.16.0 — change rows show the product; a create never attaches to an existing ASIN; product ads pause

Listing change rows (SET and REMOVE, including their refusals) are labelled with the listing's full itemName, falling back to the SKU, and carry the main image (mainImage, then the marketplace's main_product_image_locator); A+ rows are labelled with the document name. The label is part of the hashed preview, as the SKU was before, so a new proposal hashes the title; stored proposals verify against their own stored previews. CreateListing refuses ASIN-binding rows (merchant_suggested_asin, an ASIN identifier, legacy external_product_id_type=ASIN) as IDENTITY_ATTRIBUTE before any provider call, and a GTIN-family row that searchCatalogItems matches in the target marketplace as CATALOG_MATCH; the check runs at preview and again at apply. New amazon.ads.set_product_ad_state (SET_STATE at AD, SP only) pauses or enables one SP product ad behind its own default-off amazon.ads.product_ad_state family; EXACT undo, applies over drift. No new refusal key or change class; the live product-ad route is fixture-proven only.

0.15.2 — the listing lookup explains its own edit time

amazon.seller.listing_items now declares its meaning: it reads the requested SKUs from Seller Central at request time with their summaries, attributes, issues and offers, and a summary's lastUpdatedDate is when the seller last edited the listing, not when it was read. The plugin owns that fact, so a consumer no longer restates it in its own guidance; every other Amazon lookup stays without one. Repins plugin-contract >=0.14.4,<0.15, which refuses blank, multi-line or dotted-key guidance at registration. No provider call, capture, write or runtime backend pin changes.

0.15.1 — repins plugin-contract 0.14.0

Repins plugin-contract 0.14.0 (>=0.14,<0.15), which lets a Source declare its removal reach and revoke page. Amazon declares neither, so its removal stays LOCAL without a URL: Amazon Ads is region-specific and Seller Central is per marketplace, and a wrong link would be worse than none. No declaration, provider call, capture, lookup or write changed.

0.15.0 — Ads money writes refuse a moved value, and an unknown MSKU is the caller's

The three Ads money writes amazon.ads.set_target_bid, set_campaign_budget and set_ad_group_bid now carry DriftPolicy.REFUSE, and their readers record the live bid or daily budget as the version token, so an apply whose value moved after the preview refuses with BASE_CHANGED instead of overwriting it. Amazon Ads has no conditional write, so the re-read just before sending is the boundary. An Ads bid or budget proposal saved before 0.19.0 and approved after it has those rows refused with BASE_CHANGED; propose it again. amazon.seller.fba_prep_details answers Amazon's refusal of a batch that names an MSKU it does not know as NOT_FOUND with Amazon's own line, so the caller checks the MSKU instead of reading REQUEST_REJECTED with SUPPORT.

0.14.2 — A+ field shape and prep-details MSKUs

The A+ content preview now refuses a text field that does not fit Amazon's module shape, such as body.textList on STANDARD_TEXT, with PROVIDER_VALIDATION at /content/modules/<i> instead of failing the read, because the caller's own field name is theirs to fix and never a provider outage.

listPrepDetails sends one comma-joined mskus value per 100-MSKU batch. Amazon reads only the first of repeated parameters, so the amazon.seller.fba_prep_details lookup and the FBA create preview now read every requested MSKU rather than the first of each batch, with each MSKU's own %, + and , still double-encoded. No wire change.

0.14.1 — accepted placement and never-stocked FBA inventory

Amazon reports an accepted FBA placement option as ACCEPTED, so the FBA cancel check and the amazon.seller.fba_inbound_plan_status lookup's committed now count it. Before, the check looked for CONFIRMED, a value Amazon never returns, so only selected transportation or a shipped shipment closed the window.

The FBA inventory read behind the amazon.seller.fba_inventory lookup and the remove-listing check now reads only each summary's SKU and quantities, so a summary with an unusable last-updated time, as Amazon sent for an SKU that never held stock, no longer fails the read. A malformed quantity still fails it, because those totals gate the removal refusal. No wire change.

0.14.0 — FBA prep details, honest preview, Amazon's failure message

The new read-only amazon.seller.fba_prep_details lookup reads Amazon's saved prep details for 1 to 100 exact MSKUs (1-255 characters each). Rows carry Amazon's own strings, and Amazon omits an MSKU it does not know and prep entered only in Seller Central, so a missing row says nothing about the item.

The create preview refuses the Brazil account before any read, and otherwise refuses an item only when it breaks an explicit prep-owner or label-owner constraint, or when a MUST_MATCH all-owners constraint meets two different owners. A missing row and an UNKNOWN category pass, because Amazon states its own constraints and validates the rest at apply. A failed FBA operation now shows Amazon's own message first, with its details in parentheses.

amazon.ads declares no operator app renewal row: the shared public Ads app has no expiry, so ELTA_OAUTH_APP_SECRET_ROTATED_AT is retired and ignored if still set. Token refresh and the 365-day customer consent clock are unchanged, and the Seller public app keeps its 180-day row.

0.13.0 — keyword write family and inbound plan history

Positive keyword writes leave the negative-keywords switch. The new amazon.ads.keywords family ("Add and remove keywords") allows add_keyword and archive_keyword; the existing amazon.ads.negative_keywords family keeps its key for saved policies and is retitled "Add and remove negative keywords", so one switch no longer allows both kinds. Store owners must enable the new switch to keep positive keyword adds.

Three read-only lookups read earlier FBA inbound plans: amazon.seller.fba_inbound_plans lists the bound marketplace's plans (status filter, last-update or creation order, 30 per page) and amazon.seller.fba_inbound_plan_items/amazon.seller.fba_inbound_plan_boxes read one plan's MSKU lines and packed boxes (up to 500 per page; an unknown plan is INBOUND_PLAN_NOT_FOUND). Amazon's plan filter can leave a page short or empty while a cursor is returned, so an agent keeps paging. The plan's ship-from address is never returned. The listing and A+ undo notes now address the seller instead of naming ELTA; no action behavior, key or hash changed.

amazon.ads declares consent_lifetime_days=365, so existing connection projections show renewal from the latest successful consent (legacy grants fall back to first bind). Amazon's https://advertising.amazon.com/API/docs/en-us/guides/get-started/retrieve-access-token states that refresh tokens issued on or after July 30, 2026 expire 365 days after advertiser consent; earlier tokens have no fixed expiration and receive a conservative renewal prompt. Token refresh does not restart this clock. No plugin-contract or wire schema changes.

Pins plugin-contract >=0.13.0,<0.14. amazon.seller now offers the website-authorization CONSENT way beside the seller's own private app, but only once the operator configures the client's public SP-API app; otherwise connect stays {CREDENTIALS} and the source stays available (never available=False).

start returns one Seller Central site per Amazon store of the store's region (23 stores, each with a bilingual country label), all sharing one 600-second round state, with url set to the first site for clients predating site selection. exchange requires the callback's selling partner id (Amazon's selling_partner_id, forwarded neutrally as callback_account_id) and returns a grant sealing only refresh_token, access_token and selling_partner_id; a missing or blank id is a typed reconnect. refresh uses the app that issued the grant: the seller's sealed private pair for a credentials grant, otherwise ELTA's operator public app, keeping the selling partner id either way. A consent grant declares consent_lifetime_days = 365 (Amazon's reauthorization rule), selected by bound_with instead of the private secret's 180 days. With no seller-owned secret to name, an expired operator public secret classifies as REQUEST_REJECTED/SUPPORT, never a customer reconnect. ELTA_SELLER_PUBLIC_APP_SECRET_ROTATED_AT tracks the public pair through the operator renewal path; the shared Ads pair declares no renewal row (0.14.0).

0.11.0 — LWA secret lifecycle

Pins plugin-contract >=0.12.1,<0.13. Seller client secrets declare a 180-day lifetime and bilingual renewal steps: rotate in Seller Central, allow up to about 15 minutes for Amazon to propagate the new secret, then update it. A 403 whose details say the secret expired becomes AUTH_INVALID naming the seller's secret; role denials still name the missing permission. Seller LWA invalid_client also names the secret, and A+ upload preserves this issue. The report fatal-detail fallback remains PROVIDER_UNAVAILABLE so the next createReport classifies it; MCF reconciliation deliberately retains UNKNOWN to avoid claiming a write's outcome.

The operator-owned Ads pair declares no renewal row: the shared public Ads app has no expiry, so ELTA_OAUTH_APP_SECRET_ROTATED_AT is retired and ignored if still set, and no date is inferred from import history. Token refresh is unchanged: ELTA refreshes on demand within five minutes of expiry and re-seals a rotated token. Rotation must still update the secret in every ELTA2 Infisical scope holding the pair (hk-services prod / and test-shared prod /elta2); config-roll all three services in each environment. hzads ELTA1 updates its own stored pair through its own path and has no rotated-at setting. With no customer-owned secret to name, an expired operator secret is REQUEST_REJECTED (SUPPORT), never a customer reconnect instruction.

Amazon Ads hosts follow the store's sales region: consent uses that region's LWA prefix and the token exchange uses that region's LWA token host, so an EU or FE advertiser signs into its own Amazon account system instead of an amazon.com account that may hold no advertising access.

0.10.0 — Amazon's own levels, refusals and MCF quote choice

Declares Amazon's vocabulary under plugin-contract 0.12.0: the seven entity levels no other provider has (AmazonLevel) and the five provider-only refusal codes, each naming the standard target reason it is a case of, so PLACEMENT, PURCHASED_PRODUCT and the rest leave the shared contract. The MCF create action gains quote_choice, and the reader-less fba_inbound_plans and mcf_orders datasets with their three families move to retired for the operator retirement run. exchange() drops selling_partner_id and presence_reconcile is called through the protocol. Stored keys, action keys and approval hashes are unchanged; the pin becomes >=0.12,<0.13.

Private address text now reparses ELTA's retention token without weakening ordinary provider bounds or changing schemas.

0.9.2 — keyword ADDs send the parent campaign id

amazon.ads.add_keyword and amazon.ads.add_negative_keyword now resolve the target ad group's parent campaignId through the same SP ad-group read the ADD preview already uses and send it in the create body. Amazon SP v3 requires both adGroupId and campaignId, so the two actions previously previewed as accepted but were refused at apply with HTTP 400 INVALID_ARGUMENT ("Value null at 'keywords.1.member.campaignId'") and wrote nothing. A missing or uneditable parent now returns the preview's typed prerequisite issue instead of a provider failure. No wire-contract change: plugin-contract stays 0.11.0.

0.9.1 — FBA source address is required in its change schema

amazon.seller.create_fba_inbound_plan now declares source_address.city and source_address.phone_number required in its change schema, matching the validator it already had and SP-API v2024-03-20 AddressInput. The typed FbaSourceAddress owns that rule, so the rule is no longer duplicated in an after-validator. Requests without either field were already refused with 422, so no previously accepted request changes; the shared MCF destination address keeps both optional.

0.9.0 — ELTA 3.5 provider cut

Repins plugin-contract 0.11.0, adopts localized declarations and standard ad metrics, and validates schema-generated dataset payloads. Adds live Seller status/product-type reads, retires reader-less capture declarations and returns typed resource-not-found issues. Regional routing and approved-write identity remain intact; live provider acceptance is separate from this packages-only cut.

0.8.0 — neutral Ads intents

Repins plugin-contract 0.10.0, declares seven neutral intents, and adds SP campaign pause/enable plus ad-group default bids. Campaign state is a separate default-off switch; stored subclass names, action keys and approval hashes stay unchanged. Ship with the ELTA 3.4.0 paired contract/client/backend consumer train.

elta-amz is the Amazon provider plugin for ELTA. It implements elta_plugin_contract only and owns every Amazon-specific fact: the declaration (Amazon Ads + Seller Central sources, 18 capturing Ads datasets - 15 ordinary daily reports plus 3 UNVERIFIED gross-and-invalids - and settings, families, measures and metrics), LWA consent and refresh, report reads, report mapping and the metric formulas, including TACOS.

ELTA core owns storage, timing and history; it never imports this package. The plugin never imports ELTA core or arch/.

Centralized Ads mutations

AdsActions.read_targets reads Sponsored Products settings for the declared writes. It reports current values, labels, presence and typed provider issues; ELTA core owns policy, re-gating, diffs and pre-write records. AdsActions.apply sends only approved writes and never compares with an earlier preview. Amazon has no conditional writes, so a provider-side race remains after ELTA's final read. Keyword creation returns its provider id only when confirmed, authorizing the declared archive inverse.

Action key Neutral intent / target level Store switch Refresh
amazon.ads.set_target_bid SET_BID / TARGET BIDS SP keyword and target settings
amazon.ads.set_target_state SET_STATE / TARGET BIDS SP keyword and target settings
amazon.ads.set_campaign_budget SET_DAILY_BUDGET / CAMPAIGN BUDGETS SP campaign settings
amazon.ads.set_campaign_state SET_STATE / CAMPAIGN CAMPAIGN_STATE SP campaign settings
amazon.ads.set_ad_group_bid SET_BID / AD_GROUP BIDS SP ad-group settings
amazon.ads.set_product_ad_state SET_STATE / AD PRODUCT_AD_STATE SP product-ad settings
amazon.ads.add_keyword ADD_KEYWORD / AD_GROUP KEYWORDS none
amazon.ads.archive_keyword none / TARGET KEYWORDS none
amazon.ads.add_negative_keyword ADD_NEGATIVE_KEYWORD / AD_GROUP NEGATIVES none
amazon.ads.archive_negative_keyword none / TARGET NEGATIVES none

Keyword writes have one switch each. The new amazon.ads.keywords family ("Add and remove keywords") allows add_keyword and archive_keyword only; the existing amazon.ads.negative_keywords family keeps its key for saved policies and is retitled "Add and remove negative keywords", so it now allows the two negative actions only.

Campaign state has the new amazon.ads.campaign_state family, off by default; existing enabled bid/budget families never authorize it. BIDS keeps amazon.ads.bids and explicitly includes the ad-group default bid. Campaign pause/enable uses PUT /sp/campaigns with state; ad-group bids use PUT /sp/adGroups with numeric defaultBid. Both have EXACT undo by restoring the live before-value: a state toggle applies over drift, while the ad-group default bid refuses a live bid that moved after the preview. An SB/SD or unknown id misses the SP settings list and is NOT_FOUND at preview; archived entities retain the existing typed lifecycle issue. Product-ad pause/enable (CG-ADS-PAUSE-1) follows the same campaign-state pattern with its own amazon.ads.product_ad_state family ("Pause or enable product ads"), off by default: it reads POST /sp/productAds/list for the before-state and sends PUT /sp/productAds with {"productAds": [{"adId", "state"}]}. It is SP only; an SD product ad misses the SP list and is NOT_FOUND. No provider writes are performed by the fixture tests; Asiboan live acceptance remains a later gated step.

ELTA owns the neutral change bases. Amazon retains SetBid, SetDailyBudget, SetTargetState, AddKeyword and AddNegativeKeyword as subclasses because stored outcomes name those concrete types. Field names and approval hashes stay unchanged. TargetEnablement aliases neutral EntityState; positive keywords use KeywordMatchType.EXACT (the former PositiveMatchType is removed). Amazon's AddKeyword still requires a positive 12-digit/2dp bid; unlike the neutral base it never admits an omitted or null bid. Later SB/SD support extends these same keys and dispatches per ad product, rather than declaring competing intent/level actions.

Version 0.6.0 adds the Wave M Seller action schemas and four live lookup handles, all re-exported from the package root. Seller lookups now include Catalog Items by ASIN, Listings Items by SKU, A+ documents by ASIN/name/content reference, FBA packing options by inbound plan, and live FBA inventory by seller SKU. Every lookup uses the supplied account's region and marketplace with the existing Seller permission; results are returned live and are not persisted. The listing, A+, packing-option and inventory HTTP reads are shared with their existing Seller action paths. The public A+ response schema exposes workflow status but no rejection-reason field, so rejection_reasons remains empty. The vendored elta-plugin-contract (>=0.12,<0.13) validates action fidelity/drift metadata.

Product type lookups (additive): amazon.seller.product_type_search searches the bound marketplace by keywords or item name, and amazon.seller.product_type_definition reads the seller-specific Product Type Definition (sellerId from the grant). Its JSON Schema body is fetched only from Amazon's returned schema.link.resource through fetch_guarded (JSON only, 20 MB, 15 s); schema_sha256 is the SHA-256 of those exact bytes. An unknown type returns PRODUCT_TYPE_NOT_FOUND; a guard refusal returns a typed issue with the refusal code.

Inbound plan status lookup (additive): amazon.seller.fba_inbound_plan_status reads one plan through the GETs the FBA actions use and returns Amazon's free-string status unchanged (documented: ACTIVE, VOIDED, SHIPPED, ERRORED; newer values pass through), committed (placement confirmed, transportation selected or shipped) and the accepted packing option from the plan's own summaries. An unknown id returns INBOUND_PLAN_NOT_FOUND. amazon.seller.mcf_order_status reads one seller order through getFulfillmentOrder and returns its existing typed status. Both reads use the bound account's regional host. These are live reads, not capture-day or apply-success claims. The reader-less amazon.seller.fba_inbound_plans and amazon.seller.mcf_orders datasets and their three fact families are removed. No action refreshes them. Existing empty lane/coverage metadata has a bounded dry-run-first operator cleanup in the backend; it never deletes stored facts and refuses if a retired family contains any. LISTING_NOT_FOUND, APLUS_DOCUMENT_NOT_FOUND, INBOUND_PLAN_NOT_FOUND and PRODUCT_TYPE_NOT_FOUND now mean NOT_FOUND / CHECK_REQUEST, keeping their provider detail. Amazon Ads state dimensions use uppercase spellings across older/newer API payloads.

Inbound plan history (additive): amazon.seller.fba_inbound_plans lists the bound marketplace's plans, filterable by ACTIVE/VOIDED/SHIPPED, ordered by last update or creation in ASC/DESC order, at most 30 per page. Amazon's own filter can leave a page short or empty while a next cursor is still returned, so an agent keeps paging until no cursor comes back. The plan's ship-from address is never returned. amazon.seller.fba_inbound_plan_items reads one plan's MSKU lines (identity, quantity, label and prep owners, expiration and lot code) and amazon.seller.fba_inbound_plan_boxes its packed boxes (contents, dimensions, weight, content source and template name), up to 500 per page; an unknown plan returns INBOUND_PLAN_NOT_FOUND. All three use the FBA inventory permission of fba_inbound_plan_status on the bound account's regional host.

FBA prep details (additive): amazon.seller.fba_prep_details reads the bound marketplace's saved prep details for 1 to 100 exact MSKUs (1-255 characters each, as mskus) and returns, per MSKU, Amazon's own strings: the prep category, the prep types and the prep-owner, label-owner and all-owners constraints. Amazon refuses a batch that names an MSKU it does not know (400 "The following MSKUs are not valid: [...]"), which ELTA answers as NOT_FOUND with Amazon's own line, so the caller checks the MSKU; prep entered only in Seller Central is not returned, so a missing row only means Amazon returned nothing for that MSKU. Reads use the FBA inventory permission of fba_inbound_plan_status on the bound account's regional host, 100 MSKUs per request with 0.5 s between batches (Amazon's 2 requests/s), and persist nothing.

FBA placement, transport and documents (BL-16, additive, never on snapshots): amazon.seller.fba_placement_options and amazon.seller.fba_transportation_options read every Amazon page and answer the whole option set on the first page, each row carrying one options_version (sha256 of the set, live_reads.placement_options_version / transportation_options_version, which the confirm reads reuse). Only the first page generates (free): placement when no unexpired option is OFFERED or ACCEPTED, transport when the query has a configuration (ready-to-ship start, plus pallets and freight per shipment) and no shipment has a selected transport yet. Generation polls about 20 s inside the 30 s client bound; still running is a retryable PROVIDER_UNAVAILABLE. amazon.seller.fba_shipment_documents decides READY, AWAITING_PLACEMENT, AWAITING_TRANSPORT or NOT_APPLICABLE (no pallets) from getShipment, then mints v0 box labels (UNIQUE, every box id), pallet labels (PALLET, the pallet count) or the bill of lading on the confirmation id; the ~15 s link is a result field only, never stored. fba_inbound_plan_status adds the accepted placement and each listed shipment (confirmation id, status, warehouse, selected transport) from the same single getShipment pass committed uses.

FBA placement and transport writes (BL-16) sit in their own family amazon.seller.fba_inbound_shipments ("Confirm or cancel FBA shipments (Amazon fees apply)"), off by default, so the fee-free fba_inbound_plans switch never grants them. amazon.seller.confirm_fba_placement and amazon.seller.confirm_fba_transportation are ADDs at INBOUND_PLAN that create INBOUND_PLACEMENT / INBOUND_TRANSPORT from placement_option_id, quoted, NONE undo, drift REFUSE on the lookup's options_version. Their reads only list: the same confirmed choice is NO_CHANGE, a different one is WINDOW_CLOSED, and transport needs the placement ACCEPTED, one partnered option per placement shipment, one mode (small parcel or LTL), one carrier for small parcel, and the private top-level contact exactly for LTL (copied into every selection at apply). A lost answer after send (5xx, no operation id, lost poll) is UNKNOWN with no issue and reconciles from a fresh read; a FAILED operation re-reads Amazon, and a mixed transport result is UNKNOWN with NOT_CONFIRMED per unmatched selection. The transport APPLIED outcome re-lists the options once for carrier, cost and Amazon's voidable_until. amazon.seller.cancel_confirmed_fba_inbound_plan (REMOVE, ELTA-created plans) cancels a committed plan before transport or before the smallest void deadline, re-reading at apply; otherwise WINDOW_CLOSED. All three are fixture-proven only.

The create preview reads the same details: it refuses a Brazil account before any read, and otherwise refuses an item only when it breaks an explicit prep-owner or label-owner constraint (field /items/<n>/prep_owner or /items/<n>/label_owner), or when a MUST_MATCH all-owners constraint meets two different owners (field /items/<n>), each with PROVIDER_VALIDATION. A missing row, an UNKNOWN category or a category without a constraint passes, because Amazon states its own constraints and validates the rest at apply; an MSKU Amazon does not know refuses the row with that NOT_FOUND answer before anything is sent. A failed FBA operation reports Amazon's message first, with its details in parentheses, instead of the generic resource template alone.

Layout and E1 unit ownership

Path Protocol E1 unit
src/elta_amz/declaration.py — (Amazon's declaration and its own AmazonLevel/AmazonRefusal keys) Ads and seller declarations, including W4.3 mutation actions and the Wave M types-only block
src/elta_amz/plugin.py ProviderPlugin (handle-keyed dispatch) frozen
src/elta_amz/lwa/client.py shared LWA login (LwaClient) Ads
src/elta_amz/ads/authority.py ConnectionAuthority Ads
src/elta_amz/ads/actions.py ProviderActions Ads W4.3 mutations
src/elta_amz/ads/readers.py DatasetReader Ads
src/elta_amz/ads/mappers.py FactMapper Ads
src/elta_amz/ads/profiles.py profile discovery parse Ads
src/elta_amz/seller/authority.py ConnectionAuthority seller + TACOS
src/elta_amz/seller/settings.py seller deployment settings (public app) seller + TACOS
src/elta_amz/seller/stores.py Seller Central consent sites seller + TACOS
src/elta_amz/seller/grant.py sealed grant shape and issuing app seller + TACOS
src/elta_amz/seller/readers.py DatasetReader seller + TACOS
src/elta_amz/seller/mappers.py FactMapper seller + TACOS
src/elta_amz/calculator/__init__.py MetricCalculator composer (written) frozen
src/elta_amz/calculator/ads.py MetricCalculator Ads
src/elta_amz/calculator/seller.py MetricCalculator seller + TACOS
src/elta_amz/calculator/tacos.py MetricCalculator seller + TACOS
src/elta_amz/_generated/ moved generated Ads + selling_partner + report_models clients read-only
scripts/build_spapi_spec.py upstream SP-API spec builder Ads

Every remaining stubbed method body is raise NotImplementedError("E1: <unit>"). The dispatcher and calculator composer remain handle-driven; Ads mutation declarations and provider I/O are owned by the Ads source package.

Store regions

The core selects authority(source, region) before binding. Seller and Ads account discovery use that region; Ads discovery excludes profiles from other sales regions. The catalog advertises NA/EU/FE. Ads is unavailable when its operator app settings are incomplete; Seller is always available, through the seller's own private app and, when the operator configures the client's public app, through consent too. Ads readers and actions and Seller readers select NA/EU/FE API hosts from AccountRef.region through elta_amz.regions, never deployment endpoint settings. Opaque read handles retain that account region for later polling, downloads and pages; old regionless handles cannot resume safely and are refused rather than defaulted to NA. ELTA_ADS_API_BASE_URL and ELTA_SP_API_BASE_URL are no longer plugin settings. Seller LWA tokens remain on api.amazon.com: SP-API explicitly documents that host for every sales region. Ads consent and token hosts are region-keyed in elta_amz.regions (NA/EU/FE), because each region's LWA prefix signs the advertiser into a different Amazon account system (ADS_AUTHORIZATION_URLS, ADS_TOKEN_URLS). EU/FE routing is proven offline with recorded request URLs; Ads consent and live capture/write acceptance remain unverified.

Seller Central connects with four values from the seller's self-authorized private SP-API app (CREDENTIALS): LWA client ID, LWA client secret, Refresh token, and Seller ID (Merchant Token). The LWA client ID is not the Application ID. The store-binding form sends these values to POST /v2/connections/credentials (ConnectWithCredentialsRequest.store_id, .source_key and .fields); the amazon.seller declaration owns the credential keys. The plugin trims values, uppercases the Seller ID, checks the entered pair with one LWA refresh, and returns the validated values for ELTA to seal. Refresh keeps the issuing pair and Seller ID and replaces only the access and rotated refresh tokens. Only the secret and refresh token are declared updatable; core owns the update.

B1 adds the CONSENT way beside it once the operator configures the client's public SP-API app (below). It stays out of the source's connect until then, so an unconfigured deployment offers the private app alone and the source remains available. The seller picks their Seller Central store, signs in and approves the app; Amazon returns state, selling_partner_id and spapi_oauth_code, which ELTA exchanges with the public app pair for a grant sealing only refresh_token, access_token and selling_partner_id. A consent grant's deadline counts Amazon's 365-day reauthorization rule from its latest successful consent, never the private secret's 180 days. ELTA_LWA_TOKEN_URL optionally overrides the token endpoint for Seller apps, private and public; Amazon Ads consent, token and API hosts follow the store's sales region (NA/EU/FE).

Seller LWA invalid_client for the seller's own private app is AUTH_INVALID, naming the client secret, so the seller can update a rotated secret; for our operator public app, and for Ads, the same code stays REQUEST_REJECTED. invalid_grant requires reconnect. Permission hints translate Keble's instructions into English and Chinese while keeping Amazon's role, permission, and menu names in English inside both texts.

Operator setup for the public app

  1. In Seller Central > Apps and Services > Develop Apps, register the public SP-API app and note its Application ID (amzn1.sellerapps.app.…, for the consent URL) and its LWA client ID/secret (amzn1.application-oa2-client.…, for the code exchange and refresh).
  2. Register the app's Log-in URI as the keble.ai page that forwards the signed-in seller to Amazon's callback (/stores/login) and its Redirect URI as /stores/callback. The log-in page accepts amazon_callback_uri only over HTTPS from the saved chosen site's origin, and forwards version exactly as received. Both pages send Referrer-Policy: no-referrer.
  3. Write ELTA_SELLER_PUBLIC_APP_APPLICATION_ID, ELTA_SELLER_PUBLIC_APP_CLIENT_ID and ELTA_SELLER_PUBLIC_APP_CLIENT_SECRET only in the environment whose /stores/login Log-in URI is registered on the Amazon app (that environment is where Amazon returns the callback), then config-roll the three elta2 services there. Whether one Amazon app accepts more than one Log-in URI is unconfirmed; confirm it in Developer Central before activation. A keble-test check therefore needs either the app pointed at keble-test first or a second Draft app registered for it. While the app is a Draft leave ELTA_SELLER_PUBLIC_APP_DRAFT=true (which adds version=beta to the consent URL); set it to false after Amazon publishes the app. CONSENT is hidden until all three values are set.
  4. Amazon forces every LWA client secret to rotate about every 180 days. When the public pair is rotated, write the new secret and ELTA_SELLER_PUBLIC_APP_SECRET_ROTATED_AT (that real UTC instant, ISO 8601) in the scope that holds the pair (step 3's environment; a second keble-test Draft app has its own scope and its own rotation), then config-roll that environment's elta2 services. Readiness then reports app_renewals for amazon.seller as that instant + 180 days; with no declared instant the configured pair still warns with a null renew_by. No instant is inferred from import history. An expired public secret is ours to rotate: its 403 is REQUEST_REJECTED (SUPPORT), never a customer reconnect.

Generated clients

src/elta_amz/_generated/ is moved verbatim from ELTA1 elta.backend/amazon/access/_generated/ with only import paths fixed (amazon.access._generated -> elta_amz._generated, schemas -> elta_amz._generated._schemas). The two hand-written base modules are self-contained: the keble_helpers model config is inlined as a pydantic ConfigDict, and ELTA1's raw-response persistence classes are dropped because ELTA2 archives raw bytes and stores change-only facts. pyrightconfig.json ignores the generated implementations (types are still resolved on demand), and ruff excludes the directory.

ELTA1's amazon/access/generated/*.pyi overlay was not moved: 185 of its 200 stubs described a persistence/ wrapper layer that no longer exists, and the remaining Any stubs would shadow the real generated models, whose types the pyright ignore rule resolves on demand (verified: a bogus field is still reported).

ELTA1's operation registry (amazon/access/common/catalog/_operation_registry.py, 10M) and API spec (amazon/access/_api_spec/, 32M) were left behind: no moved generated module imports them; E1 decides whether a reader needs them.

Checks

uv sync
uv run pytest -q
npx --yes pyright .
uv run ruff check .

Metadata

Release files for elta-amz 0.22.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distribution (wheel)

Table of built distributions (wheels) for elta-amz 0.22.0
File Interpreter ABI Platform Actions
elta_amz-0.22.0-py3-none-any.whl Python 3 none any Details for elta_amz-0.22.0-py3-none-any.whl

Release files / elta_amz-0.22.0-py3-none-any.whl

Download URL elta_amz-0.22.0-py3-none-any.whl
Size 1.6 MB
Tags Python 3
SHA-256 checksum
How to use checksums
63340906c7754082124e68c08f31fa9ad35c1d925fbef98e8606e78bbf29283d
BLAKE2b-256 checksum
How to use checksums
58c6d99e9113e465b157f32b4886bc264eb190d964cea5cc383d15feed00610d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for elta-amz 0.22.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.22.0 This release

1 release file No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page