Amazon BFF Route — Import API
Purpose
Section titled “Purpose”POST /api/amazon/import is a server-only BFF route in arda-frontend-app that accepts an Amazon ASIN or product page URL, calls Amazon’s Creators API, and returns a stable v1 DTO representing the product. It is the data-acquisition endpoint for the “Create Item from Amazon URL” workflow (PDEV-446 / PDEV-445).
The route acts as a faithful proxy/adaptor for the Amazon Creators API GetItems response: it maps the upstream fields into a stable Arda DTO without imposing stricter field-presence requirements than Amazon does. Amazon’s GetItems responses are sparse for some ASINs (particularly digital items); nullable DTO fields are passed through as null rather than rejected. The caller receives the best information Amazon provides.
The route is not directly callable by end users; it is consumed by the SPA (a follow-up project). It has no user-facing surface in v1.
Authentication
Section titled “Authentication”Tenant-scoped Cognito JWT — identical to all /api/arda/* routes. The Authorization: Bearer <token> header is required. Anonymous requests are rejected with HTTP 401 to protect Arda’s Amazon API quota.
Request
Section titled “Request”POST /api/amazon/importContent-Type: application/jsonAuthorization: Bearer <cognito-id-token>Body:
{ "input": "<ASIN or Amazon product URL>" }input is required. Accepted forms:
| Form | Example |
|---|---|
| Bare ASIN | B08N5WRWNW |
/dp/<ASIN> (canonical) | https://www.amazon.com/dp/B08N5WRWNW |
/<slug>/dp/<ASIN>/... | https://www.amazon.com/Some-Product/dp/B08N5WRWNW/ref=sr_1_1 |
/gp/product/<ASIN> | https://www.amazon.com/gp/product/B08N5WRWNW |
/gp/aw/d/<ASIN> (mobile) | https://www.amazon.com/gp/aw/d/B08N5WRWNW |
Arbitrary query parameters are stripped before ASIN extraction. Only US amazon.com URLs are accepted.
Response — Success
Section titled “Response — Success”HTTP 200 vs HTTP 206
Section titled “HTTP 200 vs HTTP 206”HTTP 200 is returned when all four primary fields — name, image, price, and productUrl — are populated in Amazon’s response.
HTTP 206 (Partial Content) is returned when any of name, image, price, or productUrl is null. The DTO is still well-formed (nullable fields preserved); the 206 status signals to callers that Amazon’s response was sparse for this ASIN. unitCount, unit, and upc being null does NOT trigger 206 — those are routinely absent even on fully-cooperative Amazon responses (e.g. digital items and software).
Example full response (HTTP 200):
{ "ok": true, "data": { "name": "Some Product Name", "image": { "url": "https://m.media-amazon.com/images/I/...", "width": 500, "height": 500 }, "price": { "amount": 19.99, "currency": "USD", "displayAmount": "$19.99" }, "unitCount": 12, "unit": "32 oz", "upc": "012345678901", "asin": "B08N5WRWNW", "productUrl": "https://www.amazon.com/dp/B08N5WRWNW?linkCode=ogi&tag=ardacards-20&th=1&psc=1" }}Example sparse response (HTTP 206 — price and productUrl absent from Amazon’s upstream response):
{ "ok": true, "data": { "name": "Some Digital Product", "image": { "url": "https://m.media-amazon.com/images/I/...", "width": 500, "height": 500 }, "price": null, "unitCount": null, "unit": null, "upc": null, "asin": "B08N5WRWNW", "productUrl": null }}Output DTO Shape
Section titled “Output DTO Shape”The v1 DTO type is defined in arda-frontend-app/src/lib/shared/amazon/types.ts (AmazonImportDto).
| Field | Type | Nullable | Notes |
|---|---|---|---|
name | string | null | Yes | Item display title; null when Amazon’s response omits itemInfo.title |
image | { url: string; width: number; height: number } | null | Yes | Primary image at Large size; null when Amazon’s response omits images.primary.large. When present, url is Amazon-CDN-hosted and passed through unchanged |
price | { amount: number; currency: string; displayAmount: string } | null | Yes | Current Buy Box price; null when Amazon returns no Buy Box listing. When present, currency is "USD" for US-only v1; displayAmount is pre-formatted (e.g. "$19.99") |
unitCount | number | null | Yes | Integer pack count when Amazon exposes one (routinely absent for digital items) |
unit | string | null | Yes | Free-text size / unit-of-measure string (routinely absent for digital items) |
upc | string | null | Yes | Universal Product Code; first value when Amazon returns multiple (routinely absent for digital items) |
asin | string | No | 10-character Amazon ASIN — always populated |
productUrl | string | null | Yes | Amazon detailPageURL verbatim when present — see Affiliate-Tag Rule below; null when Amazon’s response omits the field |
Affiliate-Tag Rule (Constraint 3)
Section titled “Affiliate-Tag Rule (Constraint 3)”When productUrl is non-null, it is Amazon’s detailPageURL passed through unchanged. Amazon embeds Arda’s partnerTag and tracking parameters (linkCode, language, th, psc) into this URL; these must not be stripped, rebuilt, or modified. Verbatim Amazon guidance (API Rates page, 2026-05-07):
“You are using the links provided by Creators API when linking back to Amazon. Do not edit any of the URL parameters.”
When productUrl is null, Amazon’s response did not include detailPageURL for this ASIN. The route does not synthesise a fallback URL.
The buildAffiliateUrl() utility in src/lib/shared/amazon/affiliate-url.ts constructs a minimal URL from an ASIN for cases where no Creators API response is available (e.g. PDEV-429 cart-link work) — it is not used to produce productUrl in v1.
Response — Errors
Section titled “Response — Errors”Error responses use stable machine-readable codes plus human-readable default messages. The SPA can override the message copy; the code field is the stable contract.
{ "ok": false, "code": "AMAZON_ITEM_NOT_ACCESSIBLE", "message": "The requested Amazon item is not available via the API."}Error Code Matrix
Section titled “Error Code Matrix”| Code | HTTP Status | When |
|---|---|---|
AUTHENTICATION_REQUIRED | 401 | Authorization header missing or JWT invalid/expired |
INVALID_REQUEST | 400 | Request body is not valid JSON, or the input field is missing or not a string |
UNSUPPORTED_SHORT_LINK | 422 | Request body is valid and input is a string, but the value is an a.co or amzn.to short link — redirect-following not supported in v1 |
UNRECOGNIZED_AMAZON_URL | 422 | Request body is valid and input is a string, but the value cannot be parsed as a recognisable ASIN or Amazon product URL |
UNSUPPORTED_AMAZON_LOCALE | 422 | input resolves to a non-US Amazon host (e.g. amazon.co.uk, amazon.de) |
AMAZON_ITEM_NOT_ACCESSIBLE | 404 | Amazon returned HTTP 404 ResourceNotFoundException — item not found or restricted |
AMAZON_API_THROTTLED | 429 | Amazon returned HTTP 429 ThrottleException — TPS/TPD quota exceeded |
AMAZON_API_UNAVAILABLE | 502 | Amazon API failure (5xx), network failure, credential misconfiguration, or eligibility loss |
INVALID_REQUEST (HTTP 400) is the structural guard: it fires before any ASIN parsing and covers malformed JSON, missing input, or a non-string input value. UNRECOGNIZED_AMAZON_URL and the other 422s only fire when the request body is structurally valid.
AMAZON_API_UNAVAILABLE on a 401 or 403 from Amazon is alarm-worthy and indicates a credential or eligibility issue, not a transient failure.
Creators API Field Mapping
Section titled “Creators API Field Mapping”The route reads the following Creators API resource paths to populate the DTO. Only the v1 minimum set is requested:
itemInfo.titleitemInfo.productInfoitemInfo.externalIdsimages.primary.largeoffersV2.listings.priceoffersV2.listings.isBuyBoxWinnerFull mapping table — per context-exploration.md §“v1 BFF DTO ← Creators API field mapping”:
| DTO field | Creators API source path |
|---|---|
name | itemInfo.title.displayValue |
image.url | images.primary.large.url |
image.width | images.primary.large.width |
image.height | images.primary.large.height |
price.amount | offersV2.listings[0].price.money.amount |
price.currency | offersV2.listings[0].price.money.currency |
price.displayAmount | offersV2.listings[0].price.money.displayAmount |
unitCount | itemInfo.productInfo.unitCount.displayValue |
unit | itemInfo.productInfo.size.displayValue |
upc | itemInfo.externalIds.upcs.displayValues[0] |
asin | asin (top-level) |
productUrl | detailPageURL (top-level) — verbatim pass-through |
Configuration Touchpoints
Section titled “Configuration Touchpoints”Environment Variables
Section titled “Environment Variables”Four server-side environment variables are required. They are aggregated through src/lib/env.ts. All have mock-value fallbacks in mock mode.
| Variable | Description | Source |
|---|---|---|
AMAZON_CREATORS_CREDENTIAL_ID | OAuth2 client ID | 1Password vault Arda-*OAM → Amplify env var |
AMAZON_CREATORS_CREDENTIAL_SECRET | OAuth2 client secret | 1Password vault Arda-*OAM → Amplify env var |
AMAZON_CREATORS_CREDENTIAL_VERSION | Credential version string (e.g. "3.1") | 1Password vault Arda-*OAM → Amplify env var |
AMAZON_ASSOCIATE_TAG | Amazon Associates partner tag | 1Password vault Arda-*OAM → Amplify env var |
These variables must be present in the Amplify app’s branch environment before the route becomes operational. They are added to the env | grep allowlist in amplify.yml so Amplify writes them to the build’s .env.
MARKETPLACE Constant
Section titled “MARKETPLACE Constant”The US marketplace identifier "www.amazon.com" is a source constant defined in src/lib/shared/amazon/constants.ts. It is not a runtime env var — v1 supports US only (goal.md Constraint 6).
Amplify Allowlist
Section titled “Amplify Allowlist”amplify.yml includes these four variable names in the env | grep filter:
-e AMAZON_CREATORS_CREDENTIAL_ID -e AMAZON_CREATORS_CREDENTIAL_SECRET -e AMAZON_CREATORS_CREDENTIAL_VERSION -e AMAZON_ASSOCIATE_TAGSource Layout
Section titled “Source Layout”src/ lib/ shared/amazon/ types.ts # AmazonImportDto + AmazonImportErrorCode types constants.ts # MARKETPLACE constant asin.ts # extractAsin() — ASIN from URL or bare ASIN affiliate-url.ts # buildAffiliateUrl() — fallback builder (not used for productUrl) server/ lib/amazon/ creators-client.ts # fetchCreatorsApiItems() — thin wrapper around amazon-creators-api SDK routes/amazon/ import.ts # importFromAmazon() — orchestration + DTO mapping app/ api/amazon/import/ route.ts # Next.js Route Handler — JWT + JSON → importFromAmazon → responseConstraints Not Surfaced in the DTO
Section titled “Constraints Not Surfaced in the DTO”- No in-process response caching. Each request triggers a fresh Creators API call. The IP License permits caching non-image content for up to 24 hours; v1 opts for no cache to keep the implementation simple.
- Image URL is not re-hosted.
image.urlis Amazon’s CDN-hosted URL passed through unchanged. The IP License prohibits storing or caching images. Downstream callers must respect the 24-hour caching ceiling on stored URLs. - Single ASIN per call in v1. The Creators API client signature accepts a list of ASINs for future bulk use, but the v1 route always calls with one ASIN.
- Eligibility risk. Creators API access is conditional on generating qualified referring sales every 30 days. See
context-exploration.md§“API Rates, Quotas & Eligibility”.
Copyright: © Arda Systems 2025-2026, All rights reserved