Mercado Pago(メルカドパゴ、決済サービス)の統合を、公式リソースとバンドル済みリソースから自動的に構築するウィザード(自動設定ツール)です。MCP は特定のアカウント操作や資料の不足を補う部分にのみ使用します。 **次のような場合に使用:** 開発者が Mercado Pago の決済フローを新たに追加したい、または既存のものから移行したい場合
Wizard that scaffolds a complete Mercado Pago integration from official and bundled sources, using MCP only for selected account actions or documentation gaps. Use whenever the developer wants to add or migrate a Mercado Pago payment flow.
This skill is the single entry point for building a Mercado Pago integration. It collects the minimum context from the developer and assembles a ready-to-paste bundle using curated reference files and, as fallback, the MCP server.
Use ${CLAUDE_PLUGIN_ROOT} for every bundled reference and script. Claude Code resolves it to the active plugin version. Never scan an installation cache, load another marketplace copy, or copy the plugin's .mcp.json into the developer's project.
| File | Absolute path | Read when |
|---|---|---|
terminology-rules.md |
${CLAUDE_PLUGIN_ROOT}/skills/mp-integrate/references/terminology-rules.md |
Always first |
recommendation-template.md |
${CLAUDE_PLUGIN_ROOT}/skills/mp-integrate/references/recommendation-template.md |
Always — mandatory output structure |
guides/checkout-pro.md |
${CLAUDE_PLUGIN_ROOT}/skills/mp-integrate/references/guides/checkout-pro.md |
product = checkout-pro |
guides/checkout-api.md |
${CLAUDE_PLUGIN_ROOT}/skills/mp-integrate/references/guides/checkout-api.md |
product = checkout-api |
guides/bricks.md |
${CLAUDE_PLUGIN_ROOT}/skills/mp-integrate/references/guides/bricks.md |
product = bricks |
guides/qr.md |
${CLAUDE_PLUGIN_ROOT}/skills/mp-integrate/references/guides/qr.md |
product = qr |
guides/point.md |
${CLAUDE_PLUGIN_ROOT}/skills/mp-integrate/references/guides/point.md |
product = point |
guides/subscriptions.md |
${CLAUDE_PLUGIN_ROOT}/skills/mp-integrate/references/guides/subscriptions.md |
product = subscriptions |
guides/marketplace.md |
${CLAUDE_PLUGIN_ROOT}/skills/mp-integrate/references/guides/marketplace.md |
product = marketplace |
guides/wallet-connect.md |
${CLAUDE_PLUGIN_ROOT}/skills/mp-integrate/references/guides/wallet-connect.md |
product = wallet-connect |
guides/payouts.md |
${CLAUDE_PLUGIN_ROOT}/skills/mp-integrate/references/guides/payouts.md |
product = money-out (current name: Payouts) |
guides/smartapps.md |
${CLAUDE_PLUGIN_ROOT}/skills/mp-integrate/references/guides/smartapps.md |
product = smartapps |
guides/webhooks.md |
${CLAUDE_PLUGIN_ROOT}/skills/mp-integrate/references/guides/webhooks.md |
any product + webhooks |
products.md |
${CLAUDE_PLUGIN_ROOT}/skills/mp-integrate/references/products.md |
test cards per country, API reference |
Do NOT use MCP before reading all applicable files above. For live documentation, WebFetch the official {country_domain}/developers/llms.txt (tier 1 — see Step 3), falling back to products.md.
⚠️ IMPORTANT — when invoked via /mp-integrate command: The command file already ran the environment check and readiness flow. Start directly at Step 1.a (auto-detect SDK/client/mode). Do not probe MCP state. Credentials are imported only if the developer explicitly selected that MCP-backed option.
These rules override any "what makes sense" judgement during the wizard. Past wizard runs have violated them; do not repeat the mistake.
The SDK / language is NEVER asked via AskUserQuestion. Period.
package.json, pyproject.toml, etc.).node. Mention the choice in a single line of chat (✓ SDK: node — from package.json) and continue without asking.node, mention it (✓ SDK: node — defaulted (no manifest detected; we'll create package.json during scaffolding)), and continue.AskUserQuestion.If you find yourself about to call AskUserQuestion with header="SDK" or header="Stack" or header="Language", stop immediately. The SDK is never a picker. The Tabs row at the top of the wizard must NOT include "SDK" as one of the tabs.
| Product | The ONLY valid mode values |
Picker behavior |
|---|---|---|
checkout-pro |
preferences (the Orders API does not exist for Checkout Pro) |
Skip the mode question entirely. Do not call AskUserQuestion with header="Mode". Do not show "Orders API" as an option. Use mode=preferences silently. |
checkout-api |
orders |
Always orders in ALL countries. |
bricks |
payments |
Internal routing value. card-payment and payment create Payments API payments; wallet creates /checkout/preferences; status-screen only displays a paymentId. Never add v1 to the preferences path. |
qr |
orders |
Always orders in ALL countries. |
point |
orders |
Always orders in ALL countries. |
marketplace |
preferences or payments |
Resolve marketplace-checkout= first. Checkout Pro and Wallet Brick use Preferences; Checkout API uses Payments API. Marketplace is not a standalone Orders API mode. |
wallet-connect |
orders |
Always orders. Never ask. |
subscriptions |
n/a (uses its own preapproval API) |
Skip the mode question. |
money-out |
n/a (current product name: Payouts; country-specific API contract) | Skip the mode question. |
smartapps |
n/a | Skip the mode question. |
If product=checkout-pro and you are about to render a Mode picker that includes Orders API, abort. The Orders API is not available for Checkout Pro today. Period. Do not "future-proof" by offering it. Do not add a "Recommended" tag to it. Do not include it in any "Other" fallback.
init_point, never sandbox_init_pointMercado Pago removed the sandbox environment. There is no staging URL. Every integration — including test-user flows — runs against the production API.
Never generate code that references sandbox_init_point. Always use init_point from the preference response. The difference between a test run and a production run is only which credentials are loaded (APP_USR- from a test user vs. a real account) — not the URL.
If you find sandbox_init_point in existing code, flag it as a bug: the redirect will fail silently or land on an error page.
Also applies to test users: test users created via create_test_user operate against the production API host using the APP_USR- credentials returned for that test-user account. There is no separate test base URL or sandbox toggle. This does not make TEST- credentials invalid: static test credentials for Checkout API, Bricks, and Payments API may use TEST-. Code using sandbox_init_point with any credential will not work.
The wizard's Tabs row at the top (the □ Country □ Product □ Mode ✓ Submit line) must include only the dimensions that are actually still unresolved AND non-skipped per LOCK 1 and LOCK 2. Concretely:
product is checkout-pro / bricks / wallet-connect / subscriptions / money-out / smartapps.Immediately after the product is resolved, normalize these aliases before any product branch:
checkout-api-orders, checkout-transparente, checkout-transparent, checkout_api → checkout-apicheckout-pro remains checkout-proFor either normalized value, run this from the target project root before assembling or writing the checkout UI:
node "${CLAUDE_PLUGIN_ROOT}/scripts/resolve-checkout-cta.mjs" "{product}" .
Persist the returned product, status, selected, candidates, and nextAction for Step 2.5. Do not independently reinterpret checkout-api-orders as another product. nextAction=wire_selected_cta requires using selected; nextAction=ask_user_for_cta_or_insertion_location requires an immediate AskUserQuestion for a concrete target. A Checkout Pro or Checkout API scaffold may never finish successfully without a wired CTA. This lock applies equally to both products; do not change the working Checkout Pro behavior while fixing Checkout API.
auto_returnWhen product=checkout-pro, auto_return: "approved" is valid only when the effective APP_URL is a public HTTPS origin. If APP_URL is missing, uses localhost, 127.0.0.1, 0.0.0.0, or is not HTTPS, omit auto_return from the preference body. Do not merely provide localhost back_urls: the Preferences API rejects that combination before creating the preference.
For applications that support local and production execution, derive an explicit publicAppUrl boolean from APP_URL (HTTPS and non-local) and conditionally spread { auto_return: "approved" } only when it is true. Before reporting success, run validate-checkout-pro-server.mjs as required by Step 3.5.
When product=point, scaffold only the current Orders API flow: POST /v1/orders, type: "point", and config.point.terminal_id. Never generate /point/integration-api/.../payment-intents, type: "instore", or config.device.id.
For a developer without hardware, support the official standard virtual terminal NEWLAND_N950__SBX0000001, but only behind an explicit MP_POINT_TEST_MODE=true guard. Production must require MP_POINT_TERMINAL_ID; it may never silently fall back to the virtual terminal. Include order lookup by ID so the application can reconcile asynchronous status changes. Before reporting success, run:
node "${CLAUDE_PLUGIN_ROOT}/scripts/validate-point-server.mjs" "{server_file}"
When product=qr, scaffold only POST /v1/orders with type: "qr", matching
total_amount and transactions.payments[0].amount, and
config.qr.external_pos_id. The only valid QR modes are static, dynamic, and
hybrid. Never generate /instore/orders/qr/..., /instore/qr/..., a redirect
Checkout order, or a QR whose content is a Checkout URL. Keep the request minimal:
do not invent a payer and remove legacy items[].currency_id and
items[].total_amount fields. Validate client-supplied prices, quantities, and
the computed total as finite positive values. QR cancellation must not copy the
Point-only X-Allow-Cancelable-Status header.
Store and POS provisioning is a prerequisite, not a hidden side effect of the
scaffold. Reuse an existing POS when one is explicitly configured. If none is
available, ask for the real Store location before creating persistent resources;
never invent an address. Dynamic and hybrid modes render
type_response.qr_data locally. Static mode renders the QR returned when the POS
was created. Include order lookup and cancellation, and run both acceptance
checks before reporting success:
node "${CLAUDE_PLUGIN_ROOT}/scripts/validate-qr-server.mjs" "{server_file}"
node "${CLAUDE_PLUGIN_ROOT}/scripts/validate-qr-client.mjs" "{client_file}" 'data-mp-qr-cta="create-order"' "/api/qr/orders"
Resolve brick= before writing code and read references/guides/bricks.md. Never
apply one Brick's backend to all four variants:
card-payment: CardPayment/cardPayment creates a Payments API payment.payment: Payment/payment creates the selected method via Payments API.wallet: Wallet/wallet creates a preference using exactly
/checkout/preferences; the path has no version segment.status-screen: StatusScreen/statusScreen renders a validated paymentId;
it does not create a payment and must not receive an order ID.Use the application's actual framework and scan the whole project for a real checkout CTA. When one exists, preserve its presentation and link it to the new dedicated Brick page after removing the competing old handler. If none exists, create the page anyway and report the exact route/invocation the developer must link. Never collect raw card fields around a Brick. Before reporting success:
node "${CLAUDE_PLUGIN_ROOT}/scripts/validate-bricks-integration.mjs" . "{brick}"
When product=subscriptions, resolve subscription-model= before writing code
and read references/guides/subscriptions.md. The only valid values are
with-plan, without-plan-authorized, and without-plan-pending.
with-plan uses a server-controlled preapproval_plan_id, a securely
tokenized card_token_id, and status: "authorized". Never accept a plan ID
from the browser or create a plan from the buyer CTA.without-plan-authorized sends trusted server-side recurrence terms, a
securely tokenized card_token_id, and status: "authorized".without-plan-pending sends trusted recurrence terms and status: "pending",
omits card_token_id, and redirects only to the returned init_point.Authorized flows must use MercadoPago.js CardForm or the official Card Payment
Brick. Never ask the buyer to paste a card token, never collect raw card data,
and never omit the CardForm lifecycle selects (issuer, installments, and
identificationType). Scan the whole application for every subscription CTA.
All marketing/entry CTAs must converge on the existing or generated dedicated
signup page; only its final CTA may create a preapproval. Remove competing demo
handlers and orphan server routes so exactly one preapproval creator remains.
Before reporting success:
node "${CLAUDE_PLUGIN_ROOT}/scripts/validate-subscriptions-integration.mjs" . "{subscription-model}"
When product=marketplace, resolve marketplace-checkout= before writing code
and read references/guides/marketplace.md. The only supported values are
checkout-pro, checkout-api, and bricks-wallet.
checkout-pro uses the connected seller OAuth access token, exactly
/checkout/preferences, and marketplace_fee.checkout-api uses the integrator public key, the connected seller OAuth
access token, /v1/payments, secure tokenization, and application_fee.bricks-wallet uses the integrator public key, seller OAuth access token,
exactly /checkout/preferences, marketplace_fee, a dynamic preferenceId,
and marketplace: true.Every contract must implement one-time server-side OAuth state, exact redirect URI matching, authorization-code exchange, encrypted persistent seller tokens, refresh-token rotation, and trusted server-side seller/cart/commission resolution. Never accept seller ID, amount, commission, collector ID, or OAuth tokens from the browser. Marketplace is not a standalone Orders API flow and must not silently fall back to the platform token. Before reporting success:
node "${CLAUDE_PLUGIN_ROOT}/scripts/validate-marketplace-integration.mjs" . "{marketplace-checkout}"
When product=wallet-connect, read
references/guides/wallet-connect.md before any scaffold decision.
BLOCKED: active Wallet Connect agreement required and do not
write files. If enablement is unknown, ask once before writing.orders mode. Do not ask about mode and do not replace
this product with the Wallet Brick or Advanced Payments API.Before reporting success, run:
node "${CLAUDE_PLUGIN_ROOT}/scripts/validate-wallet-connect-integration.mjs" .
When product=smartapps, read references/guides/smartapps.md before any
scaffold decision.
BLOCKED: active SmartApps agreement required and do not write files.mcp__plugin_mercadopago_mcp__search_documentation for the current
SmartApps guide even when tier-1 public documentation is available. If MCP
authentication is missing, run the normal inline authentication flow and
stop until it succeeds.main versus mini and own versus third-party before writing.
Main apps own the HOME launcher; mini apps do not. Third-party integrations
require the SDK OAuth mode.Before reporting a successful static scaffold, run:
node "${CLAUDE_PLUGIN_ROOT}/scripts/validate-smartapps-integration.mjs" . "{main|mini}" "{own|third-party}"
Passing this check is not device certification. Compilation requires the real latest AAR; payment and hardware validation require the Mercado Pago development terminal and the sandbox-flavor kit.
When product=money-out, read references/guides/payouts.md before any scaffold
decision and present the current product name as Payouts.
disbursements API, Advanced Payments, Marketplace split,
checkout flow, buyer CTA, or card form. The old Money Out URL now redirects
to Payouts.BLOCKED: verified Payouts country contract required if it does
not return a verified contract.Before reporting success, run:
node "${CLAUDE_PLUGIN_ROOT}/scripts/validate-payouts-integration.mjs" . "{AR|BR}"
$ARGUMENTS and ask for missing context$ARGUMENTS may include any combination of these flags. Anything missing must be asked via AskUserQuestion in batches of ≤4.
| Flag | Values |
|---|---|
country= |
AR / BR / MX / CL / CO / PE / UY |
product= |
checkout-pro / checkout-api / bricks / qr / point / subscriptions / marketplace / wallet-connect / money-out / smartapps |
mode= |
depends on product — see Product Matrix below |
sdk= |
node / python / java / php / ruby / dotnet / go (or none for raw REST) |
client= |
vanilla-js / react / ios / android / flutter / react-native (only for products with a client component) |
lang= |
es / en / pt (docs language) |
recurrent= |
yes / no (Checkout API, Bricks) |
3ds= |
yes / no (Checkout API, Bricks) |
marketplace= |
yes / no (split payments) |
brick= |
payment / card-payment / wallet / status-screen (only when product=bricks) |
qr-mode= |
static / dynamic / hybrid (only when product=qr) |
subscription-model= |
with-plan / without-plan-authorized / without-plan-pending (only when product=subscriptions) |
marketplace-checkout= |
checkout-pro / checkout-api / bricks-wallet (only when product=marketplace) |
smartapps-agreement= |
confirmed (only when product=smartapps; absence is never inferred as confirmation) |
smartapp-kind= |
main / mini (only when product=smartapps) |
smartapp-ownership= |
own / third-party (only when product=smartapps) |
After parsing or inferring product, apply LOCK 5 normalization immediately. Use only the normalized internal value for the Product Matrix, guide selection, CTA resolution, and scaffold branches. The presentation-only slug checkout-api-orders may appear in the final recommendation metadata, but it must never be used as an internal branch value.
You MUST run this step before any AskUserQuestion call. Every dimension that resolves here is removed from the wizard. The developer should only be asked about dimensions that genuinely cannot be inferred. Skipping the auto-detection and asking the developer anyway is the single most common mistake — do not do it.
For every dimension, attempt these resolution sources in order:
| Dimension | 0th: agent inference (Step 1.a) | 1st: persisted | 2nd: repo signals | 3rd: ask |
|---|---|---|---|---|
product |
If agent resolved from message keywords → use it, skip question | Read from .mp-integrate-progress.md |
— | AskUserQuestion picker |
country |
If agent resolved from message keywords → use it, skip question | Read from .mp-integrate-progress.md |
None — do not grep for country (unreliable, costs tokens) | AskUserQuestion picker. Persist the answer. |
sdk |
— | — | MUST run Glob for: package.json→node, pyproject.toml/requirements.txt→python, pom.xml/build.gradle*→java, composer.json→php, Gemfile→ruby, *.csproj/Program.cs→dotnet, go.mod→go. Single match → resolved. Multiple matches → choose the manifest in the active application area. No match → default to node. |
Never ask which SDK; only ask authorization before an install/update. |
client |
— | — | Inspect package.json deps: react/next→react, react-native/expo→react-native, *.xcodeproj→ios, Android build.gradle→android, pubspec.yaml→flutter. Single match → resolved. |
AskUserQuestion (only if product has client component AND ambiguous) |
lang |
— | — | Derive from country (BR→pt, others→es). | Almost never asked — defaulted from country |
mode |
— | Read from progress file | Grep for /v1/orders/order.create→orders; /v1/payments/payment.create→payments; /checkout/preferences/preference.create→preferences. Product Matrix may pin to single value (e.g. checkout-pro → always preferences). |
AskUserQuestion (only when matrix allows >1 AND grep didn't disambiguate) |
Concrete order of operations for the wizard (INFER FIRST, ASK LAST):
Check for legacy Instore APIs in repo (before any question). Run Grep for legacy QR/Point patterns:
/mpmobile/instore/qr (QR Instore)/instore/qr/seller/collectors (QR Instore V2)/instore/orders/qr/seller/collectors (QR Dinámico)/point/integration-api/devices/.*/payment-intents (Point PDV + Self Service)If any found AND the project is not already fully on /v1/orders, ask once via AskUserQuestion:
"Existing integration""Yes, migrate first (/mp-integrate migrate)" / "No, scaffold the new integration"/mp-integrate migrate to migrate the existing integration, then come back to scaffold the new one."$ARGUMENTS already contains migrate.Check agent inference — if the agent's Step 1.a resolved product= and/or country= from the developer's message, those dimensions are already resolved. Do NOT ask for them.
Read .mp-integrate-progress.md if it exists — pull any previously-resolved values.
Do NOT grep for country. Country is asked via AskUserQuestion unless already resolved by steps 1–2. No locale-string grep, no mercadopago.com.<tld> grep, no currency_id grep — they cost tokens and produce wrong matches.
Run Glob over the manifest patterns. If a single SDK manifest matches, the SDK is RESOLVED — do NOT ask. The official Mercado Pago SDK for the detected language is the one used. Never propose a third-party SDK.
If the product needs a client, run Glob/Grep on manifest deps. If a single client matches, client resolved. Skip the client question.
Default lang from country. Skip the lang question.
Now — and only now — call AskUserQuestion for whatever is still missing, one tool call at a time, in the order defined in Step 1.b. After each answer, persist it to .mp-integrate-progress.md.
Known MCP limitation — country resolution: The Mercado Pago MCP does not currently expose a tool that returns the developer's site_id (neither application_list nor quality_checklist nor notifications_history carry the country in their response). The OAuth access token would let us call GET https://api.mercadopago.com/users/me directly, but the token is held by the MCP server and is not exposed to the plugin client. Until MP ships a new MCP tool (e.g. current_user_info or a generic proxy_request), country resolution is just: read .mp-integrate-progress.md if it has a country, otherwise ask via AskUserQuestion and persist. Do not waste tokens grepping the repo for country signals (locales, URLs, currency_id, site_id, app-name heuristics) — they don't pay off, and asking the developer once is cheaper and more reliable.
After auto-resolving, render a single confirmation block listing every value that was inferred (not just country — also SDK, client, and any other dimension that came from the repo). Then, before any wizard question, ask the developer with one AskUserQuestion:
header="Confirm setup""I auto-detected the following from your repo. Is everything correct?""Yes, continue" — proceed to Step 1.b with the auto-resolved values."No, let me correct" — drop the user-selectable auto-resolved values back into the wizard queue. Do not add SDK/language to that queue: re-run repository detection for them and explain the selected official SDK without presenting an SDK picker.Skip this confirmation only when there was nothing to auto-resolve (clean repo, no manifest, no locale, no existing MP URLs). In that case the wizard goes straight to asking.
Example block to render:
I auto-detected the following from your repo:
✓ App: My Store (123456789012345) — from application_list
✓ SDK: node — from backend/package.json (mercadopago v2.12.0 already installed)
✓ Client: react — from frontend/package.json
Country will be asked next (not auto-detected).
Confirm the above to continue, or correct.
The developer must explicitly opt-in to the auto-resolved set. Never proceed silently to Step 1.b after auto-resolving — that's how wrong assumptions propagate to the final bundle.
If the agent already passed flags (country=, sdk=, mode=, etc.), treat those as resolved too.
Anything still unresolved after 1.a goes into the wizard in 1.b.
Always use the official Mercado Pago SDKs, listed below, regardless of whether the developer mentions a wrapper or alternative library. The official SDKs are maintained by Mercado Pago and aligned with the live API.
This is the most-violated rule of the wizard. The two screenshots that broke the v4 wizard were caused by violating this section. Read it twice.
STOP-TEST before writing any chat output:
If your response includes ANY of these patterns, you are doing it wrong — abort and use AskUserQuestion instead:
Question N of M1. Country / 2. Product / 3. SDK (numbered question list)- checkout-pro — …Type the code or Reply with or Answer withThese are all the v3 anti-pattern. The developer cannot click on plain text. They get a worse experience than the v3 plugin you just rewrote.
HARD RULES — no exceptions:
AskUserQuestion. If your first tool call is anything else (Read, Write, Bash, search_documentation, …), you skipped the wizard and went straight to "ask in chat". Stop and restart with AskUserQuestion.AskUserQuestion runs one tool call per dimension, waiting for the answer before issuing the next call. The developer sees an interactive picker with arrow-key selection.AskUserQuestion call MUST be ≤3 short lines — one line per auto-resolved dimension, plus an optional one-line "now I'll ask the rest". No menus, no numbered lists, no "I'll ask you 4 quick questions".AskUserQuestion calls: ≤1 line of confirmation, then immediately the next call. Do not summarise progress, do not show "Question N of M".Order of AskUserQuestion calls — only for dimensions still unresolved after Step 1.a. Skip any dimension that is already known. Do NOT ask about dimensions the Product Matrix marks n/a for the chosen product.
| Order | Dimension | Header | Options to show |
|---|---|---|---|
| 1 | product |
"Product" | The 4 most likely products as buttons + "Other" auto-fallback. Pick the 4 from this priority: checkout-pro, bricks, checkout-api, subscriptions (most common). The remaining ones (qr, point, marketplace, wallet-connect, money-out, smartapps) are reachable via "Other". |
| 2 | mode |
"Mode" | Cross-reference LOCK 2 first. Skip entirely when LOCK 2 says "Skip the mode question". When asked, only show modes that LOCK 2 explicitly allows for the chosen product. Never include "Orders API" as an option for checkout-pro. |
| 3 | client |
"Client" | Only if the product has a client component AND repo signals were ambiguous. Show the 3 most likely + Other. |
| 4 | brick |
"Brick" | Only when product=bricks. Options: payment / card-payment / wallet / status-screen. |
| 5 | qr-mode |
"QR mode" | Only when product=qr. Options: static / dynamic / hybrid. |
| 5.5 | subscription-model |
"Subscription" | Only when product=subscriptions. Options: with-plan / without-plan-authorized / without-plan-pending. |
| 5.6 | marketplace-checkout |
"Marketplace" | Only when product=marketplace. Options: checkout-pro / checkout-api / bricks-wallet. |
| 5.7 | smartapps-agreement |
"Agreement" | Only when product=smartapps. Ask whether the active commercial/integration agreement with Mercado Pago is confirmed. Options: confirmed / not confirmed. If not confirmed, stop before any write. |
| 5.8 | smartapp-kind |
"SmartApp type" | Only when product=smartapps and the agreement is confirmed. Options: main / mini. |
| 5.9 | smartapp-ownership |
"Terminal use" | Only when product=smartapps and the agreement is confirmed. Options: own / third-party. |
| 6 | recurrent |
"Recurrent" | Only when the matrix marks it yes for the chosen product. Options: yes / no. |
| 7 | 3ds |
"3DS" | Only when the matrix marks it yes. Options: yes / no. |
| 8 | marketplace |
"Splits" | Only when the matrix marks it optional. Options: yes / no. |
sdk is intentionally absent from this table — see LOCK 1 above. The SDK is never asked via AskUserQuestion.
environment is NEVER asked. Mercado Pago no longer has a sandbox/production toggle. Both production credentials and test-user credentials use the APP_USR- prefix; the difference is whether the credentials belong to a real account or a test user (handled in mp-test-setup). Do not present an "Environment: production / test" picker. Do not write code that branches on NODE_ENV to switch MP base URLs.
mode without an eager MCP callUse the Product Matrix below first. If its mode cell is fixed for the selected product, use that value and do not connect to MCP.
Only when the product/mode combination is absent or genuinely ambiguous in the bundled sources, use mcp__plugin_mercadopago_mcp__search_documentation with a query like "{product} orders api {country}". This is an MCP-backed fallback: authenticate immediately before that query, not earlier. Never run it for checkout-pro — LOCK 2 already forbids Orders for that product.
If the fallback docs explicitly confirm a mode, use it for this run. If they do not, do not offer an unverified mode.
This rule exists because the v4 wizard offered Orders for Checkout Pro when the API does not exist for that product. Never offer a mode that does not exist on the MP API today, even if it is rumored or coming-soon.
country will commonly end up in this list. Today the MCP does not return site_id, so unless repo signals or persisted state resolved it in 1.a, you will need to ask. Use header="Country" with AR, BR, MX, CO as buttons (the 4 most common) — the picker auto-adds an "Other" entry that lets the developer type CL, PE, or UY. After the answer, persist it to .mp-integrate-progress.md.
Wrong (v3 anti-pattern, exactly what the screenshot showed):
Now I need a few details to scaffold the right integration:
1. Country — Which site/country are you integrating for?
- MCO — Colombia
- MLA — Argentina
…
2. Product — Which Mercado Pago product…
…
3. SDK / Language — What stack are you using?
…
Right:
✓ App: My Store (123456789012345) — from application_list
✓ SDK: node — from package.json
(Country will be asked next — not auto-detected.)
→ then immediately the AskUserQuestion call for product. The developer picks. Then ≤1 line confirmation. Then the next AskUserQuestion. And so on.
Golden rule of persistence: every piece of information collected — by inference, by wizard, by MCP, by any means — is written to .mp-integrate-progress.md immediately after collection. It is never asked again unless the developer explicitly changes it.
At the start of every run, read this file first and use every value found in it. Only ask for dimensions that are genuinely absent.
Fields to persist (write after each is resolved, do not wait until the end):
# mp-integrate progress
- country: AR
- product: checkout-pro
- mode: preferences
- sdk: node
- client: react
- lang: es
- credential_type: test
- application_id: 123456789012345
- brick: card-payment
- qr_mode: dynamic
- subscription_model: with-plan
- marketplace_checkout: checkout-pro
- recurrent: no
- three_ds: no
Rules:
.mp-integrate-progress.md to .gitignore if not already there.| Product | sdk | client | mode (allowed values) | recurrent | 3ds | marketplace | sub-flag |
|---|---|---|---|---|---|---|---|
checkout-pro |
yes | optional | preferences only — Checkout Pro does NOT have an Orders API mode |
n/a | n/a | optional | n/a |
checkout-api |
yes | yes | orders (ALL countries) |
yes | yes | optional | n/a |
bricks |
yes (server) | yes | internal payments routing; backend is variant-specific per LOCK 9 |
yes (payment, card-payment) | yes (payment, card-payment, status-screen) | optional | brick= |
qr |
yes | n/a | orders (ALL countries) |
n/a | n/a | n/a | qr-mode= |
point |
yes | n/a | orders (ALL countries) |
n/a | n/a | n/a | n/a |
subscriptions |
yes | conditional (authorized contracts use MercadoPago.js) | n/a (own preapproval API) |
implicit | n/a | optional | subscription-model= |
marketplace |
yes | conditional | preferences for Checkout Pro/Wallet; payments for Checkout API |
n/a | n/a | implicit | marketplace-checkout= |
wallet-connect |
yes | n/a | orders |
n/a | n/a | n/a | n/a |
money-out |
conditional (verified REST is valid) | n/a | n/a (Payouts; country-specific contract) | n/a | n/a | n/a | country resolves contract |
smartapps |
n/a (private kit AAR) | Android | n/a | n/a | n/a | n/a | smartapp-kind=, smartapp-ownership= |
When a product's mode cell is fixed (single value or n/a), never ask the developer about mode — just use the value or skip the question.
| Country | Site ID | Domain | Currency | Default lang |
|---|---|---|---|---|
| Argentina | MLA | www.mercadopago.com.ar |
ARS | es |
| Brazil | MLB | www.mercadopago.com.br |
BRL | pt |
| Mexico | MLM | www.mercadopago.com.mx |
MXN | es |
| Chile | MLC | www.mercadopago.cl |
CLP | es |
| Colombia | MCO | www.mercadopago.com.co |
COP | es |
| Peru | MPE | www.mercadopago.com.pe |
PEN | es |
| Uruguay | MLU | www.mercadopago.com.uy |
UYU | es |
If lang= was not provided, default to the country's default lang.
Resolve documentation in tiers. The official llms.txt per country is always fresh — fetch it first since the developer has internet and the file is a few KB. Fall back gracefully if unreachable.
| Tier | Source | Auth | When |
|---|---|---|---|
| 1 | https://www.{country_domain}/developers/llms.txt (WebFetch — official, always current) |
none | Always first — fetch using resolved country domain. If fails (403, timeout), fall to tier 2. |
| 2 | {plugin_base}/skills/mp-integrate/references/products.md (bundled) |
none | Always — product guides, API reference, code snippets, country-specific test cards. |
| 3 | mcp__plugin_mercadopago_mcp__search_documentation |
MCP OAuth | Fallback only, except SmartApps where it is mandatory — use when tiers 1–2 don't cover the combination, and always for product=smartapps. |
Country domain for tier 1:
| Country | llms.txt URL |
|---|---|
| AR (MLA) | https://www.mercadopago.com.ar/developers/llms.txt |
| BR (MLB) | https://www.mercadopago.com.br/developers/llms.txt |
| MX (MLM) | https://www.mercadopago.com.mx/developers/llms.txt |
| CO (MCO) | https://www.mercadopago.com.co/developers/llms.txt |
| CL (MLC) | https://www.mercadopago.cl/developers/llms.txt ← no .com |
| PE (MPE) | https://www.mercadopago.com.pe/developers/llms.txt |
| UY (MLU) | https://www.mercadopago.com.uy/developers/llms.txt |
Country is always resolved before Step 3. Never fetch tier 1 without a resolved country.
If tier 1 fetch fails: silently fall to tier 2 (references/products.md). Do NOT show an error or retry.
Only when tier 3 is actually needed: attempt search_documentation directly. If it is unavailable or returns an authentication error, call mcp__plugin_mercadopago_mcp__authenticate, show the OAuth link in the developer's language, and instruct them to Cmd+Click (Mac) or Ctrl+Click (Windows/Linux) without copying the URL into an external browser. When the developer returns, retry search_documentation directly. Do not call application_list as a probe.
Build 1–3 targeted queries and call mcp__plugin_mercadopago_mcp__search_documentation with each. Use language from the resolved doc language.
Query templates (use the most specific 1–3 for the chosen product/mode/sdk):
| Need | Query template |
|---|---|
| Server creation | "{product} create {mode} {sdk} {country}" (e.g., "checkout-pro create preference node argentina" or "checkout-api create order node argentina") |
| Client/UI | "{product} {client} initialization {brick?}" (e.g., "bricks react payment brick initialization") |
| Tokenization (Checkout API / Card Payment Brick) | "card token {client} {country}" |
| 3DS challenge | "3ds {product} {sdk}" |
| Webhook handling | Skip — defer to mp-webhooks skill |
| Test cards / users | Skip — defer to mp-test-setup skill |
| Marketplace splits | "marketplace split {sdk} application_fee" |
| Subscriptions plan/preapproval | "subscriptions preapproval {sdk}" |
| Payouts (legacy alias: Money Out) | "payouts money transfer {country} {sdk}" |
| Wallet Connect | "wallet connect agreements payer token orders {sdk} {country}" |
| SmartApps | `"smartapps {main |
Do not issue more than 3 queries. If a query returns generic results, refine once and stop.
If search_documentation returns a result that contains only overview or landing prose (no code blocks), do NOT fabricate code. Output exactly:
No verified snippet available for {product} / {country} / {sdk}. The MCP returned documentation for this combination but no code snippet. Review the guide manually:
https://{DOMAIN}/developers/{LANG}/docs/{product-slug}/overview
Then stop. Specifically:
CardForm hallucination) must never be presented as if it were MCP-verified.llms.txt request is tier 1, bundled references are tier 2, and MCP is tier 3. If none contains a verified snippet, report that it is unavailable.When product=smartapps, do not render the generic server/web checkout bundle
below and do not create .env credentials. Render a SmartApps-specific bundle
from references/guides/smartapps.md plus the authenticated MCP result with
these sections: commercial agreement, Android project eligibility, app kind
(main|mini), ownership (own|third-party), latest private SDK artifact,
Manifest/initialization contract, SDK-only payment flow, static validation,
development-terminal tests, and homologation. Label anything that still
depends on the private kit or terminal as blocked; never replace it with a
guessed public SDK or API call. Then continue to Step 4.5.
When product=money-out, label the bundle Payouts and render a server-only
bundle from references/guides/payouts.md plus the current country source. Do
not render the generic client/payment-form section, do not request a public key,
and do not create a checkout CTA. Include these sections: country contract,
privileged service boundary, durable trusted instruction repository, operator
authorization, audit trail, idempotency, explicit test mode, production
Ed25519 signing, resource lookup, notifications, safe automated test, and
production release controls. Use raw REST when the verified official SDK does
not expose Payouts and do not install a payment SDK merely to wrap fetch.
Render the result with this exact structure. Code blocks come from the resolved documentation tier (verbatim where possible). Do not invent payloads or endpoints.
# Mercado Pago Integration — {Product} ({Country} · {SDK} · {mode})
## 1. Install
```bash
{install command for the chosen SDK}
```
## 2. Credentials
Get your credentials from the Mercado Pago Developer Dashboard:
👉 **https://{DOMAIN}/developers/panel/app**
- Under your application, click **Credentials**.
- For **testing**: click the **{test_tab}** to get test credentials.
- For **production**: use the credentials in the **{prod_tab}** tab.
Credentials come in two valid prefixes: **`APP_USR-`** (Orders API, Checkout Pro, Point, QR; also test-user credentials from `create_test_user`) and **`TEST-`** (Checkout API, Bricks, Payments API). Both are valid and actively issued — never tell a developer to change their prefix. What matters is which tab they come from: {test_tab} = test, {prod_tab} = production.
Create `.env` from the template below (**never commit `.env`**):
```
MP_ACCESS_TOKEN=APP_USR-... # server-side, keep secret
MP_PUBLIC_KEY=APP_USR-... # client-side, can be public
MP_WEBHOOK_SECRET=... # from Dashboard → Webhooks → Signature secret
APP_URL=http://localhost:3000
```
Also ensure `.env` is in `.gitignore` (and `.env.example` is **not** ignored).
## 3. Server code
```{language}
{snippet from the resolved documentation tier — server-side creation, e.g., create order/preference/subscription/disbursement}
```
## 4. Client code (if applicable)
**Always show the total amount above the payment form** (do not bury it inside the brick):
```html
<!-- Total amount — always visible above the payment form -->
<p class="checkout-total">Total: <strong>{currency} {amount}</strong></p>
```
```{language}
{snippet from the resolved documentation tier — tokenization, brick mount, redirect, etc.}
```
**Payment feedback states — include ALL THREE in the scaffold (not as TODOs):**
```jsx
// Loading state — show while the payment is processing
{isLoading && (
<div className="checkout-loading">
<p>Processing your payment…</p>
</div>
)}
// Success state
{paymentStatus === 'approved' && (
<div className="checkout-success">
<h2>Payment approved!</h2>
<p>Order: <strong>{orderId}</strong></p>
<p>Next step: run <code>/mp-review</code> to validate your integration before going live.</p>
</div>
)}
// Error state — actionable, not the raw API error
{paymentStatus === 'error' && (
<div className="checkout-error">
<p>Payment could not be processed: {errorMessage}</p>
<p>If testing, check your test card data or try a different scenario code —
e.g. cardholder name <strong>APRO</strong> for approved, <strong>FUND</strong> for insufficient funds.</p>
</div>
)}
```
> These three blocks are **part of the default scaffold on every run** — never leave them as `{/* TODO */}` placeholders. Adapt the conditional syntax to the detected client framework (React shown; use the equivalent for vanilla-js, Vue, etc.).
## 5. Webhook receiver
> Webhook validation is handled by the `mp-webhooks` skill — invoke it next, or run `/mp-integrate webhook` to scaffold the receiver with HMAC validation.
## 6. Test
- Get test credentials and test users via the `mp-test-setup` skill (or run `/mp-integrate test-setup`).
- Test cards for the country: see `references/products.md` (AR/BR/MX/CO/CL) or query MCP for others.
- After your first successful test payment → run `/mp-review` (**step 6 of 7 — MANDATORY before production**).
## 7. Docs (country-specific)
- Product guide: https://{DOMAIN}/developers/{LANG}/docs/{product-slug}/overview (fallback: /landing)
- API reference: https://{DOMAIN}/developers/{LANG}/reference
## 8. Gotchas
{render the gotchas for the chosen product from the Gotchas Bank below}
| SDK | Install command |
|---|---|
| node | npm install mercadopago |
| python | pip install mercadopago |
| java | Maven: com.mercadopago:sdk-java / Gradle equivalent |
| php | composer require mercadopago/dx-php |
| ruby | gem install mercadopago-sdk |
| dotnet | dotnet add package MercadoPago |
| go | go get github.com/mercadopago/sdk-go |
| react (client) | npm install @mercadopago/sdk-react |
| vanilla-js (client) | <script src="https://sdk.mercadopago.com/js/v2"></script> |
| ios | SPM: https://github.com/mercadopago/sdk-ios |
| android | Gradle: com.mercadopago:sdk |
⚠️ MANDATORY — bundle must be visible to the user before this step.
The full bundle from Step 4 MUST appear in the chat as rendered markdown output BEFORE this AskUserQuestion call — every time, on every run, even if references were already loaded in a previous turn of the same session. Never skip the render. Never say "referências já carregadas" or equivalent and jump here directly. If the bundle is not visibly rendered in the current response, render it now before proceeding.
Immediately after rendering the bundle, before listing next steps, call AskUserQuestion with:
header="Scaffold files""Do you want me to write these files to your project now?""Yes, write the files" → execute the scaffold below"No, just the code" → skip to Step 5If the developer chooses to scaffold, execute this sequence (in order — each step depends on the previous):
Install or update the SDK only with authorization — query the official registry and apply LOCK 1. If a change is needed, ask explicit authorization with the exact stable version before running npm install mercadopago@latest (or the equivalent stable-release command for the detected SDK) in the directory that contains the server-side manifest. Never select a prerelease. Update the lockfile, adapt incompatible integration code, run relevant tests, and stop on a non-zero exit. If the current dependency already resolves to the registry's stable release, do not mutate it; report the verified version.
Write the server snippet — create or edit the server file (e.g., backend/index.js, backend/src/routes/mercadopago.js) inserting the snippet from Step 4. If the file already exists, inject the new route after existing routes rather than overwriting.
When product=point: run the Point server acceptance check immediately after writing the server integration. Fix every failure before continuing or reporting success:
node "${CLAUDE_PLUGIN_ROOT}/scripts/validate-point-server.mjs" "{server_file}"
When product=qr: run the QR server acceptance check immediately after writing the server integration. After wiring the client in the application's real charge CTA, run the client acceptance check as well. Fix every failure before continuing or reporting success:
node "${CLAUDE_PLUGIN_ROOT}/scripts/validate-qr-server.mjs" "{server_file}"
node "${CLAUDE_PLUGIN_ROOT}/scripts/validate-qr-client.mjs" "{client_file}" 'data-mp-qr-cta="create-order"' "/api/qr/orders"
When product=bricks: apply LOCK 9 and run the application-wide validator
after the dedicated Brick page, server route (when applicable), runtime public
configuration, and CTA wiring have all been written:
node "${CLAUDE_PLUGIN_ROOT}/scripts/validate-bricks-integration.mjs" . "{brick}"
When product=subscriptions: apply LOCK 10 after the subscription CTA,
signup page, tokenization (when authorized), server route, and lifecycle routes
have been written:
node "${CLAUDE_PLUGIN_ROOT}/scripts/validate-subscriptions-integration.mjs" . "{subscription-model}"
When product=marketplace: apply LOCK 11 after seller OAuth,
encrypted persistence/refresh, the selected checkout contract, and both the
seller-connect and buyer-checkout CTAs have been written:
node "${CLAUDE_PLUGIN_ROOT}/scripts/validate-marketplace-integration.mjs" . "{marketplace-checkout}"
When product=wallet-connect: apply LOCK 12 after the dedicated page,
checkout CTA wiring, account-linking routes, encrypted payer-token storage,
and Orders API routes have been written:
node "${CLAUDE_PLUGIN_ROOT}/scripts/validate-wallet-connect-integration.mjs" .
When product=smartapps: apply LOCK 13 after the Android Manifest,
application initialization, and SDK payment flow have been written. Run the
validator with the resolved app kind and ownership. Do not report the AAR as
current or the build as passing unless the real latest kit artifact was
supplied and compiled successfully:
node "${CLAUDE_PLUGIN_ROOT}/scripts/validate-smartapps-integration.mjs" . "{main|mini}" "{own|third-party}"
When product=money-out: apply LOCK 14 after the privileged service,
durable instruction repository, authorization/audit controls, resolved
country contract, explicit test mode, production signing, and lookup routes
have been written:
node "${CLAUDE_PLUGIN_ROOT}/scripts/validate-payouts-integration.mjs" . "{AR|BR}"
2.5. checkout-pro and checkout-api — Mandatory checkout CTA discovery (skip for all other products):
This step is unconditional for both checkout products. The scaffold is incomplete until a concrete CTA target has been resolved. The products use the same detector but different wiring in Step 3.5:
checkout-pro: place a visible Pay with Mercado Pago button at the resolved CTA location; it submits to the preference-creation route and redirects to init_point.checkout-api: link the resolved CTA to the new, separate checkout screen.Reuse the LOCK 5 result. If it is unavailable for any reason, run the bundled resolver from the project root exactly once:
node "${CLAUDE_PLUGIN_ROOT}/scripts/resolve-checkout-cta.mjs" "{product}" .
First replace {product} with the normalized internal value returned by LOCK 5. The resolver scans HTML and common web templates/components (JSX, TSX, Vue, Svelte, Astro, PHP, ERB, EJS, Handlebars, Twig, JavaScript, and TypeScript). It scores semantic evidence from visible text, attributes, and the actual click/navigation handler; it contains no application-specific selectors.
Resolve the target:
form-checkout, type="submit", mp-pay-btn) — that button submits payment; it is not the link into the form.onclick, onClick, href, or addEventListener before changing anything.status=selected, use that CTA and report {file}:{line}. This result is mandatory; do not downgrade it to “not found”.status=ambiguous, ask via AskUserQuestion which candidate is the checkout CTA (maximum four candidates). A target must be selected before scaffolding continues.status=not_found, inspect the application's actual cart/order/product entry screens and ask via AskUserQuestion where the new checkout CTA should be inserted (maximum four concrete file/location choices). After the developer chooses, set cta_status=create and use that exact location.BLOCKED: checkout CTA target required. Never finish the scaffold, silently omit the CTA, or report success.Store {cta_file}, {cta_line_or_region}, {cta_selector}, {cta_status}, and any existing handler for Step 3.5. Do not edit it yet; the server route and, for Checkout API, the new checkout screen must exist first.
checkout-api only — Always create a separate checkout screen in a new file — generate the client form from Step 4 using the project's architecture. For checkout-pro, skip directly to Step 3.5; Checkout Pro redirects to Mercado Pago and must not create a local payment-form screen.
This is unconditional for Checkout API: the screen is created after Step 2.5 has resolved where its entry CTA will live.
Separation rule: never place the generated payment form inside an existing cart, product, drawer, modal, accordion, tab, or conditionally hidden section. Never append the form markup to an existing screen file. Shared layouts, styles, and components may be imported or reused, but the checkout screen itself must be owned by its new file and opened through its own route/URL/navigation destination.
Reuse the project's naming and route conventions. Record:
{checkout_screen_file} — the new file created for the screen;{checkout_screen_destination} — its route, URL, or navigation name;{checkout_screen_invocation} — the framework-appropriate code needed to open it.Do not link anything to the destination until the new file exists and the route/navigation registration has been verified.
Checkout API public-key delivery — mandatory and application-agnostic:
%MP_PUBLIC_KEY% or another text-replacement token in generated client files. Never depend on rewriting the checkout HTML response: browsers, CDNs, service workers, and static hosts can retain a stale document containing the literal token.MP_PUBLIC_KEY on the server, return { publicKey }, send Cache-Control: no-store, max-age=0, and return a non-2xx response with a clear error when the variable is missing. The checkout screen must request that endpoint with cache: 'no-store' before constructing MercadoPago.MP_ACCESS_TOKEN or any other private credential.data-mp-public-key-source="runtime-endpoint" or data-mp-public-key-source="framework-public-config", matching the strategy actually used.Checkout API secure-field integrity — mandatory and application-agnostic:
Build the smallest valid form. The always-visible card inputs are cardNumber, expirationDate, securityCode, and cardholderName.
Payer email and identification are required payment data, but they are not automatically required visible inputs. Reuse trusted values already available from the authenticated buyer/session/cart. Only render their inputs when the application does not have those values, and mark the selected strategy on the form with data-mp-payer-email-source="form|application" and data-mp-payer-identification-source="form|application".
The SDK JS CardForm map requires issuer, installments, and identificationType even when the product UX does not show those controls. Always render exactly one <select> for each, keep it inside the form, mark it with data-mp-sdk-required-field="issuer|installments|identificationType", and reference its exact ID in mp.cardForm({ form: ... }). Omitting any of the three is a scaffold failure because the SDK populates them during its payment-method lifecycle and can leave the secure iframe fields unresponsive when their DOM targets do not exist.
When one of those three controls is not part of the visible UX, use a real hidden lifecycle node: <select hidden aria-hidden="true" tabindex="-1">. Do not use disabled, because disabled controls cannot participate in form/SDK state. These hidden selects are SDK plumbing, not payment data trusted by the backend.
Derive the identification type from the resolved country and buyer context. For example, an individual buyer in Brazil uses CPF. Keep the required identificationType lifecycle select hidden when the type is known; make it a labeled visible selector only when the application genuinely supports multiple types and cannot infer the correct one.
Keep the required issuer lifecycle select hidden by default. Make it a labeled visible selector only if the payment-method metadata reports additional_info_needed containing issuer_id; do not send issuer_id inside Orders API payment_method.
Keep the required installments lifecycle select hidden for the minimal one-time flow and enforce installments: 1 on the server. Make it a labeled visible selector only when the developer explicitly wants to offer installments. Never trust the hidden browser value instead of the server rule.
Every field registered under mp.cardForm({ form: ... }) must have exactly one matching element in the DOM before mp.cardForm(...) runs. Never configure an optional field after choosing to source it from application state or omit it from the UI.
The form ID in form.id must exactly match the rendered <form id="...">.
Render a persistent visible label for every field, localized to the project's language. Placeholders such as MM/AA and CVC are hints, not labels, and may not render inside secure iframes.
For iframe fields (cardNumber, expirationDate, securityCode), keep the SDK host <div> empty and interactive. Never add disabled, readonly, pointer-events: none, or an overlapping decorative element to the host or its iframe.
Give each secure host a non-zero height and position: relative; make the injected iframe display: block, width: 100%, and height: 100%. The visible border belongs to the host, not to an overlay.
Mount secure fields only after the new checkout screen route is visible and the host has non-zero dimensions. Use the application's lifecycle/router hook or requestAnimationFrame; never initialize into display: none, and never use an arbitrary setTimeout as the visibility mechanism.
Mount exactly once per visible form instance. In SPAs, unmount/destroy the previous SDK controller or field instances before remounting.
Group each secure host with an external visible label and an accessible relationship, for example:
<div class="checkout-field" role="group" aria-labelledby="expiration-label">
<span id="expiration-label" class="checkout-label">Validade do cartão (MM/AA)</span>
<div id="form-checkout__expirationDate" class="secure-input"></div>
</div>
Only disable the payment submit button while fetching or submitting. Never disable card-data fields as part of loading state management.
In onFormMounted, verify that every secure host contains exactly one iframe, has non-zero dimensions, has a visible external label, and that neither host nor iframe resolves to pointer-events: none. Surface failures both in the console and in a visible form error; do not report the scaffold as successful.
Before continuing, compare the registered field IDs with the rendered IDs in both directions. Then inspect the generated source for disabled, readonly, aria-disabled, inert, overlays, and pointer-events affecting secure hosts or their ancestors. Missing labels, hidden mounting, duplicated instances, and non-interactive hosts are scaffold failures and must be fixed immediately.
Mark every visible field wrapper with data-mp-field="{fieldName}"; mark the three SDK iframe hosts with data-mp-secure-field="cardNumber|expirationDate|securityCode"; mark the three required CardForm lifecycle selects with data-mp-sdk-required-field="issuer|installments|identificationType". The form must declare whether payer email and identification come from the form or application state using the source markers above. After writing the new screen, run the deterministic acceptance check:
# runtime-endpoint strategy: pass the file that implements the config route
node "${CLAUDE_PLUGIN_ROOT}/scripts/validate-checkout-screen.mjs" "{checkout_screen_file}" "{server_or_config_route_file}" "{cta_file}"
# framework-public-config strategy: no server config file is needed
node "${CLAUDE_PLUGIN_ROOT}/scripts/validate-checkout-screen.mjs" "{checkout_screen_file}" "" "{cta_file}"
If it fails, fix the new screen and rerun it. Never show a successful scaffold summary until this command exits with code 0.
3.5. checkout-pro and checkout-api — Always wire the resolved CTA:
A resolved CTA is mandatory. Preserve the surrounding layout and reuse the project's button classes and accessibility conventions. Mark the final element with data-mp-checkout-cta="{product}" so the deterministic check can verify the integration.
When product=checkout-api: preserve the existing CTA's visible text and styling, then replace only its navigation behavior so it opens {checkout_screen_destination}.
<a>: add data-mp-checkout-cta="checkout-api" and set or update href="{checkout_screen_destination}".<button>: add data-mp-checkout-cta="checkout-api" and replace its existing checkout handler with exactly one window.location.assign('{checkout_screen_destination}') action.data-mp-checkout-cta="checkout-api" and use the existing router navigation API. Do not introduce window.location when the application already uses client-side routing.cta_status=create, insert one project-styled button/link at the exact location selected in Step 2.5 and wire it to the new screen.When product=checkout-pro: place a visible button labeled Pay with Mercado Pago (localized to the application language) at the resolved location. The button must start preference creation and redirect to the returned init_point; it must not open a local card form.
Server-rendered/static app: replace the chosen CTA, or insert at the chosen region, with a form that posts to the preference route:
<form action="{preference_route}" method="POST">
<button type="submit" data-mp-checkout-cta="checkout-pro" class="{existing_button_classes}">
Pagar com Mercado Pago
</button>
</form>
SPA/framework app: keep one visible project-styled button with data-mp-checkout-cta="checkout-pro"; its single handler must call the backend preference route and navigate to the returned init_point. Remove the old checkout handler instead of stacking a second listener.
Never create a second checkout page for Checkout Pro. The chosen CTA location is where the Mercado Pago button belongs.
Mandatory verification after editing:
Confirm exactly one final element has data-mp-checkout-cta="{product}".
For Checkout API, confirm {checkout_screen_file} is separate, {checkout_screen_destination} resolves to it, and the CTA has exactly one navigation action to that destination.
For Checkout Pro, confirm the visible button says Mercado Pago and reaches the preference-creation route that redirects to init_point.
Confirm the old CTA handler is gone and clicking cannot trigger two checkout flows.
For Checkout API, confirm the payment form's own submit button was not mistaken for or rewired as the entry CTA.
Run the deterministic CTA acceptance check and fix any failure before continuing:
node "${CLAUDE_PLUGIN_ROOT}/scripts/validate-checkout-cta.mjs" "{product}" "{cta_file}" "{checkout_screen_destination_or_preference_route}"
For Checkout Pro, also run the server validator. It rejects unconditional auto_return when the application has a localhost fallback:
node "${CLAUDE_PLUGIN_ROOT}/scripts/validate-checkout-pro-server.mjs" "{server_file}"
Report ✓ {cta_file}:{cta_line_or_region} → {checkout_screen_destination_or_preference_route}. There is no successful “CTA not linked” outcome for Checkout Pro or Checkout API.
Create .env.example — write the template vars (MP_ACCESS_TOKEN, MP_PUBLIC_KEY, MP_WEBHOOK_SECRET, APP_URL) to .env.example. Only create .env with real values if the developer explicitly selected credential import and get_credentials succeeded; do not overwrite an existing .env without confirmation. Otherwise, never create .env — the developer must fill in their own credentials.
Update .gitignore — add .env, .env.*.local, .mp-integrate-progress.md if not already present.
5.5. Delete .mp-integrate-progress.md after successful scaffolding — this file is only a crash/cancel resume checkpoint. Remove it before running the final product validator and before printing a success summary. Keep it only when the run is canceled, blocked, or failed. Never leave a completed integration with this file present.
After all writes, print the product-specific summary. Both successful outcomes must include a wired CTA:
Checkout API:
✓ npm install mercadopago — OK
✓ {server_file} — Checkout API route added
✓ {checkout_screen_file} — separate checkout screen created
✓ MP_PUBLIC_KEY — loaded through {detected_config_strategy}; no HTML placeholder
✓ {cta_file}:{line} {cta_selector} → {checkout_screen_destination} → {checkout_screen_file}
✓ .env.example — created (fill in your credentials)
✓ .gitignore — updated
Checkout Pro:
✓ npm install mercadopago — OK
✓ {server_file} — preference route added
✓ {cta_file}:{line} — Pay with Mercado Pago button → {preference_route}
✓ .env.example — created (fill in your credentials)
✓ .gitignore — updated
Scaffold guardrails:
get_credentials: do not overwrite the confirmed .env; only create .env.example with placeholders..env.example with APP_USR-... placeholders. Never create .env here.+diff-style preview of what changed.%MP_PUBLIC_KEY%, .replace(...), template-token substitution, or an inline hard-coded public key. Use the detected framework's public configuration convention, or a no-store JSON runtime-config endpoint for vanilla/server applications.Always close with:
Run /mp-integrate webhook to add the webhook receiver (HMAC validation included).
Run /mp-integrate test-setup to create a test user and load funds.
2.5. For Orders API products (checkout-api / qr / point — ALL countries): Ask via AskUserQuestion before listing next steps:
"Yes, create test user now" → invoke mp-test-setup skill inline; "No, I'll do it later" → show reminder: "⚠️ Run /mp-integrate test-setup before testing — Orders API returns 422 without a test user."Run /mp-review — MANDATORY before going to production. This is step 6 of 7 in your integration journey. The auto-checker validates your integration automatically after the first payment. Do not switch to production credentials (step 7) until /mp-review passes.
You are at step 6 of 7. After
/mp-reviewpasses, the only remaining step is switching to production credentials.
Render only the section that matches the chosen product. These are the experiential traps that the docs do not surface clearly. Keep them short.
init_point, never sandbox_init_point. Mercado Pago has no sandbox — there is only the production API. Test runs use test-user credentials (APP_USR-), not a different URL.currency_id must match the country (ARS, BRL, MXN, CLP, COP, PEN, UYU).back_url query params alone — always re-fetch payment status server-side.auto_return=approved requires back_urls.success set; otherwise it is silently ignored.external_reference is your reconciliation anchor — set it on every preference/order.422 unprocessable_content if you use an arbitrary email. Run /mp-integrate test-setup before testing. This applies to ALL countries.getCardFormData() returns camelCase — paymentMethodId and issuerId, not payment_method_id and issuer_id. Map them on the server.issuer_id is NOT allowed inside payment_method for Orders API — remove it from the payload or you get additionalProperties not allowed.issuer, installments, and identificationType selects in the DOM/CardForm map but hidden from the minimal UI; enforce installments: 1 server-side unless the merchant explicitly offers installments.total_amount and amount must be "10.00" not "10" — use Number(x).toFixed(2).card-payment and payment create via Payments API; wallet creates a dynamic preference at /checkout/preferences (without v1); status-screen only displays an existing paymentId.<p>Total: <strong>{currency} {amount}</strong></p> above the container div.onSubmit runs. (2) Success state showing payment ID and "Payment approved" message. (3) Error state with an actionable message ("Card declined — try a different card"), not the raw API error string. Missing these states means buyers don't know if the payment went through.<div id="..."></div> must exist in the DOM before calling bricksBuilder.create(...). A setTimeout is not a fix; use onReady or React useEffect with the ref mounted.onSubmit must return a Promise that resolves after the server responds — returning void makes the brick stay in the loading state forever.sdk.mercadopago.com → the brick raises FIELDS_SETUP_FAILED and silently fails to mount. If a developer reports "the brick doesn't appear", check the ad-blocker before debugging code.installments: 1 for debit and does not require the selector field to be present.preferenceId as a placeholder (e.g., <PREFERENCE_ID>, YOUR_PREFERENCE_ID, "preference_id"): the brick fails silently. The preferenceId must always be created dynamically on the server per buyer session./checkout/preferences.payment_id — extract it from the POST /v1/payments response (response.id) and pass it to the brick. Do not pass an order ID.bricksBuilder.create() and call controller.unmount() before rebuilding or removing its container. The React SDK component owns its own controller lifecycle; do not create a second controller around it.back_urls must be on the same origin as the page that mounts the brick. Cross-domain back_urls fail silently — the redirect after payment lands on a blank page with no error.type: "qr"; legacy /instore/... routes and QR-encoded Checkout redirect URLs are scaffold failures.config.qr.external_pos_id must exactly match the POS external_id and belong to the seller whose token creates the order.static, dynamic, and hybrid. Only dynamic and hybrid return type_response.qr_data; static uses the QR returned by POS creation.created, processed, canceled, expired, and refunded explicitly.orders topic. A real processed/refund test still requires scanning with the buyer test account; do not invent the Point /events simulator for QR.type: "point" and config.point.terminal_id; never scaffold /point/integration-api/.../payment-intents, type: "instore", or config.device.id.NEWLAND_N950__SBX0000001 only behind explicit test mode and simulate each order result through /v1/orders/{order_id}/events. It is not valid for integration-quality measurement.orders. The legacy point_integration_wh topic belongs to the old Point Integration API — do not use it for new integrations.with-plan, without-plan-authorized, or without-plan-pending before scaffolding. A preapproval created without a plan cannot be migrated to one later.init_point.authorized, pending, paused, and canceled explicitly and reconcile through GET/webhooks.back_url must be HTTPS in production; HTTP is only acceptable for a local-development fallback.state, the exact configured redirect URI, encrypted persistent tokens, and atomic refresh-token rotation. Never expose or log seller tokens.seller_id, collector_id, amount, or fee from the buyer request.marketplace_fee on /checkout/preferences; Checkout API uses application_fee on /v1/payments. The seller OAuth token in the Authorization header determines the receiving seller; do not invent collector_id in the payment payload.disbursements contract or substitute Advanced Payments.mp-webhooks skill (or /mp-integrate webhook).mp-test-setup skill (or /mp-integrate test-setup).mp-review skill (or /mp-review).llms.txt per country (tier 1), references/products.md (tier 2), or MCP search_documentation (tier 3 fallback). Never from training-data memory alone.原文・著作権は Anthropic および各プラグイン作者に帰属します。日本語訳は Claude API による自動翻訳です。