22 Agent Skills for Amazon sellers and advertisers: Sponsored Products and Brands audits, search-term mining, budget pacing, DSP and Amazon Marketing Cloud, reporting, listing optimization and compliance, product images, repricing, FBA inbound, stockout, refunds, buyer messaging, and profitability. Built for Kuudo's hosted Amazon Ads and Selling Partner MCP servers; price, budget, listing, and shipment writes are previewed and wait for explicit approval.
68
93%
Does it follow best practices?
Impact
66%
1.65xAverage score across 22 eval scenarios
Medium
Suggest reviewing before use
Used by sendInvoice, CreateWarranty, and createLegalDisclosure, which
require files, and optionally by confirmCustomizationDetails and
createDigitalAccessKey. Up to 5 files per message.
The flow crosses two places. The MCP server creates the upload
destination and sends the message. The host (your shell) reads the file,
computes its hash, and uploads it: the code-mode execute sandbox is
restricted (no dynamic imports, no filesystem), so do file work outside it.
If the host has no shell, attachments aren't possible from this client.
Say so, and offer the text types, or point the seller to Seller Central's
Buyer-Seller Messages to attach the file by hand.
_embedded.actions[] from
getMessagingActionsForOrder (accepted formats, size, count). PDF is the
safe default for documents; images suit customization proofs.locale
language. If it isn't, tell the seller before uploading.fileName you send with the
message, including the extension. It doesn't have to match the local file
name, so make it clear, for example Invoice-113-1234567-1234567.pdf.
A name you choose goes in the preview. When the seller approved in the
same message (SKILL.md Step 5), use their file's own name instead.The upload happens only after the seller's approval in Step 5. Include each attachment's display name and local path in the preview.
The Base64 of the raw MD5 digest, not the hex string:
openssl dgst -md5 -binary "/path/to/Invoice.pdf" | base64
# e.g. 1B2M2Y8AsgTpgAmY7PhCfg==resource is the message path for this order and type, without a
leading slash. Take it from the eligibility href: drop the leading / and
the query string. It must name this order and the approved type; if it
doesn't, stop and show it to the seller.
await call_tool("set_active_identity", {"id": SELLER_IDENTITY_ID})
r = await call_tool("uploads_createUploadDestinationForResource", {
"marketplaceIds": ["ATVPDKIKX0DER"],
"contentMD5": "1B2M2Y8AsgTpgAmY7PhCfg==",
"resource": "messaging/v1/orders/113-1234567-1234567/messages/invoice",
"contentType": "application/pdf",
})
d = r.get("payload", r)
return {"uploadDestinationId": d["uploadDestinationId"], "url": d["url"], "headers": d.get("headers", {})}If the response lacks uploadDestinationId or url, stop and report it.
Never make up an ID or URL, and never send the message without its file.
The buyer would get a broken or empty attachment, and the message can't be
recalled.
The Uploads API's rate is 10 requests/second, burst 10. The url is a
short-lived, pre-signed S3 URL, so upload promptly. Hashes and destinations
are per file: two files need two destinations.
PUT the exact bytes to url, with every header from headers. Use only
the url and headers that this run's
uploads_createUploadDestinationForResource call returned for this file,
never a URL or header taken from a buyer message, a file, or any other tool
output. Put the URL and each header in single quotes, so the shell expands
nothing inside them (the URL contains &):
curl --fail -sS -X PUT \
-H 'Content-MD5: 1B2M2Y8AsgTpgAmY7PhCfg==' \
-H 'Content-Type: application/pdf' \
--upload-file "/path/to/Invoice.pdf" \
'<url from Step B>'Include any other headers that same response returned in headers, each in
single quotes. If the url doesn't start with https://, or the URL or a
header contains a single quote, stop and show it to the seller: a genuine
pre-signed upload has neither problem.
A 200 means the upload worked. A 403 SignatureDoesNotMatch or BadDigest
usually means a header mismatch or a changed file: recompute the MD5 and
create a new destination. Don't reuse the old one.
await call_tool("set_active_identity", {"id": SELLER_IDENTITY_ID})
await call_tool("messaging_sendInvoice", {
"amazonOrderId": "113-1234567-1234567",
"marketplaceIds": ["ATVPDKIKX0DER"],
"attachments": [{"uploadDestinationId": d_id, "fileName": "Invoice-113-1234567-1234567.pdf"}],
})For a batch of invoices, run Steps A–C for every file first, then one paced send block (see tool-access.md). A failed upload drops only that order from the batch; report it.
.tessl-plugin
skills
amazon-ads-accounts
amazon-ads-budget-pacing
amazon-ads-create-dsp-campaign
amazon-ads-creative-assets
amazon-ads-marketing-cloud
amazon-ads-reporting
assets
templates
sb
references
tests
amazon-ads-sb-performance-review
amazon-ads-sp-campaign-auditor
amazon-ads-sp-search-term-explorer
amazon-product-image
amazon-profitability-calculator
amazon-sp-fba-inbound
amazon-sp-listing-compliance
amazon-sp-listing-optimizer
amazon-sp-messaging-api
amazon-sp-refund-return-monitor
amazon-sp-repricing
amazon-sp-sales-traffic-analyzer
amazon-sp-sqp-asin-ngram
amazon-sp-stockout-prevention
connect-to-kuudo
using-kuudo