```
├── .github/
├── CODEOWNERS (100 tokens)
├── PULL_REQUEST_TEMPLATE/
├── admin.md (300 tokens)
├── minor-improvement.md (600 tokens)
├── release.md (200 tokens)
├── sep-proposal.md (700 tokens)
├── scripts/
├── validate-pr-description.js (1400 tokens)
├── workflows/
├── main.yml (200 tokens)
├── stale-reminder.yml (300 tokens)
├── validate-consistency.yml (100 tokens)
├── validate-pr-description.yml (100 tokens)
├── .gitignore
├── .vscode/
├── settings.json
├── CODE_OF_CONDUCT.md (1100 tokens)
├── CONTRIBUTING.md (1700 tokens)
├── LICENSE (omitted)
├── MAINTAINERS.md
├── NOTICE (100 tokens)
├── README.md (1700 tokens)
├── changelog/
├── 2025-09-29.md (100 tokens)
├── 2025-12-12.md (900 tokens)
├── 2026-01-16.md (200 tokens)
├── 2026-01-30.md (1000 tokens)
├── 2026-04-17.md (6.2k tokens)
├── unreleased/
├── .gitkeep
├── add-feed-update-id.md (100 tokens)
├── add-meta-tsc-member.md (100 tokens)
├── add-upsert-products-response-schema.md (300 tokens)
├── document-intervention-required-error-code.md (100 tokens)
├── fix-address-company-description.md (100 tokens)
├── fix-delegate-payment-error-examples.md (200 tokens)
├── fix-message-type-examples.md (200 tokens)
├── fix-refund-amount-example-type.md (100 tokens)
├── fulfillment-details-on-complete.md (100 tokens)
├── intent-traces-examples.md (100 tokens)
├── order-schema-alignment.md (800 tokens)
├── stale-pr-reminder.md (200 tokens)
├── suggested-pricing.md (200 tokens)
├── docs/
├── governance.md (4.2k tokens)
├── mcp-binding.md (2.5k tokens)
├── operating-model.md (900 tokens)
├── principles-mission.md (400 tokens)
├── sep-cart-capability.md (1700 tokens)
├── sep-guidelines.md (2000 tokens)
├── sep-markdown-specification.md (2.6k tokens)
├── examples/
├── 2025-09-29/
├── examples.agentic_checkout.json (2.5k tokens)
├── examples.delegate_payment.json (400 tokens)
├── 2025-12-12/
├── examples.agentic_checkout.json (3.6k tokens)
├── examples.delegate_payment.json (400 tokens)
├── 2026-01-16/
├── examples.agentic_checkout.json (4.8k tokens)
├── examples.capability_negotiation.json (2.1k tokens)
├── examples.delegate_payment.json (400 tokens)
├── 2026-01-30/
├── discount-extension/
├── README.md (800 tokens)
├── automatic-discount.json (500 tokens)
├── order-level-discount.json (500 tokens)
├── percentage-discount-with-allocations.json (600 tokens)
├── rejected-discount-code.json (500 tokens)
├── stacked-discounts.json (800 tokens)
├── examples.agentic_checkout.json (6.2k tokens)
├── examples.delegate_payment.json (400 tokens)
├── 2026-04-17/
├── discount-extension/
├── README.md (800 tokens)
├── automatic-discount.json (500 tokens)
├── order-level-discount.json (500 tokens)
├── percentage-discount-with-allocations.json (600 tokens)
├── rejected-discount-code.json (600 tokens)
├── stacked-discounts.json (800 tokens)
├── examples.agentic_checkout.json (8.3k tokens)
├── examples.delegate_authentication.json (1500 tokens)
├── examples.delegate_payment.json (500 tokens)
├── examples.feed.json (600 tokens)
├── examples.mcp.agentic_checkout.json (2.4k tokens)
├── examples.multi_item_checkout.json (1000 tokens)
├── orders/
├── digital-fulfillment.json (400 tokens)
├── partial-fulfillment.json (500 tokens)
├── refunded-order.json (500 tokens)
├── shipped-order.json (700 tokens)
├── simple-order.json (100 tokens)
├── discount-extension/
├── README.md (800 tokens)
├── automatic-discount.json (500 tokens)
├── order-level-discount.json (500 tokens)
├── percentage-discount-with-allocations.json (600 tokens)
├── rejected-discount-code.json (600 tokens)
├── stacked-discounts.json (800 tokens)
├── orders/
├── digital-fulfillment.json (400 tokens)
├── partial-fulfillment.json (500 tokens)
├── refunded-order.json (500 tokens)
├── shipped-order.json (700 tokens)
├── simple-order.json (100 tokens)
├── unreleased/
├── examples.agentic_checkout.json (8.4k tokens)
├── examples.delegate_authentication.json (1500 tokens)
├── examples.delegate_payment.json (500 tokens)
├── examples.feed.json (600 tokens)
├── examples.intent_traces.json (700 tokens)
├── examples.mcp.agentic_checkout.json (2.4k tokens)
├── examples.multi_item_checkout.json (1000 tokens)
├── legal/
├── cla/
├── CORPORATE.md (1400 tokens)
├── CORPORATE_PROCESS.md (2.5k tokens)
├── INDIVIDUAL.md (1300 tokens)
├── INDIVIDUAL_PROCESS.md (2.6k tokens)
├── SIGNATORIES.md (500 tokens)
├── package.json (200 tokens)
├── pnpm-lock.yaml (omitted)
├── rfcs/
├── rfc.affiliate_attribution.md (3.6k tokens)
├── rfc.agentic_checkout.md (6.2k tokens)
├── rfc.capability_negotiation.md (4.7k tokens)
├── rfc.cart.md (3.4k tokens)
├── rfc.delegate_authentication.md (3.8k tokens)
├── rfc.delegate_payment.md (3k tokens)
├── rfc.discount_extension.md (3.2k tokens)
├── rfc.discovery.md (4.1k tokens)
├── rfc.extensions.md (2.4k tokens)
├── rfc.intent_traces.md (2.2k tokens)
├── rfc.marketing_consent.md (3k tokens)
├── rfc.orders.md (3.9k tokens)
├── rfc.payment_handlers.md (7k tokens)
├── rfc.product_feeds.md (5.4k tokens)
├── rfc.seller_backed_payment_handler.md (6.3k tokens)
├── scripts/
├── README.md (800 tokens)
├── pre-commit-hook.sh (100 tokens)
├── setup.sh (300 tokens)
├── validate-consistency.js (4.6k tokens)
├── spec/
├── 2025-09-29/
├── json-schema/
├── schema.agentic_checkout.json (2.3k tokens)
├── schema.delegate_payment.json (1300 tokens)
├── openapi/
├── openapi.agentic_checkout.yaml (3.6k tokens)
├── openapi.agentic_checkout_webhook.yaml (900 tokens)
├── openapi.delegate_payment.yaml (2.6k tokens)
├── 2025-12-12/
├── json-schema/
├── schema.agentic_checkout.json (6.2k tokens)
├── schema.delegate_payment.json (1300 tokens)
├── openapi/
├── openapi.agentic_checkout.yaml (7.2k tokens)
├── openapi.agentic_checkout_webhook.yaml (900 tokens)
├── openapi.delegate_payment.yaml (2.6k tokens)
├── 2026-01-16/
├── json-schema/
├── schema.agentic_checkout.json (5k tokens)
├── schema.delegate_payment.json (1300 tokens)
├── openapi/
├── openapi.agentic_checkout.yaml (6.2k tokens)
├── openapi.agentic_checkout_webhook.yaml (900 tokens)
├── openapi.delegate_payment.yaml (2.6k tokens)
├── 2026-01-30/
├── json-schema/
├── schema.agentic_checkout.json (18.3k tokens)
├── schema.delegate_payment.json (2.4k tokens)
├── schema.discount.json (1900 tokens)
├── schema.extension.json (1000 tokens)
├── openapi/
├── openapi.agentic_checkout.yaml (19.2k tokens)
├── openapi.agentic_checkout_webhook.yaml (1400 tokens)
├── openapi.delegate_payment.yaml (3.8k tokens)
├── 2026-04-17/
├── json-schema/
├── schema.agentic_checkout.json (24.9k tokens)
├── schema.cart.json (1000 tokens)
├── schema.delegate_authentication.json (4.1k tokens)
├── schema.delegate_payment.json (2.7k tokens)
├── schema.discount.json (2.5k tokens)
├── schema.extension.json (1400 tokens)
├── schema.feed.json (3.8k tokens)
├── openapi/
├── openapi.agentic_checkout.yaml (22.7k tokens)
├── openapi.agentic_checkout_webhook.yaml (2.2k tokens)
├── openapi.cart.yaml (2.2k tokens)
├── openapi.delegate_authentication.yaml (6.2k tokens)
├── openapi.delegate_payment.yaml (4.3k tokens)
├── openapi.feed.yaml (4.7k tokens)
├── openrpc/
├── openrpc.agentic_checkout.json (1600 tokens)
├── unreleased/
├── json-schema/
├── schema.agentic_checkout.json (25.6k tokens)
├── schema.cart.json (1000 tokens)
├── schema.delegate_authentication.json (4.1k tokens)
├── schema.delegate_payment.json (2.7k tokens)
├── schema.discount.json (2.5k tokens)
├── schema.extension.json (1400 tokens)
├── schema.feed.json (4.1k tokens)
├── openapi/
├── openapi.agentic_checkout.yaml (23.3k tokens)
├── openapi.agentic_checkout_webhook.yaml (2.2k tokens)
├── openapi.cart.yaml (2.2k tokens)
├── openapi.delegate_authentication.yaml (6.2k tokens)
├── openapi.delegate_payment.yaml (4.2k tokens)
├── openapi.feed.yaml (4.8k tokens)
├── openrpc/
├── openrpc.agentic_checkout.json (1600 tokens)
```
## /.github/CODEOWNERS
```github/CODEOWNERS path="/.github/CODEOWNERS"
/.github/CODEOWNERS @agentic-commerce-protocol/founding-maintainers
/CONTRIBUTING.md @agentic-commerce-protocol/founding-maintainers
/CODE_OF_CONDUCT.md @agentic-commerce-protocol/founding-maintainers
/MAINTAINERS.md @agentic-commerce-protocol/founding-maintainers
/NOTICE @agentic-commerce-protocol/founding-maintainers
/LICENSE @agentic-commerce-protocol/founding-maintainers
/docs/ @agentic-commerce-protocol/founding-maintainers
/legal/ @agentic-commerce-protocol/founding-maintainers
```
## /.github/PULL_REQUEST_TEMPLATE/admin.md
<!--
This template is for Administrative changes by admins.
Use this for:
- Adding newly signed Corporate CLA parties to SIGNATORIES.md
- Updating authorized contributor lists (Corporate CLA Schedule A changes)
- Other corporate/administrative housekeeping
This template requires the PR title to start with "ADMIN:".
Only admins should use this template.
-->
# ADMIN: [Short Description of Admin Action]
## 🔑 Admin Action
<!-- Check the type of admin action -->
- [ ] New Corporate CLA signatory (add to SIGNATORIES.md)
- [ ] Schedule A update (add/remove authorized contributors for existing Corporate CLA)
- [ ] Other administrative change: [describe]
---
## 📝 Summary
<!-- Brief description of the administrative change being made. -->
---
## 🔗 Reference
<!-- Link to the Corporate CLA issue, Schedule A update comment, or other request that prompted this change. -->
Related: #[issue or discussion number]
---
## ✅ Admin Checklist
- [ ] I am an admin or authorized representative
- [ ] The Corporate CLA issue has been reviewed and the signatory's authority verified
- [ ] GitHub usernames in Schedule A have been validated as real accounts
- [ ] SIGNATORIES.md is updated to reflect this change
- [ ] CLA Assistant allowlist is updated (add/remove usernames at https://cla-assistant.io/)
---
**Process**: Admin PRs require approval from another admin. See [governance.md](../../docs/governance.md) and [CORPORATE_PROCESS.md](../../legal/cla/CORPORATE_PROCESS.md) for the full maintainer workflow.
## /.github/PULL_REQUEST_TEMPLATE/minor-improvement.md
<!--
This template is for Minor Changes that do NOT require a SEP.
Use this for:
- Documentation fixes or editorial clarifications
- Simple bugfixes
- Minor enum or data changes to support additional participants
- Tooling improvements
- Typo corrections
- Example updates
If your change is substantial, complex, or controversial, use the SEP template instead.
See docs/governance.md for guidance on what requires a SEP.
-->
# [Short Descriptive Title]
## 🔧 Type of Change
<!-- Check all that apply -->
- [ ] Documentation fix/improvement
- [ ] Bug fix (non-breaking)
- [ ] Tooling improvement
- [ ] Example update
- [ ] Minor data/enum addition
- [ ] Other: [describe]
---
## 📝 Description
<!--
Clear and concise description of what this PR does.
What problem does it solve or what does it improve?
-->
---
## 🎯 Motivation and Context
<!--
Why is this change needed?
What issue does it address?
Link to any related issues or discussions.
-->
Fixes/Addresses: #[issue number]
---
## 🧪 Testing
<!--
How has this been tested?
For bug fixes: How do you verify the bug is fixed?
For examples: Have you validated the JSON/YAML against schemas?
-->
---
## 📸 Screenshots / Examples
<!--
If applicable, add screenshots or code examples showing:
- Before/after for documentation changes
- Example output for tooling changes
- Sample requests/responses for API changes
-->
---
## ✅ Checklist
Before submitting, ensure:
- [ ] I have signed the [Contributor License Agreement (CLA)](../legal/cla/INDIVIDUAL.md)
- [ ] My change follows the project's code style and conventions
- [ ] I have updated relevant documentation (if applicable)
- [ ] I have added/updated examples (if applicable)
- [ ] I have added a changelog entry file to `changelog/unreleased/your-change-description.md`
- [ ] I have tested my changes locally
- [ ] This change does NOT require a SEP (it's minor/non-breaking)
- [ ] All CI checks pass
---
## 🔍 Scope Verification
<!--
Please confirm this change is truly minor and doesn't require a SEP.
If ANY of these are true, you should use the SEP template instead:
-->
- [ ] ❌ This adds/removes/modifies protocol features
- [ ] ❌ This introduces breaking changes
- [ ] ❌ This changes governance or processes
- [ ] ❌ This is complex or controversial
- [ ] ✅ **This is a minor, straightforward change** (confirm by checking this)
---
## 📚 Additional Notes
<!--
Any other information reviewers should know:
- Dependencies
- Follow-up work needed
- Open questions
-->
---
**Review Process**: Minor changes require approval from a Steward (may be from the same organization for efficiency). See [governance.md](../docs/governance.md) for details.
## /.github/PULL_REQUEST_TEMPLATE/release.md
<!--
This template is for cutting a new spec release (admins only).
Use this for:
- Promoting unreleased specs, examples, and changelog entries to a dated version
This template requires the PR title to start with "RELEASE:".
-->
# RELEASE: [Version Date, e.g. 2026-02-19]
## 📦 Release Summary
<!-- Brief overview of what this release includes. -->
---
## 🔗 Included Changes
<!-- List the changelog entries being promoted from changelog/unreleased/. -->
- [ ] `changelog/unreleased/...`
---
## ✅ Release Checklist
- [ ] Unreleased changelog entries combined into `changelog/YYYY-MM-DD.md`
- [ ] Individual `changelog/unreleased/` entry files removed
- [ ] Specs promoted from `spec/unreleased/` to `spec/YYYY-MM-DD/`
- [ ] Examples promoted from `examples/unreleased/` to `examples/YYYY-MM-DD/`
- [ ] Version references updated across specs and schemas
- [ ] Previous version marked as deprecated in changelog (if applicable)
---
**Process**: Release PRs require approval from another admin. See [governance.md](../../docs/governance.md) for details.
## /.github/PULL_REQUEST_TEMPLATE/sep-proposal.md
<!--
This template is for Specification Enhancement Proposals (SEPs)
SEPs are required for major protocol changes, breaking changes, and process changes.
See docs/sep-guidelines.md for full details.
-->
# SEP: [Short Descriptive Title]
## 📋 SEP Metadata
- **SEP Number**: #[GitHub Issue Number - link to your SEP issue]
- **Author(s)**: [Your Name / Organization]
- **Status**: `proposal` (awaiting sponsor)
- **Type**: [ ] Major Change [ ] Process Change
- **Related Issues/RFCs**: [Link any related issues, RFCs, or discussions]
---
## 🎯 Abstract
<!--
Provide a ~200 word description of the problem and proposed solution.
What is being changed and why?
-->
---
## 💡 Motivation
<!--
Why is the existing protocol inadequate?
What problem does this solve?
Why should the community care about this?
SEPs without sufficient motivation may be rejected outright.
-->
---
## 📐 Specification
<!--
Detailed technical specification of the proposed change.
This PR should include:
- Updates to OpenAPI specs in spec/unreleased/openapi/
- Updates to JSON schemas in spec/unreleased/json-schema/
- Example requests/responses in examples/unreleased/
- Documentation updates as needed
Be specific enough to allow competing, interoperable implementations.
-->
---
## 🤔 Rationale
<!--
Why did you make specific design decisions?
What alternative approaches did you consider?
What are the tradeoffs?
What feedback have you received from the community?
Document any important objections or concerns raised.
-->
---
## 🔄 Backward Compatibility
<!--
Required for all SEPs, especially those with breaking changes.
- Are there any breaking changes?
- What is their severity?
- How do you propose to handle migration?
- What is the deprecation timeline (if applicable)?
-->
---
## 🛠️ Reference Implementation
<!--
Link to a prototype or reference implementation if available.
Not required for initial submission, but required before status "Final".
The principle of "rough consensus and running code" helps resolve details.
-->
---
## 🔒 Security Implications
<!--
Are there any security concerns related to this proposal?
Consider:
- Authentication/authorization impacts
- Data privacy concerns
- Attack vectors
- Compliance implications
-->
---
## ✅ Pre-Submission Checklist
Before submitting this SEP PR, ensure:
- [ ] I have created a GitHub Issue with the `SEP` and `proposal` tags
- [ ] I have linked the SEP issue number above
- [ ] I have discussed this proposal in the community (Discord/GitHub Discussions)
- [ ] I have signed the [Contributor License Agreement (CLA)](../legal/cla/INDIVIDUAL.md)
- [ ] This PR includes updates to OpenAPI/JSON schemas (if applicable)
- [ ] This PR includes example requests/responses (if applicable)
- [ ] This PR includes a changelog entry file in `changelog/unreleased/your-change-description.md`
- [ ] I am seeking or have found a sponsor (Founding Maintainer)
---
## 📚 Additional Context
<!--
Any other information that would be helpful for reviewers:
- Screenshots, diagrams, or mockups
- Performance benchmarks
- User research or feedback
- Related work in other protocols/standards
-->
---
## 🙋 Questions for Reviewers
<!--
Specific questions or areas where you'd like focused feedback
-->
---
**Note**: SEPs require unanimous approval from Founding Maintainers. See [governance.md](../docs/governance.md) and [sep-guidelines.md](../docs/sep-guidelines.md) for the full process.
## /.github/scripts/validate-pr-description.js
```js path="/.github/scripts/validate-pr-description.js"
#!/usr/bin/env node
/**
* Validates PR title and description against minor-improvement, SEP, admin, or release template.
* Expects PR_TITLE and PR_BODY in environment (set by GitHub Actions).
*/
const title = process.env.PR_TITLE || '';
const body = process.env.PR_BODY || '';
const MIN_TITLE_LENGTH = 10;
const PLACEHOLDER_MINOR = '[Short Descriptive Title]';
const PLACEHOLDER_SEP = 'SEP: [Short Descriptive Title]';
const PLACEHOLDER_ADMIN = 'ADMIN: [Short Description of Admin Action]';
const PLACEHOLDER_RELEASE = 'RELEASE: [Version Date, e.g. 2026-02-19]';
const MINOR_SECTIONS = [
'## 🔧 Type of Change',
'## 📝 Description',
'## 🎯 Motivation and Context',
'## 🧪 Testing',
'## 📸 Screenshots / Examples',
'## ✅ Checklist',
'## 🔍 Scope Verification',
'## 📚 Additional Notes',
];
const SEP_SECTIONS = [
'## 📋 SEP Metadata',
'## 🎯 Abstract',
'## 💡 Motivation',
'## 📐 Specification',
'## 🤔 Rationale',
'## 🔄 Backward Compatibility',
'## 🛠️ Reference Implementation',
'## 🔒 Security Implications',
'## ✅ Pre-Submission Checklist',
'## 📚 Additional Context',
'## 🙋 Questions for Reviewers',
];
const ADMIN_SECTIONS = [
'## 🔑 Admin Action',
'## 📝 Summary',
'## 🔗 Reference',
'## ✅ Admin Checklist',
];
const RELEASE_SECTIONS = [
'## 📦 Release Summary',
'## 🔗 Included Changes',
'## ✅ Release Checklist',
];
const errors = [];
function detectType() {
const hasSepMarkers =
body.includes('## 📋 SEP Metadata') && body.includes('## 🎯 Abstract');
const hasMinorMarkers =
body.includes('## 🔧 Type of Change') && body.includes('## 📝 Description');
const hasAdminMarkers =
body.includes('## 🔑 Admin Action') && body.includes('## ✅ Admin Checklist');
const hasReleaseMarkers =
body.includes('## 📦 Release Summary') && body.includes('## ✅ Release Checklist');
if (hasReleaseMarkers && !hasSepMarkers && !hasMinorMarkers && !hasAdminMarkers) return 'release';
if (hasAdminMarkers && !hasSepMarkers && !hasMinorMarkers) return 'admin';
if (hasSepMarkers && !hasMinorMarkers) return 'sep';
if (hasMinorMarkers) return 'minor';
return null;
}
function validateTitle(type) {
const t = title.trim();
if (!t) {
errors.push('PR title is empty.');
return;
}
if (t.length < MIN_TITLE_LENGTH) {
errors.push(`PR title is too short (minimum ${MIN_TITLE_LENGTH} characters).`);
return;
}
if (type === 'sep') {
if (!t.startsWith('SEP:')) {
errors.push('SEP PRs must have a title starting with "SEP: " (e.g. "SEP: My new SEP proposal").');
return;
}
const afterPrefix = t.slice(4).trim();
if (!afterPrefix || afterPrefix === '[Short Descriptive Title]') {
errors.push('SEP title must not be the placeholder "SEP: [Short Descriptive Title]".');
}
} else if (type === 'admin') {
if (!t.startsWith('ADMIN:')) {
errors.push('Admin PRs must have a title starting with "ADMIN: " (e.g. "ADMIN: Add Acme Corp to CLA signatories").');
return;
}
const afterPrefix = t.slice(6).trim();
if (!afterPrefix || afterPrefix === '[Short Description of Admin Action]') {
errors.push('Admin title must not be the placeholder "ADMIN: [Short Description of Admin Action]".');
}
} else if (type === 'release') {
if (!t.startsWith('RELEASE:')) {
errors.push('Release PRs must have a title starting with "RELEASE: " (e.g. "RELEASE: 2026-02-19").');
return;
}
const afterPrefix = t.slice(8).trim();
if (!afterPrefix || afterPrefix === '[Version Date, e.g. 2026-02-19]') {
errors.push('Release title must not be the placeholder "RELEASE: [Version Date, e.g. 2026-02-19]".');
}
} else {
if (t === PLACEHOLDER_MINOR || t === PLACEHOLDER_SEP || t === PLACEHOLDER_ADMIN || t === PLACEHOLDER_RELEASE) {
errors.push(`PR title must not be the placeholder "${t}".`);
}
const RESERVED_PREFIXES = ['SEP:', 'ADMIN:', 'RELEASE:'];
const mismatch = RESERVED_PREFIXES.find((p) => t.toUpperCase().startsWith(p));
if (mismatch) {
errors.push(
`PR title starts with "${mismatch}" but the description uses the Minor Improvement template. Please use the matching template for ${mismatch} PRs.`
);
}
}
}
function validateSections(requiredSections, typeLabel) {
const missing = requiredSections.filter((heading) => !body.includes(heading));
if (missing.length > 0) {
errors.push(
`PR description is missing required ${typeLabel} section(s):\n - ${missing.join('\n - ')}`
);
}
}
function validateKeySectionsHaveContent(type) {
const checksMap = {
sep: [
{ heading: '## 🎯 Abstract', minLength: 50 },
{ heading: '## 💡 Motivation', minLength: 30 },
{ heading: '## 📐 Specification', minLength: 30 },
],
minor: [
{ heading: '## 📝 Description', minLength: 30 },
{ heading: '## 🎯 Motivation and Context', minLength: 20 },
],
admin: [
{ heading: '## 📝 Summary', minLength: 20 },
],
release: [
{ heading: '## 📦 Release Summary', minLength: 20 },
],
};
const checks = checksMap[type] || [];
for (const { heading, minLength } of checks) {
const idx = body.indexOf(heading);
if (idx === -1) continue;
const start = idx + heading.length;
const nextHeading = body.indexOf('\n## ', start);
const sectionBody =
nextHeading === -1 ? body.slice(start) : body.slice(start, nextHeading);
const text = sectionBody
.replace(/<!--[\s\S]*?-->/g, '')
.replace(/\s+/g, ' ')
.trim();
if (text.length < minLength) {
errors.push(
`Section "${heading}" should have at least ~${minLength} characters of content (excluding comments).`
);
}
}
}
function main() {
if (!body.trim()) {
errors.push('PR description (body) is empty.');
} else {
const type = detectType();
if (!type) {
errors.push(
'PR description does not match any template. It must include the required sections from the Minor Improvement, SEP Proposal, Admin, or Release template. See .github/PULL_REQUEST_TEMPLATE/'
);
} else {
validateTitle(type);
const sectionMap = { sep: SEP_SECTIONS, minor: MINOR_SECTIONS, admin: ADMIN_SECTIONS, release: RELEASE_SECTIONS };
const labelMap = { sep: 'SEP', minor: 'Minor Improvement', admin: 'Admin', release: 'Release' };
validateSections(sectionMap[type], labelMap[type]);
validateKeySectionsHaveContent(type);
}
}
if (errors.length > 0) {
console.error('PR description validation failed:\n');
errors.forEach((e) => console.error(' •', e));
console.error('\nPlease update the PR title and/or description to match the template.');
process.exit(1);
}
console.log('PR title and description validation passed.');
process.exit(0);
}
main();
```
## /.github/workflows/main.yml
```yml path="/.github/workflows/main.yml"
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
compile-schema:
name: Compile Schema
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Ajv env check
run: |
node -p "require('ajv/package.json').version"
node -p "require('ajv-cli/package.json').version"
node -p "require('ajv-formats/package.json').version"
- name: Show tree (debug)
run: ls -la spec/unreleased/json-schema
- name: Compile schema
run: pnpm run compile:schema
```
## /.github/workflows/stale-reminder.yml
```yml path="/.github/workflows/stale-reminder.yml"
name: Stale PR Reminder
on:
workflow_dispatch:
inputs:
dry_run:
description: 'Preview only — no comments posted, no labels added'
type: boolean
default: true
permissions:
pull-requests: write
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v10
with:
debug-only: ${{ inputs.dry_run }}
# PRs only — disable issues entirely
days-before-pr-stale: 90
days-before-pr-close: -1 # Never auto-close
days-before-issue-stale: -1
days-before-issue-close: -1
stale-pr-label: 'stale'
exempt-draft-pr: true
operations-per-run: 50
stale-pr-message: |
Hi 👋 — Thank you for your contribution to ACP!
This PR has been inactive (no commits, comments, or reviews) for over 90 days. If this work is still relevant, please:
- Rebase onto `main` to resolve any merge conflicts
- Address any outstanding review feedback
- Leave a comment confirming you'd like to keep this open
If we don't hear back within **30 days**, this PR may be closed to keep the backlog manageable. You're always welcome to reopen or submit a new PR — no work is lost!
Thanks for your patience and contributions.
```
## /.github/workflows/validate-consistency.yml
```yml path="/.github/workflows/validate-consistency.yml"
name: Validate Specification Consistency
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
validate:
name: Validate Schemas and Consistency
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run Comprehensive Validation
run: pnpm run validate:all
```
## /.github/workflows/validate-pr-description.yml
```yml path="/.github/workflows/validate-pr-description.yml"
name: Validate PR Description (.github/PULL_REQUEST_TEMPLATE)
on:
pull_request:
types: [opened, edited, synchronize, reopened]
branches: [main]
jobs:
validate-pr:
name: PR title and description
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Validate PR title and description
env:
PR_TITLE: ${{ github.event.pull_request.title }}
PR_BODY: ${{ github.event.pull_request.body }}
run: node .github/scripts/validate-pr-description.js
```
## /.gitignore
```gitignore path="/.gitignore"
# IDE
.cursor/
.vscode/
.idea/
# OS
.DS_Store
Thumbs.db
# Node
node_modules/
```
## /.vscode/settings.json
```json path="/.vscode/settings.json"
{
// Run Prettier on save
"editor.formatOnSave": true,
// Use Prettier as the default formatter
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
```
## /CODE_OF_CONDUCT.md
# Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in the Agentic Commerce Protocol community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Enforcement Responsibilities
Project maintainers are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the project maintainers responsible for enforcement. See [MAINTAINERS.md](MAINTAINERS.md) for contact information.
All complaints will be reviewed and investigated promptly and fairly.
All project maintainers are obligated to respect the privacy and security of the reporter of any incident.
## Enforcement Guidelines
Project maintainers will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from project maintainers, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of actions.
**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at [https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations
## /CONTRIBUTING.md
# Contributing to Agentic Commerce Protocol (ACP)
Thank you for your interest in contributing! We welcome improvements, bug fixes, and new ideas. Please read these guidelines to help maintain a high-quality, consistent, and collaborative project.
---
## Table of Contents
- [Contributor License Agreement (CLA)](#contributor-license-agreement-cla)
- [Branching Model](#branching-model)
- [Pull Request Guidelines](#pull-request-guidelines)
- [Spec Versioning & Review Process](#spec-versioning--review-process)
- [Required Updates for All Changes](#required-updates-for-all-changes)
- [Code of Conduct](#code-of-conduct)
- [Getting Help](#getting-help)
---
## Contributor License Agreement (CLA)
**All contributors must sign a Contributor License Agreement (CLA) before their contributions can be accepted.**
This is required by Section 2.4 of our [Collaboration and Governance Agreement](docs/governance.md) and ensures clear intellectual property rights for all contributors and users.
### For Individual Contributors
When you submit your first pull request:
1. The **CLA Assistant bot** will automatically comment on your PR
2. Click the link to review the [Individual CLA](legal/cla/INDIVIDUAL.md)
3. Click "I Agree" to sign electronically
4. Your signature is recorded for all future contributions
**This takes less than 1 minute and only needs to be done once.**
See [Individual CLA Process](legal/cla/INDIVIDUAL_PROCESS.md) for details.
### For Corporate Contributors
If you're contributing on behalf of your employer:
1. Your employer must sign the [Corporate CLA](legal/cla/CORPORATE.md)
2. Follow the [Corporate CLA Process](legal/cla/CORPORATE_PROCESS.md)
3. Once approved, you and your colleagues can contribute without individual CLA signatures
**Important:** Check with your employer about their IP policies before contributing.
### CLA Questions?
- **Why is a CLA required?** The CLA clarifies IP rights and protects both contributors and users. It's based on Apache Foundation's standard CLAs.
- **View signed CLAs:** [SIGNATORIES.md](legal/cla/SIGNATORIES.md)
- **Corporate CLA FAQ:** [CORPORATE_PROCESS.md](legal/cla/CORPORATE_PROCESS.md)
---
## Branching Model
- **main**: The stable, released branch. All production-ready code lives here.
- **feature branches**: For new features, bug fixes, or documentation updates, create a branch from `main`:
- Name your branch descriptively, e.g., `feature/add-webhook-support` or `fix/typo-in-rfc`.
- **Pull Requests (PRs)**: All changes must be submitted via PR. Never commit directly to `main`.
---
## Pull Request Guidelines
### 💡 Using PR Templates (Highly Recommended!)
We've created PR templates to help make your contribution process smoother and get your changes reviewed faster! When you create a pull request, GitHub will offer you a choice of templates - **we highly recommend using them** as they guide you through what reviewers need to know.
**Choose the template that matches your contribution:**
1. **[sep-proposal.md](.github/PULL_REQUEST_TEMPLATE/sep-proposal.md)** - Great for:
- Major protocol changes (new features, breaking changes)
- Process changes (governance, contribution guidelines)
- Complex or controversial changes requiring community discussion
- Any change that requires a SEP (see [SEP Guidelines](docs/sep-guidelines.md))
2. **[minor-improvement.md](.github/PULL_REQUEST_TEMPLATE/minor-improvement.md)** - Perfect for:
- Documentation fixes or editorial clarifications
- Simple bug fixes
- Minor enum or data changes
- Tooling improvements
- Example updates
**Not sure which template fits?** No worries! Check out [docs/governance.md](docs/governance.md) for guidance, or just pick the one that feels closest and we'll help you from there.
**Why use templates?** They help ensure you include all the info we need (like changelog entries, examples, and CLA status), which means faster reviews and merges for you! Think of them as a friendly checklist that helps both of us. 🚀
### General PR Guidelines
- **Scope**: Keep PRs focused and minimal. Separate unrelated changes (makes review easier for everyone!).
- **Description**: If using a template (recommended!), fill it out as completely as you can. Clear descriptions help us understand and review faster.
- **Tests**: If applicable, include or update tests/examples.
- **Review**: At least one maintainer will review and approve before merging.
- **Status Checks**: Ensure all CI checks pass before requesting review.
- **Linked Issues**: Reference any related issues or RFCs in the PR description.
- **CLA**: Ensure your CLA is signed (the bot will check automatically and guide you through it).
---
## Changelog Workflow
We use a directory-based changelog system to avoid merge conflicts when multiple contributors are working simultaneously.
### For Contributors: Adding a Changelog Entry
When you make a change, create a new markdown file in `changelog/unreleased/`:
1. **Create a file** with a descriptive name:
```bash
# Example filenames:
changelog/unreleased/add-payment-handlers.md
changelog/unreleased/fix-fulfillment-schema.md
changelog/unreleased/update-capability-negotiation.md
```
2. **Write your changelog entry** following this format:
```markdown
## Title of Your Change
Brief description of what changed and why.
### Breaking Changes (if applicable)
- List any breaking changes
- Include migration guidance
### Changes
- Specific change 1
- Specific change 2
### Files Updated
- `path/to/file1.json`
- `path/to/file2.yaml`
### Reference
- PR: #<pr-number>
```
3. **Commit the file** with your PR
### For Maintainers: Building a Release
When cutting a new release, manually combine all files in `changelog/unreleased/` into a single `changelog/YYYY-MM-DD.md` file, then remove the individual entry files.
---
## Spec Versioning & Review Process
- **Versioning**: All breaking changes or new features to the protocol/specs must increment the version (e.g., `2025-09-29` → `2025-10-01`).
- **Compatibility**: Maintain backward compatibility where possible. Document any breaking changes clearly in the changelog.
- **Review**: Major changes (especially to RFCs, OpenAPI, or JSON Schemas) require:
- Discussion in a PR or issue
- Approval from at least one lead maintainer (see [MAINTAINERS.md](MAINTAINERS.md))
### Specification Enhancement Proposals (SEPs)
For substantial changes to the protocol, you may need to submit a SEP:
- **What requires a SEP?** Major protocol changes, new features, breaking changes
- **Process:** See [docs/sep-guidelines.md](docs/sep-guidelines.md)
- **Discussion:** Start with a GitHub Discussion or Issue before creating a SEP
---
## Required Updates for All Changes
Every PR **must** include, as appropriate:
- [ ] **OpenAPI / JSON Schema**: Update or add under `spec/unreleased/openapi/` and `spec/unreleased/json-schema/` (or the appropriate version directory) as needed.
- [ ] **Examples**: Add or update sample requests/responses in `examples/`.
- [ ] **Changelog**: Add a changelog entry file to `changelog/unreleased/` describing your change.
- Create a new file: `changelog/unreleased/your-change-description.md`
- Follow the format shown in the Changelog Workflow section above
- [ ] **Documentation**: Update `README.md` or relevant RFCs if behavior or usage changes.
- [ ] **CLA**: Ensure you have signed the appropriate CLA.
---
## Code of Conduct
- Be respectful and constructive in all communications.
- Assume good intent and work collaboratively.
- Report unacceptable behavior to the maintainers listed in [MAINTAINERS.md](MAINTAINERS.md).
Full Code of Conduct: [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)
---
## Getting Help
- **Questions:** Open a [GitHub Discussion](https://github.com/agentic-commerce-protocol/agentic-commerce-protocol/discussions)
- **Bugs:** Create an issue using the Bug Report template
- **Features:** Create an issue using the Feature Request template
- **SEPs:** See [docs/sep-guidelines.md](docs/sep-guidelines.md)
- **Urgent matters:** Contact a lead maintainer (see [MAINTAINERS.md](MAINTAINERS.md))
We're here to help make your contribution experience great! Don't hesitate to reach out if you're unsure about anything.
---
## Project Governance
ACP is governed by Stripe and OpenAI as Founding Maintainers. Learn more:
- [Governance Model](docs/governance.md)
- [Project Principles](docs/principles-mission.md)
- [Maintainers](MAINTAINERS.md)
---
Thank you for helping make ACP better! 🎉
## /MAINTAINERS.md
# Maintainers
Below are the current maintainers of the Agentic Commerce Protocol.
## Lead maintainers
- OpenAI
- Stripe
- Meta
## /NOTICE
``` path="/NOTICE"
Copyright 2025 OpenAI
Copyright 2025 Stripe
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```
## /README.md
# Agentic Commerce Protocol (ACP)
[](LICENSE)
[](legal/cla/)
[](MAINTAINERS.md)
[](changelog/)
The **Agentic Commerce Protocol (ACP)** is an interaction model and open standard for connecting buyers, their AI agents, and businesses to complete purchases seamlessly.
The specification is [maintained](MAINTAINERS.md) by **OpenAI** and **Stripe** and is currently in `beta`.
- **For businesses** - Reach more customers. Sell to high-intent buyers by making your products and services available for purchase through AI agents—all while using your existing commerce infrastructure.
- **For AI Agents** - Embed commerce into your application. Let your users discover and transact directly with businesses in your application, without being the merchant of record.
- **For payment providers** - Grow your volume. Process agentic transactions by passing secure payment tokens between buyers and businesses through AI agents.
Learn more at [agenticcommerce.dev](https://agenticcommerce.dev).
---
## 📦 Repo Structure
```
rfcs/
├── rfc.agentic_checkout.md
├── rfc.capability_negotiation.md
├── rfc.payment_handlers.md
├── rfc.seller_backed_payment_handler.md
├── rfc.extensions.md
├── rfc.discount_extension.md
└── ...
spec/
├── 2025-09-29/ # Initial release
├── 2025-12-12/ # Fulfillment enhancements
├── 2026-01-16/ # Capability negotiation
├── 2026-01-30/ # Extensions, discounts, payment handlers
├── 2026-04-17/ # Cart, feed, orders, authentication, and MCP
└── unreleased/ # Current development
examples/
├── 2025-09-29/
├── 2025-12-12/
├── 2026-01-16/
├── 2026-01-30/
├── 2026-04-17/
└── unreleased/
changelog/
├── 2025-09-29.md
├── 2025-12-12.md
├── 2026-01-30.md
├── 2026-04-17.md
└── unreleased/ # Individual changelog entries (current development)
docs/
├── governance.md
├── principles-mission.md
└── sep-guidelines.md
legal/cla/
├── INDIVIDUAL.md
├── CORPORATE.md
└── SIGNATORIES.md
```
---
## 🔗 Quick Links
| Spec Type | Latest Stable | Description |
| ------------------ | ---------------------------------------------------- | ------------------------------------------------------------------ |
| **RFC (Markdown)** | [rfcs/](rfcs/) | Human-readable design doc with rationale, flows, and rollout plan. |
| **OpenAPI (YAML)** | [spec/2026-04-17/openapi/](spec/2026-04-17/openapi/) | Machine-readable HTTP API spec for integrating checkout endpoints. |
| **JSON Schema** | [spec/2026-04-17/json-schema/](spec/2026-04-17/json-schema/) | Data models for payloads, events, and reusable objects. |
| **Examples** | [examples/2026-04-17/](examples/2026-04-17/) | Sample requests, responses. |
| **Changelog** | [changelog/](changelog/) | API version history and breaking changes. |
---
## 📅 Versioning
ACP uses **date-based versioning** in `YYYY-MM-DD` format. Each version represents a complete snapshot of the specification at that point in time.
### Version Structure
| Directory | Purpose |
| --------- | ------- |
| `spec/<version>/` | Complete spec snapshot for a released version |
| `spec/unreleased/` | Current development (not yet released) |
| `examples/<version>/` | Examples matching each spec version |
| `changelog/<version>.md` | Release notes for each version |
### Version Lifecycle
1. **unreleased/** - New features and changes are developed here
2. **Released** - When ready, `unreleased/` is snapshotted to a dated version (e.g., `2026-01-16/`)
3. **Deprecated** - Older versions remain available but are marked deprecated in the changelog
---
## 🛠 Getting Started
ACP has been **first implemented by both OpenAI and Stripe**, providing production-ready reference implementations for merchants and developers:
- [OpenAI Documentation](https://developers.openai.com/commerce/)
- [Stripe Agentic Commerce Documentation](https://docs.stripe.com/agentic-commerce)
To start building with ACP:
1. Review this repo's [OpenAPI specs](spec/2026-04-17/openapi/) and [JSON Schemas](spec/2026-04-17/json-schema/) for the latest stable version.
2. Choose a reference implementation:
- Use OpenAI's implementation to integrate with ChatGPT and other AI agent surfaces.
- Use Stripe's implementation to leverage its payment and merchant tooling.
3. Follow the guides provided in the linked documentation.
4. Test using the [examples](examples/2026-04-17/) provided in this repo.
---
## 📚 Documentation
| Area | Resource |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| Checkout API Spec | [spec/2026-04-17/openapi/openapi.agentic_checkout.yaml](spec/2026-04-17/openapi/openapi.agentic_checkout.yaml) |
| Delegate Payment Spec | [spec/2026-04-17/openapi/openapi.delegate_payment.yaml](spec/2026-04-17/openapi/openapi.delegate_payment.yaml) |
| Governance | [docs/governance.md](docs/governance.md) |
| Project Principles | [docs/principles-mission.md](docs/principles-mission.md) |
| SEP Guidelines | [docs/sep-guidelines.md](docs/sep-guidelines.md) |
---
## 📝 Contributing
We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for:
- Branching model
- Pull request templates and guidelines
- Spec versioning and review process
- Community guidelines
### Pull Request Templates
When creating a PR, choose the appropriate template:
- **[SEP Proposal](.github/PULL_REQUEST_TEMPLATE/sep-proposal.md)** - For major protocol changes, breaking changes, or process changes
- **[Minor Improvement](.github/PULL_REQUEST_TEMPLATE/minor-improvement.md)** - For documentation fixes, bug fixes, or tooling improvements
See [docs/governance.md](docs/governance.md) for guidance on what requires a SEP.
### Contributor License Agreement (CLA)
**All contributors must sign a CLA before contributions can be accepted.**
- **Individual Contributors**: Automated via [CLA Assistant](https://cla-assistant.io/) when you submit your first PR
- **Corporate Contributors**: See [Corporate CLA Process](legal/cla/CORPORATE_PROCESS.md)
[View signed CLAs](legal/cla/SIGNATORIES.md) | [Learn more about our CLA](legal/cla/)
### All changes must include:
- Updated OpenAPI / JSON Schemas (if applicable)
- New or updated examples
- Changelog entry file in `changelog/unreleased/` (see [CONTRIBUTING.md](CONTRIBUTING.md) for details)
---
## 🏛 Governance
ACP is jointly governed by **OpenAI** and **Stripe** as Founding Maintainers, with a clear path toward broader community governance.
- **Governance Model**: [docs/governance.md](docs/governance.md)
- **Project Principles**: [docs/principles-mission.md](docs/principles-mission.md)
- **Maintainers**: [MAINTAINERS.md](MAINTAINERS.md)
- **Decision Process**: Consensus-based with escalation procedures
- **Future Path**: Neutral foundation stewardship as ecosystem matures
---
## 🤝 Community
- **Code of Conduct**: [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)
- **Discussions**: [GitHub Discussions](https://github.com/agentic-commerce-protocol/agentic-commerce-protocol/discussions)
- **Issues**: [Report bugs or request features](https://github.com/agentic-commerce-protocol/agentic-commerce-protocol/issues)
- **SEPs**: [Propose protocol enhancements](docs/sep-guidelines.md)
---
## 📜 License
Licensed under the [Apache 2.0 License](LICENSE).
## /changelog/2025-09-29.md
# Changelog
## 2025-09-29
- Initial release of the Agentic Commerce Protocol specification.
- Published the first version of:
- Agentic Checkout specification and OpenAPI schema
- Delegate Payment specification and OpenAPI schema
- Added example JSON files for both agentic checkout and delegate payment flows.
- Documentation and RFCs for both protocols included.
## /changelog/2025-12-12.md
# Changelog
## 2025-12-12
This release introduces several breaking changes to the Agentic Commerce Protocol based on learnings from URBN and Etsy adapter implementations.
### Breaking Changes
#### 1. Renamed `fulfillment_address` to `fulfillment_details`
**Impact:** Both requests (Create/Update) and all responses
**Change:**
- Old structure: Flat `fulfillment_address` object with address fields only
- New structure: Nested `fulfillment_details` object with optional `name`, `phone_number`, `email`, and nested `address` object
**Migration:**
```json
// OLD
{
"fulfillment_address": {
"name": "John Doe",
"line_one": "123 Main St",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94102"
}
}
// NEW
{
"fulfillment_details": {
"name": "John Doe",
"phone_number": "15551234567",
"email": "john@example.com",
"address": {
"name": "John Doe",
"line_one": "123 Main St",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94102"
}
}
}
```
#### 2. Replaced `fulfillment_option_id` with `selected_fulfillment_options`
**Impact:** Update requests and all responses
**Change:**
- Old: Single string `fulfillment_option_id` field
- New: Array `selected_fulfillment_options[]` with type-specific nested structures supporting multiple selections and item-level mappings
**Migration:**
```json
// OLD
{
"fulfillment_option_id": "fulfillment_option_123"
}
// NEW
{
"selected_fulfillment_options": [
{
"type": "shipping",
"shipping": {
"option_id": "fulfillment_option_123",
"item_ids": ["item_456"]
}
}
]
}
```
**Rationale:** Supports selecting different fulfillment options for different items in the same cart, essential for complex fulfillment scenarios.
#### 3. Made `subtotal` and `tax` optional in FulfillmentOption
**Impact:** Both `FulfillmentOptionShipping` and `FulfillmentOptionDigital` schemas
**Change:**
- Old: `subtotal` and `tax` were required fields
- New: `subtotal` and `tax` are optional; only `total` is required
**Migration:**
```json
// OLD - both subtotal and tax required
{
"type": "shipping",
"id": "fulfillment_option_123",
"title": "Standard Shipping",
"subtotal": 100,
"tax": 0,
"total": 100
}
// NEW - can omit subtotal and tax if not available
{
"type": "shipping",
"id": "fulfillment_option_123",
"title": "Standard Shipping",
"total": 100
}
```
**Rationale:** Not all sellers provide tax/subtotal breakdown for fulfillment options. Only the total amount is essential.
#### 4. Added `selected_fulfillment_options` to UpdateCheckout request
**Impact:** `CheckoutSessionUpdateRequest` schema
**Change:**
- Old: Could only update via `fulfillment_option_id` (now removed)
- New: Update via `selected_fulfillment_options[]` array
### Additional Changes
#### Bug Fix: Fulfillment Amount Types
Fixed inconsistency in OpenAPI spec where fulfillment option amounts (`subtotal`, `tax`, `total`) were incorrectly typed as strings instead of integers. The JSON Schema and RFC always specified integers in minor units.
#### Added: Total Description Field
Added optional `description` field to the `Total` type to provide additional context for line items, especially fees (e.g., "Processing and handling fee").
#### Added: `return_policy` Link Type
Added `return_policy` as a new link type option alongside `terms_of_use` and `privacy_policy`. Removed `seller_shop_policies` link type (redundant).
#### Added: LineItem Display Fields
Added optional display fields to `LineItem` for richer product presentation:
- `name`, `description`, `images`, `unit_amount`
- `disclosures`, `custom_attributes`, `marketplace_seller_details`
#### Added: Intent Traces
Added support for structured cancellation context via `intent_trace` on the cancel endpoint, allowing agents to communicate why a session is being abandoned.
#### Added: Affiliate Attribution
Added support for the Affiliate Attribution extension, enabling agents to credit third-party publishers without relying on cookies or client-side tracking. Supports first-touch (session creation) and last-touch (completion) attribution.
### Version Compatibility
- Clients MUST send `API-Version: 2025-12-12` header
- Previous version `2025-09-29` is deprecated
- Breaking changes require client updates
### Files Updated
- `spec/json-schema/schema.agentic_checkout.json`
- `spec/openapi/openapi.agentic_checkout.yaml`
- `examples/examples.agentic_checkout.json`
- `rfcs/rfc.agentic_checkout.md`
### Reference
- Commit: [fb790cc](https://github.com/agentic-commerce-protocol/agentic-commerce-protocol/commit/fb790cc)
## /changelog/2026-01-16.md
# Version 2026-01-16
---
# Authentication Provider
**Added** – Initial support for an **open authentication provider model**, allowing merchants to specify their preferred 3DS
provider. Also adding required `merchant_id` field to `PaymentProvider`
**Schema Changes:**
- Added `merchant_id` required field to `PaymentProvider`
- Added `AuthenticationProvider` schema with `provider`, `merchant_id`, and `supported_authentication_methods` fields
- Added `authentication_provider` field to `CheckoutSessionBase`
- Added `adyen` to the provider enum for both `PaymentProvider` and `AuthenticationProvider`
**Files Updated:**
- `spec/2026-01-16/schema.agentic_checkout.json`
- `spec/2026-01-16/openapi.agentic_checkout.yaml`
- `examples/2026-01-16/examples.agentic_checkout.json`
- `rfcs/rfc.agentic_checkout.md`
## /changelog/2026-01-30.md
# Version 2026-01-30
This release introduces four major features that enhance ACP's capability discovery, payment handling, and extensibility.
---
## Capability Negotiation
**Enables agents and sellers to discover and negotiate supported features during checkout.**
Agents declare their capabilities in requests; sellers return the intersection of supported features in responses.
**Key Features:**
- Single `capabilities` object used in both requests and responses
- Intersection semantics: seller computes mutual compatibility
- Early incompatibility detection before payment authorization
- Required field for predictable behavior
**Example:**
```json
// Agent request
{
"capabilities": {
"interventions": {
"supported": ["3ds", "address_verification"],
"display_context": "webview",
"max_redirects": 1
}
}
}
// Seller response (intersection)
{
"capabilities": {
"payment_methods": [
{
"method": "card",
"brands": ["visa", "mastercard"]
}
],
"interventions": {
"supported": ["3ds"], // Intersection of agent + seller
"required": [],
"enforcement": "conditional"
}
}
}
```
**See:** [Capability Negotiation RFC](../rfcs/rfc.capability_negotiation.md)
---
## Payment Handlers Framework (Breaking Change)
**Replaces simple payment method identifiers with structured handlers.**
**What Changed:**
1. **Declaration:**
- Old: `payment_provider.supported_payment_methods`
- New: `capabilities.payment.handlers`
2. **Handler Structure:**
```json
{
"id": "card_tokenized",
"name": "dev.acp.tokenized.card",
"version": "2026-01-22",
"spec": "https://acp.dev/handlers/...",
"requires_delegate_payment": true,
"requires_pci_compliance": false,
"psp": "stripe",
"config": {
"merchant_id": "acct_1234567890",
"accepted_brands": ["visa", "mastercard"],
"supports_3ds": true
}
}
```
3. **Payment Data:**
- Old: `{ "token": "spt_123", "provider": "stripe" }`
- New: `{ "handler_id": "card_tokenized", "instrument": { "type": "card", "credential": { "type": "spt", "token": "spt_123" } } }`
**Benefits:**
- Standardized handler discovery
- Explicit security requirements
- PSP identification for credential vaulting
- Handler-specific configuration
**See:** [Payment Handlers RFC](../rfcs/rfc.payment_handlers.md)
---
## Extensions Framework
**Standardized mechanism for optional, composable capabilities.**
Extensions are declared in `capabilities.extensions[]` and integrate with capability negotiation:
```json
{
"capabilities": {
"extensions": [
{
"namespace": "dev.acp.discount",
"version": "2026-01-27"
}
]
}
}
```
**Lifecycle:** Discovery → Negotiation → Usage
**See:** [Extensions Framework RFC](../rfcs/rfc.extensions.md)
### Discount Extension
**Rich discount code support (first ACP extension).**
**Features:**
- Discount code input via `discounts.codes[]`
- Applied discount details with line-item allocations
- Automatic discounts (no code required)
- Rejected codes via `messages[]` with error codes
**Example:**
```json
// Request
{
"discounts": {
"codes": ["SUMMER25"]
}
}
// Response
{
"discounts": {
"applied": [
{
"id": "discount_123",
"coupon": {
"code": "SUMMER25",
"name": "25% Summer Sale",
"percent_off": 25.0
},
"amount": -2500,
"allocations": [
{
"line_item_id": "item_456",
"amount": -2500
}
]
}
]
}
}
```
**Migration:** Optional extension. No changes required for existing implementations.
**See:** [Discount Extension RFC](../rfcs/rfc.discount_extension.md)
---
## Version Compatibility
- API Version: `2026-01-30`
- Previous version `2026-01-22` deprecated
- Payment Handlers: **Breaking change** - requires updates
- Extensions/Discount: **Optional** - adopt incrementally
## Files Updated
**Specifications:**
- `spec/2026-01-30/json-schema/schema.agentic_checkout.json`
- `spec/2026-01-30/json-schema/schema.discount.json` (new)
- `spec/2026-01-30/json-schema/schema.extension.json` (new)
- `spec/2026-01-30/json-schema/schema.delegate_payment.json`
- `spec/2026-01-30/openapi/openapi.agentic_checkout.yaml`
- `spec/2026-01-30/openapi/openapi.delegate_payment.yaml`
- `spec/2026-01-30/openapi/openapi.agentic_checkout_webhook.yaml`
**Examples:**
- `examples/2026-01-30/examples.agentic_checkout.json`
- `examples/2026-01-30/examples.delegate_payment.json`
- `examples/2026-01-30/discount-extension/*.json` (5 examples)
**RFCs:**
- `rfcs/rfc.extensions.md` (new)
- `rfcs/rfc.discount_extension.md` (new)
- `rfcs/rfc.payment_handlers.md` (new)
## /changelog/2026-04-17.md
# Version 2026-04-17
This release promotes the accumulated unreleased ACP changes since 2026-01-30.
## Version Compatibility
- API Version: `2026-04-17`
- Previous version `2026-01-30` deprecated
## Included Changes
### Additional 3DS authentication flow examples
Added examples for 3DS authentication outcomes that complement the consumer authentication SEP (PR #53).
#### Changes
- `authentication_result_denied_example`: Failed authentication with `outcome: "denied"`
- `authentication_result_frictionless_example`: Frictionless flow with `outcome: "attempt_acknowledged"`
- `complete_session_with_denied_authentication_request`: Complete request showing how to handle denied authentication
#### Files Updated
- `examples/unreleased/examples.agentic_checkout.json`
#### Reference
- Issue: #55
- Related: PR #53 (consumer authentication SEP)
---
### Add error response and multi-item checkout examples
**Agentic Checkout API – Examples**
- **Error examples**: Added `error_400_invalid_item` (HTTP-level Error for invalid item ID), `checkout_session_with_out_of_stock` and `checkout_session_with_payment_declined` (CheckoutSession responses with `MessageError` in `messages` array).
- `examples/unreleased/examples.agentic_checkout.json`
- **Multi-item checkout**: Added request and response examples for a checkout session with multiple line items, showing per-item `unit_amount` and `totals`.
- `examples/unreleased/examples.multi_item_checkout.json`
---
### Feed API
**Added** – an unreleased Feed API surface for feed metadata and product catalog management.
### New API Surface
These endpoints are hosted by Agents and called by merchants. The Feed API is a
push model: merchants push product catalog metadata and product records to
Agents, rather than Agents pulling catalog data from merchant-hosted endpoints.
- `POST /feeds` for merchants to create feed metadata on an Agent-hosted feed service
- `GET /feeds/{id}` for merchants to retrieve feed metadata from the Agent
- `GET /feeds/{id}/products` for merchants to retrieve the current Agent-hosted product set
- `PATCH /feeds/{id}/products` for merchants to partially upsert products by `Product.id` into the Agent-hosted feed
### File Ingestion Format
- `metadata.json` uses the `FeedMetadata` shape
- `products.jsonl` contains one `Product` object per line
- file ingestion performs full replacement of the feed's product set
- partial updates are only supported through `PATCH /feeds/{id}/products`
### Deferred
- promotions are intentionally deferred to a stacked follow-up PR
---
### Add `supported_versions` Field to Version Mismatch Error Responses
When an ACP server rejects a request due to missing or unsupported `API-Version` header, agents previously had no programmatic way to discover which versions the server supports. This change adds guidance and schema support for a `supported_versions` array in error responses.
#### Changes
- **RFC Documentation**: Added guidance to Section 2.1 (Initialization) in both `rfc.agentic_checkout.md` and `rfc.delegate_payment.md` specifying that servers **SHOULD** include `supported_versions` array when rejecting version-related requests, and **MAY** use `unsupported_api_version` or `missing_api_version` as well-known error codes.
- **Schema Updates**: Added optional `supported_versions` field to the `Error` schema in both `schema.agentic_checkout.json` and `schema.delegate_payment_schema.json`.
#### Example Error Response
```json
{
"type": "invalid_request",
"code": "unsupported_api_version",
"message": "API version '2025-01-01' is not supported",
"supported_versions": ["2026-01-30", "2025-09-29"]
}
```
#### Benefits
- Agents can programmatically discover supported versions and retry
- Enables version negotiation without out-of-band discovery
- Low implementation burden (optional field)
- Fully backward compatible
#### Related
- Closes issue #95
---
### Allow empty risk_signals array
The current implementation of `delegate_payment` does not always provide an array of at least size 1 in the `risk_signals` array.
#### Changes
- **Risk signals:** `minItems` of `1` on the `risk_signals` field is removed.
#### Breaking Changes
None.
#### Files Updated
- `spec/unreleased/json-schema/schema.delegate_payment.json`
- `spec/unreleased/openapi/openapi.delegate_payment.yaml`
---
### Cart Capability
**Added** -- pre-checkout cart management for incremental basket building.
### New Endpoints
- **`POST /carts`** -- Create a new cart with line items and optional buyer information.
- **`GET /carts/{id}`** -- Retrieve the current state of a cart.
- **`PUT /carts/{id}`** -- Update a cart (full replacement of line items).
- **`POST /carts/{id}/cancel`** -- Cancel a cart and return its final state.
### New Schemas
- **Cart**: Response object with `id`, `line_items`, `buyer`, `currency`, `totals`, `messages`,
`continue_url`, and `expires_at`. Reuses existing ACP types (LineItem, Buyer, Total, Message).
- **CartCreateRequest**: `line_items` (required), `buyer`, `locale`.
- **CartUpdateRequest**: `line_items` (required), `buyer`.
### Discovery Integration
- **`"carts"`** added to the `capabilities.services` enum in the discovery document
(`/.well-known/acp.json`). Agents check for `"carts"` before attempting cart operations.
### Design Notes
- Carts are scoped to a single seller.
- Carts have no status lifecycle — they either exist or return 404.
- Carts have no capability negotiation — that occurs at checkout creation time.
- Carts have no payment data — payment is a checkout concern.
- Totals on carts are estimates (e.g., tax may be omitted if address is unknown).
- Cart-to-checkout conversion (via `cart_id`) and extension support (e.g., discounts) are deferred to follow-up SEPs.
**Files changed:**
- `spec/unreleased/json-schema/schema.cart.json` (new)
- `spec/unreleased/openapi/openapi.cart.yaml` (new)
- `spec/unreleased/json-schema/schema.agentic_checkout.json` (carts in discovery services enum)
- `rfcs/rfc.cart.md` (new)
- `rfcs/rfc.discovery.md` (carts in services enum)
---
### Decimal quantity support (B2B)
**Breaking change** – Item `quantity` field type change.
- **Quantity field**: Changed from `integer` to `number` (decimal) to support B2B commerce (e.g. items sold by weight or other fractional units). The field accepts decimal values greater than 0 (`exclusiveMinimum`).
- Updated in: `spec/2025-09-29/json-schema/schema.agentic_checkout.json`, `spec/2025-09-29/openapi/openapi.agentic_checkout.yaml`
- Examples updated to demonstrate decimal quantities (e.g. 2.5).
---
### Delegate Authentication
This RFC defines a standardized REST API contract for **delegated consumer authentication**. It enables agents to execute 3DS2 browser-based authentication directly with merchant specified authentication providers.
#### Changes
- **Delegate Authentication API**: Established a session-based authentication lifecycle (Create → Authenticate → Retrieve) to manage 3DS2 states across asynchronous browser actions.
- **Data Models**: Defined schemas for `PaymentMethod`, `BrowserInfo` and `AuthenticationResult` (Cryptograms and ECI).
- **Webhook Definitions**: Added support for asynchronous notifications, including Fingerprint completion, Challenge results, and an optional RReq webhook to prevent browser-to-backend race conditions.
#### Benefits
- **Standardization**: Provides a single contract for agents to interact with any compliant 3DS2 provider.
#### Files Created
- `rfcs/rfc.delegate_authentication.md`
- `spec/unreleased/json-schema/schema.delegate_authentication.json`
- `spec/unreleased/openapi/openapi.delegate_authentication.yaml`
- `examples/unreleased/examples.delegate_authentication.json`
---
### Discovery Well-Known Document
**Added** -- discovery document at `/.well-known/acp.json` for pre-session capability checks.
### New Document
- **`/.well-known/acp.json`** -- A static, publicly accessible JSON document served at the origin
root per RFC 8615. Enables agents to determine ACP support, discover the API base URL, check
version compatibility, and learn available capabilities before creating a checkout session.
### New Schemas
- **DiscoveryResponse**: Top-level document containing protocol metadata, API base URL, supported
transports, and a capabilities object.
- **DiscoveryCapabilities**: Seller capabilities wrapper containing services, extensions,
intervention types, supported currencies, and supported locales.
- **DiscoveryProtocol**: Protocol identification with name (`acp`), current version,
supported version history (chronologically ordered), and documentation URL.
- **DiscoveryExtension**: Lightweight extension declaration with name and optional spec URL.
### Design Notes
- No authentication required -- the document is publicly accessible.
- Seller-scoped -- returns information that is stable across sessions.
- Merchant-specific and session-specific capabilities (payment methods, payment handlers)
remain in the inline `capabilities` object on `POST /checkout_sessions`.
- Responses SHOULD include `Cache-Control: public, max-age=3600` as a recommended minimum.
- `transports` field advertises available transport bindings (`rest`, `mcp`), cross-referencing
the MCP Transport Binding (SEP #135).
- `services`, `intervention_types`, and `transports` enums are closed per API version.
**Files changed:**
- `spec/unreleased/json-schema/schema.agentic_checkout.json`
- `rfcs/rfc.discovery.md`
- `examples/unreleased/examples.agentic_checkout.json`
- `docs/mcp-binding.md`
---
### Enhanced Schema Validation for Documentation Completeness
**Validation Script – Added** – Comprehensive validation rules to ensure all schemas in `spec/unreleased/` have complete descriptions and examples.
### New Validations
#### JSON Schema Validation
- **Field Descriptions**: All data models and fields must have descriptions. Validates recursively through properties, array items, `oneOf`/`anyOf`/`allOf`, and `additionalProperties`.
- **Model Examples**: Every data model in `$defs` must have at least one example (using `example` or `examples` field).
#### OpenAPI Validation
- **Field Descriptions**: All schema fields must have descriptions. Enforced as errors to ensure API documentation completeness.
- **Schema Examples**: All top-level schemas in `components/schemas` must have examples.
#### Dynamic File Discovery
- Removed hardcoded file lists (`SPECS` array)
- Added dynamic discovery: `getJsonSchemaFiles()` and `getOpenApiFiles()` functions
- Now validates ALL `schema.*.json` and `openapi.*.yaml` files in each version directory
- Automatically includes newly added schemas like `schema.discount.json` and `schema.extension.json`
### Fixed Validation Issues
#### Bug Fixes
- **Amount field validation**: Fixed false positives for properties using composition patterns (`allOf`, `$ref`, etc.). The validator now skips these when checking if amount fields are integers.
#### Schema Updates
Added missing descriptions and examples to `spec/unreleased/`:
- `schema.agentic_checkout.json`
- `schema.delegate_payment.json`
- `schema.discount.json`
- `schema.extension.json`
- `openapi.agentic_checkout.yaml`
- `openapi.delegate_payment.yaml`
### Benefits
- Prevents incomplete documentation from being committed
- Ensures consistency between JSON Schema and OpenAPI specifications
- Helps developers understand data models with comprehensive examples
- Runs automatically on every commit via GitHub Actions
**Files changed**: `scripts/validate-consistency.js`, `scripts/README.md`, `spec/unreleased/json-schema/*.json`, `spec/unreleased/openapi/*.yaml`
---
### Fix incorrect fulfillment values in complete and cancel response examples
The complete and cancel response examples incorrectly showed Standard shipping values (`fulfillment_option_123`, cost 100, total 430) after the update example switched to Express shipping (`fulfillment_option_456`, cost 500, total 830). Fixed to be consistent with the preceding update response.
#### Changes
- Fixed `selected_fulfillment_options`, fulfillment amount, and total in complete response example (RFC section 9.6)
- Fixed fulfillment amount and total in cancel response example (RFC section 9.8)
- Applied same fixes to `examples/unreleased/examples.agentic_checkout.json`
#### Files Updated
- `rfcs/rfc.agentic_checkout.md`
- `examples/unreleased/examples.agentic_checkout.json`
#### Reference
- Issue: #16
---
### Fix schema consistency between JSON Schema and OpenAPI
**Fixed** — two spec drift issues between JSON Schema and OpenAPI.
#### DiscountsResponse missing `rejected` array in JSON Schema
The OpenAPI spec and the discount extension schema (`schema.discount.json`) both define a `rejected` array on `DiscountsResponse` with `RejectedDiscount` items. The main JSON schema (`schema.agentic_checkout.json`) was missing it — only had `codes` and `applied`.
Added `rejected` array, `RejectedDiscount` type, and `DiscountErrorCode` enum to the main JSON schema to match the OpenAPI spec.
#### `frictionless` flow_preference missing properties in OpenAPI
The JSON schema defines `frictionless.properties.type` with enum `["low_risk"]` on `AuthenticationMetadata.flow_preference`. The OpenAPI spec had `frictionless` as an empty object with `additionalProperties: false` and no properties.
Added the `type` property with `low_risk` enum to the OpenAPI `frictionless` object to match the JSON schema.
#### Files changed
- `spec/unreleased/json-schema/schema.agentic_checkout.json`
- `spec/unreleased/openapi/openapi.agentic_checkout.yaml`
---
### Mandatory Idempotency Requirements and Guarantees
Agents retrying failed or timed-out requests had no protocol-level guarantee of safe replay. This change makes the `Idempotency-Key` header mandatory on all POST requests and defines explicit error responses for missing keys, in-flight collisions, and payload mismatches.
#### Changes
- **IdempotencyKey parameter**: Changed from `required: false` to `required: true` on both Agentic Checkout and Delegate Payment APIs. Added `maxLength: 255` constraint. UUID v4 recommended.
- **IdempotencyKey scoping**: Moved `IdempotencyKey` out of path-level parameters on `/checkout_sessions/{id}` so GET does not inherit the now-required header.
- **Idempotent-Replayed response header**: Added to all POST 2xx responses. Set to `"true"` when the response is a cached replay.
- **400 — idempotency_key_required**: Returned when `Idempotency-Key` header is missing from a POST request.
- **409 — idempotency_in_flight**: Returned when a request with the same key is still being processed. Includes `Retry-After` header.
- **422 — idempotency_conflict**: Returned when an `Idempotency-Key` is reused with a different request body.
- **Error.type enum**: Removed `request_not_idempotent` from the Agentic Checkout Error schema. All idempotency errors now use `type: invalid_request` with specific codes.
- **Error.code enum** (Delegate Payment): Added `idempotency_key_required` and `idempotency_in_flight`.
- **Examples**: Added idempotency error examples to both Agentic Checkout and Delegate Payment example files.
#### Related
- Closes issue #120
---
### IIN field max length 6 → 8
**Delegate Payment API – Changed**
- **IIN field length**: Updated `iin` field `maxLength` from 6 to 8 characters in `PaymentMethodCard` schema to support extended IIN ranges (ISO/IEC 7812-1).
- `spec/unreleased/openapi/openapi.delegate_payment.yaml`
- `spec/unreleased/json-schema/schema.delegate_payment.json`
- `rfcs/rfc.delegate_payment.md`
---
### Markdown Specification (CommonMark)
**Changed** -- formalized markdown semantics for `content_type: "markdown"` fields.
When `content_type` is set to `"markdown"`, content MUST conform to
[CommonMark version 0.31.2](https://spec.commonmark.org/0.31.2/). Raw HTML
elements MUST NOT be included. Agents MUST render using a CommonMark-compliant
parser with raw HTML output disabled or sanitized.
Affected types: Disclosure, MessageInfo, MessageWarning, MessageError.
**Files changed:** `spec/unreleased/json-schema/schema.agentic_checkout.json`, `spec/unreleased/openapi/openapi.agentic_checkout.yaml`, `rfcs/rfc.agentic_checkout.md`
---
### Marketing Consent Support
Add marketing consent support to enable sellers to offer opt-in marketing subscriptions during checkout.
### New Schemas
- **MarketingConsentOption**: Seller-declared consent option with `channel` (open enum, e.g. email, sms, whatsapp),
`display_text`, `privacy_policy_url`, and optional `is_subscribed` boolean for returning buyers.
- **MarketingConsent**: Agent-submitted consent decision with `channel` and `opted_in` boolean.
### CheckoutSession Changes
- **`marketing_consent_options`** added as an optional array on `CheckoutSessionBase`. Sellers
include this to signal available marketing channels and the buyer's existing subscription status.
An empty array is equivalent to absent.
- **`marketing_consents`** added as an optional array on `CheckoutSessionCompleteRequest`. Agents
include the buyer's consent decisions for each option surfaced. Sellers ignore entries for
channels not offered.
### Marketing Channel Resolution
- For email consent: seller uses `buyer.email` (primary) or `fulfillment_details.email` (fallback).
- For SMS/WhatsApp consent: seller uses `buyer.phone_number` (primary) or
`fulfillment_details.phone_number` (fallback).
### Design Notes
- Consent is captured at complete checkout time only — not during checkout updates.
- `is_subscribed` lets sellers communicate existing subscription status so agents render the
correct default (pre-checked for returning subscribers, unchecked for new buyers).
- Agents MAY selectively surface a subset of options; unsurfaced options are omitted from the
response, preserving existing subscription state.
- Omission of `marketing_consents` in the complete request preserves all existing subscriptions.
- Sellers who do not want to risk accidental revocation should omit the channel from
`marketing_consent_options`.
**Files changed:**
- `spec/unreleased/json-schema/schema.agentic_checkout.json` (new schemas and fields)
- `spec/unreleased/openapi/openapi.agentic_checkout.yaml` (new schemas and fields)
- `examples/unreleased/examples.agentic_checkout.json` (consent examples)
- `rfcs/rfc.marketing_consent.md` (RFC document)
---
### MCP Transport Binding
**Added** -- Model Context Protocol (MCP) transport binding for ACP checkout operations.
### New Files
- **OpenRPC Schema**: `spec/unreleased/openrpc/openrpc.agentic_checkout.json` -- defines 5 MCP tools
- **Binding Specification**: `docs/mcp-binding.md` -- REST-to-MCP mapping conventions
- **MCP Examples**: `examples/unreleased/examples.mcp.agentic_checkout.json`
### MCP Tools
- `create_checkout_session` -- maps to POST /checkout_sessions
- `get_checkout_session` -- maps to GET /checkout_sessions/{id}
- `update_checkout_session` -- maps to POST /checkout_sessions/{id}
- `complete_checkout_session` -- maps to POST /checkout_sessions/{id}/complete
- `cancel_checkout_session` -- maps to POST /checkout_sessions/{id}/cancel
### Design Decisions
- Argument structure: `meta` (headers) / `id` (path param) / `payload` (request body)
- `payload` $refs existing ACP request schemas directly -- no schema duplication
- Auth handled via MCP server configuration, not per-request
- Errors use uniform -32000 with ACP Error object in JSON-RPC error.data
**Files changed:** spec/unreleased/openrpc/openrpc.agentic_checkout.json,
docs/mcp-binding.md, examples/unreleased/examples.mcp.agentic_checkout.json
---
### Message Resolution Field
**Added** – optional `resolution` on `MessageInfo`, `MessageWarning`, and `MessageError`.
Indicates who is responsible for resolving the message:
- `recoverable`: Agent can fix via API (e.g., retry with different parameters)
- `requires_buyer_input`: Buyer must provide information the API cannot collect programmatically (checkout incomplete)
- `requires_buyer_review`: Buyer must authorize before order placement due to policy, regulatory, or entitlement rules (checkout complete)
Enables agents to decide whether to attempt automated recovery or escalate to the buyer.
**Files changed:** `spec/unreleased/openapi/openapi.agentic_checkout.yaml`, `spec/unreleased/json-schema/schema.agentic_checkout.json`, `rfcs/rfc.agentic_checkout.md`, `examples/discount-extension/rejected-discount-code.json`
---
### Native Orders Support
**Added** – rich post-purchase order tracking with line items, fulfillments, and adjustments.
### New Schemas
- **OrderLineItem**: Per-item tracking with `quantity.ordered` and `quantity.shipped`
- **Fulfillment**: Tracks shipping, pickup, and digital delivery with carrier info and tracking
- **FulfillmentEvent**: Append-only log of delivery events (shipped, in transit, delivered, etc.)
- **Adjustment**: Post-order changes (refunds, credits, returns, disputes, chargebacks)
- **Order Totals**: Reuses checkout `Total` schema for order-level financial summary
- **LineItemReference**: References line items in fulfillments and adjustments
### Enhanced Order Schema
The existing `Order` schema gains optional fields:
- `type` – Discriminator field for webhook payloads (always `"order"`)
- `line_items[]` – What was ordered with fulfillment progress
- `fulfillments[]` – How items are being delivered
- `adjustments[]` – Post-order changes
- `totals` – Financial summary
All new fields are optional, maintaining backward compatibility.
### Order Status Enum
Extended to a superset that aligns with the webhook spec:
`[created, confirmed, manual_review, processing, shipped, delivered, canceled]`
### Order Totals
- Replaced flat `OrderTotals` object with `Total[]` array, reusing the same `Total` schema from checkout sessions
- Added `amount_refunded` to `Total.type` enum for post-purchase refund tracking
- The `total` entry is documented as the original charged amount at checkout (pre-adjustment)
### Digital Fulfillment
- Added `digital_delivery` sub-object to Fulfillment with `access_url`, `license_key`, `expires_at`
- Added `ready_for_pickup` to Fulfillment and FulfillmentEvent status/type enums
- Documented per-type status applicability (which statuses apply to shipping, pickup, digital)
### Adjustment Amount
- `Adjustment.amount` is now documented as the total amount credited to the buyer, inclusive of tax
### Webhook Spec Alignment
- `EventDataOrder` now composes the full `Order` schema via cross-file `$ref`
- `refunds[]` and the `Refund` schema have been removed from `EventDataOrder` in favor of `adjustments[]`
- Fixed pre-existing bug: inline example had `amount: "1.00"` (string) instead of integer
- Updated inline examples to show rich Order fields (line_items, fulfillments, adjustments, totals)
### Agent Use Cases
- "Where's my order?" → `fulfillments[]` with tracking and events
- "What did I order?" → `line_items[]` with details
- "Which items shipped?" → `line_items[].quantity.shipped`
- "Did I get a refund?" → `adjustments[]` with status
- "How much was I refunded?" → `totals[]` entry with `type: "amount_refunded"`
**Files changed:** `spec/unreleased/openapi/openapi.agentic_checkout.yaml`, `spec/unreleased/openapi/openapi.agentic_checkout_webhook.yaml`, `spec/unreleased/json-schema/schema.agentic_checkout.json`, `rfcs/rfc.orders.md`, `examples/orders/`
---
### Payment handler display order
**Added** – Optional `display_order` on each payment handler in `capabilities.payment.handlers`.
Sellers can suggest a preferred display order for payment methods (lower value = higher preference). The ordering is **suggestive**: platforms and agents MAY reorder (e.g. for user preference or localization). This lets sellers express their fraud vs. conversion preferences so agents have a standard hint when presenting payment options.
**Backward compatible:** Optional field; existing implementations ignore unknown properties. No breaking changes.
**RFC:** `rfcs/rfc.payment_handlers.md`
**Schema:** `spec/unreleased/json-schema/schema.agentic_checkout.json`, `spec/unreleased/openapi/openapi.agentic_checkout.yaml`
**Examples:** `examples/unreleased/examples.agentic_checkout.json`
---
### PaymentHandler display_name
**Added** – optional field for payment UI. Backward compatible.
#### Schema changes
- **PaymentHandler.display_name** — Optional human-readable name for the payment method (e.g. "Credit Card", "PayPal"). Used when showing payment options to the buyer; avoids displaying the handler’s technical `name` (e.g. `dev.acp.tokenized.card`).
#### Files changed
- `spec/unreleased/json-schema/schema.agentic_checkout.json`
- `spec/unreleased/openapi/openapi.agentic_checkout.yaml` — added `display_name` on PaymentHandler
- `examples/unreleased/examples.agentic_checkout.json` — added `display_name` on handler examples
---
### Agentic Checkout schema improvements (platform alignment)
**Added / Changed** – schema updates to align with common patterns. All new fields are optional; backward compatible.
#### Fixes
- **Duplicate key:** Removed duplicate `fulfillment_groups` property in `CheckoutSessionBase` (invalid JSON; only one occurrence retained).
#### Schema changes
- **Address:** Added description on `country` recommending ISO 3166-1 alpha-2 (e.g. `US`, `GB`) for interoperability. Added optional `company` for B2B and shipping address.
- **FulfillmentDetails.phone_number:** Added description recommending E.164 format for global and carrier interoperability.
- **Order notes:** Added optional `order_notes` (string, maxLength 5000) to `CheckoutSessionCreateRequest`, `CheckoutSessionUpdateRequest`, and `CheckoutSessionCompleteRequest` for delivery instructions, gift messages, and customer comments.
- **OrderConfirmation:** Added optional `order_notes` to echo order notes on confirmation.
- **Order:** Added description on `order_number` (human-readable display number). Added optional `client_reference_id`: reference provided by the client (agent/platform) when completing checkout; the merchant stores it on the order and returns it so the platform can reconcile its transaction (e.g. `platform_txn_abc789`) with the merchant order (e.g. `ord_xyz`) for support, refunds, or analytics. Aligns with Stripe’s `client_reference_id` (the client provides the value, the merchant stores it).
#### Descriptions added (developer clarity)
Schema descriptions were added so developers can clearly tell the Order identifiers apart:
- **Order.id** — “Merchant’s unique order id (assigned when the order is created). Use for API calls, permalink, and webhooks.” Distinguishes the merchant’s canonical order id from the session id and from any client reference.
- **Order.checkout_session_id** — “Id of the checkout session that created this order. Links the order back to the agentic checkout flow.” Makes the order–session relationship explicit.
- **Order.client_reference_id** — Short description in the schema (“Reference from the client (agent/platform) stored on the order for reconciliation…”); fuller explanation and marketplace example are in this changelog so the schema stays concise.
#### Files changed
- `spec/unreleased/json-schema/schema.agentic_checkout.json`
- `examples/unreleased/examples.agentic_checkout.json` — added `company`, `order_notes`, `order_number`, `client_reference_id`, and `confirmation.order_notes` to relevant examples
---
### Seller-backed payment
**Added** – `dev.acp.seller_backed` payment handler pattern and four handler types: `saved_card`, `gift_card`, `points`, `store_credit`.
Sellers can declare payment options in `capabilities.payment.handlers` that are resolved on the seller's backend without credential transfer. All use `requires_delegate_payment: true` and `requires_pci_compliance: false`. Tokenization via `delegate_payment` preserves audit trail and observability.
**Backward compatible:** Additive only; no schema or API changes. Existing implementations ignore unknown handlers.
**RFC:** `rfcs/rfc.seller_backed_payment_handler.md`
**Examples:** `examples/2026-01-30/examples.agentic_checkout.json`, `examples/unreleased/examples.agentic_checkout.json`
---
### Webhook signing: Stripe-aligned format and replay protection
Specifies the Merchant-Signature header format for agentic checkout webhooks and adds replay protection. Aligns with Stripe’s webhook signature scheme for interoperability.
#### Changes
- **Signature format:** Header value is `t=<unix_seconds>,v1=<64_hex>`. Signed payload is `timestamp + "." + raw_body`; HMAC-SHA256 with shared secret. Pattern accepts hex (`[a-fA-F0-9]{64}`).
- **Replay protection:** Receiver rejects requests when timestamp `t` is outside an allowed window. Recommended tolerance 300 seconds. Description states that signing is used to prevent replay attacks and to verify authenticity and integrity.
#### Breaking Changes
None. This defines the format of an already-required header (signing was already mandatory).
#### Files Updated
- `spec/unreleased/openapi/openapi.agentic_checkout_webhook.yaml`
---
## Files Released
**Specifications:**
- `spec/2026-04-17/json-schema/schema.agentic_checkout.json`
- `spec/2026-04-17/json-schema/schema.cart.json`
- `spec/2026-04-17/json-schema/schema.delegate_authentication.json`
- `spec/2026-04-17/json-schema/schema.delegate_payment.json`
- `spec/2026-04-17/json-schema/schema.discount.json`
- `spec/2026-04-17/json-schema/schema.extension.json`
- `spec/2026-04-17/json-schema/schema.feed.json`
- `spec/2026-04-17/openapi/openapi.agentic_checkout.yaml`
- `spec/2026-04-17/openapi/openapi.agentic_checkout_webhook.yaml`
- `spec/2026-04-17/openapi/openapi.cart.yaml`
- `spec/2026-04-17/openapi/openapi.delegate_authentication.yaml`
- `spec/2026-04-17/openapi/openapi.delegate_payment.yaml`
- `spec/2026-04-17/openapi/openapi.feed.yaml`
- `spec/2026-04-17/openrpc/openrpc.agentic_checkout.json`
**Examples:**
- `examples/2026-04-17/discount-extension/README.md`
- `examples/2026-04-17/discount-extension/automatic-discount.json`
- `examples/2026-04-17/discount-extension/order-level-discount.json`
- `examples/2026-04-17/discount-extension/percentage-discount-with-allocations.json`
- `examples/2026-04-17/discount-extension/rejected-discount-code.json`
- `examples/2026-04-17/discount-extension/stacked-discounts.json`
- `examples/2026-04-17/examples.agentic_checkout.json`
- `examples/2026-04-17/examples.delegate_authentication.json`
- `examples/2026-04-17/examples.delegate_payment.json`
- `examples/2026-04-17/examples.feed.json`
- `examples/2026-04-17/examples.mcp.agentic_checkout.json`
- `examples/2026-04-17/examples.multi_item_checkout.json`
- `examples/2026-04-17/orders/digital-fulfillment.json`
- `examples/2026-04-17/orders/partial-fulfillment.json`
- `examples/2026-04-17/orders/refunded-order.json`
- `examples/2026-04-17/orders/shipped-order.json`
- `examples/2026-04-17/orders/simple-order.json`
## /changelog/unreleased/.gitkeep
```gitkeep path="/changelog/unreleased/.gitkeep"
```
## /changelog/unreleased/add-feed-update-id.md
## Feed Update ID on Upsert Products Response (SEP #259)
Add agent-generated feed_update_id to UpsertProductsResponse and per-product last_update_id for update version tracking and checkout price provenance.
### Changes
- **UpsertProductsResponse**: Added optional `feed_update_id` field — agent-generated version identifier for each accepted upsert
- **Product**: Added optional `last_update_id` field — tracks the feed_update_id of the most recent upsert that touched each product
### Files Updated
- `spec/unreleased/openapi/openapi.feed.yaml`
- `spec/unreleased/json-schema/schema.feed.json`
- `examples/unreleased/examples.feed.json`
### Reference
- Issue: #259
## /changelog/unreleased/add-meta-tsc-member.md
# Add Meta as TSC Member
**Added** -- Meta as a member of the ACP Technical Steering Committee
## Overview
Meta joins the ACP TSC to help advance the protocol’s development and enable merchants worldwide to participate in agentic commerce.
## Changes
- **MAINTAINERS.md**: Added Meta to the maintainers list
- **docs/governance.md**: Added Meta as Seat 3 on the TSC with @lhwa as the representative.
## /changelog/unreleased/add-upsert-products-response-schema.md
## Add UpsertProductsResponse to feed JSON Schema bundle
**Fixed** an inconsistency between the feed OpenAPI spec and the JSON Schema bundle. `UpsertProductsResponse` is defined in `openapi.feed.yaml` and referenced as the `200` response schema for `PATCH /feeds/{id}/products`, but it was missing from `schema.feed.json`. Tools that consume the JSON Schema bundle (validators, code generators, language SDKs) had no definition for the upsert acknowledgement shape and could not validate or generate types for it.
The companion `UpsertProductsRequest` schema was already mirrored in both files; the response counterpart was not. The RFC's "Required Spec Updates" section in `rfcs/rfc.product_feeds.md` §9 already lists the upsert response schema among the required JSON Schema additions, so this change completes that requirement rather than introducing new surface.
### Changes
- Added `UpsertProductsResponse` definition to the feed JSON Schema bundle, mirroring the OpenAPI shape (`id: string`, `accepted: boolean`)
- Added an `upsert_products_response` example to the feed examples file
- Named the schema in §5.4 of the Product Feeds RFC so the response shape is documented as a reusable type
### Files Updated
- `spec/unreleased/json-schema/schema.feed.json`
- `examples/unreleased/examples.feed.json`
- `rfcs/rfc.product_feeds.md`
### Reference
- Original Feed API PR: #190
- RFC §9 (Required Spec Updates) lists "upsert response schemas" among the JSON Schema additions required for the Feed API
## /changelog/unreleased/document-intervention-required-error-code.md
# Document `intervention_required` error code
**Fixed** – added `intervention_required` to the documented MessageError codes in `rfc.agentic_checkout.md`.
PR #118 added `intervention_required` to the MessageErrorCode enum in both OpenAPI and JSON Schema, but the RFC was not updated. This adds the missing documentation: when the code is used, how it relates to `capabilities.interventions`, and how it differs from `requires_3ds`.
**Files changed:** `rfcs/rfc.agentic_checkout.md`
## /changelog/unreleased/fix-address-company-description.md
## Fix Address.company field description
Corrected a copy-paste error where the `company` field in the `Address` schema had the description "Postal or ZIP code" (duplicated from the `postal_code` field above it). Fixed to "Company or organization name".
### Changes
- Fixed incorrect description on `Address.company` in the unreleased JSON Schema
### Files Updated
- `spec/unreleased/json-schema/schema.agentic_checkout.json`
## /changelog/unreleased/fix-delegate-payment-error-examples.md
## Fix delegate_payment error response example shape
Error response examples in `spec/unreleased/openapi/openapi.delegate_payment.yaml` wrapped the body in `{ "error": { ... } }`. The `Error` schema is `additionalProperties: false` with `type`, `code`, `message` required at the top level, and the agentic_checkout RFC §3 documents the flat shape ("Error Shape (flat)"). None of the 9 error examples validated against the schema they reference.
### Changes
- Removed the `error:` wrapper from all 9 error response examples (400, 401, 409, 422, 429, 500, 503).
### Out of scope
`type`/`code` values left unchanged. The `Error` enum gaps for 401/500/503 are handled in #161.
### Files Updated
- `spec/unreleased/openapi/openapi.delegate_payment.yaml`
## /changelog/unreleased/fix-message-type-examples.md
## Fix MessageInfo, MessageWarning, and MessageError examples
Corrected examples for all three message types in the unreleased OpenAPI spec and JSON Schema bundle. The examples introduced in #140 used fields that do not exist in any of the schemas (`id`, `message`, `display_context`) and omitted all required fields (`type`, `content_type`, `content`). Because all three schemas declare `additionalProperties: false`, the previous examples would fail schema validation in any tool that validates inline OpenAPI examples (e.g. Spectral, Redocly, openapi-generator).
### Changes
- `MessageInfo` example: replaced `id`/`message`/`display_context` with valid `type`/`content_type`/`content` fields
- `MessageWarning` example: replaced `id`/`message` with valid `type`/`content_type`/`content` fields; retained valid `code` and `param`
- `MessageError` example: replaced `id`/`message` with valid `type`/`content_type`/`content` fields; retained valid `code` and `param`
### Files Updated
- `spec/unreleased/openapi/openapi.agentic_checkout.yaml`
- `spec/unreleased/json-schema/schema.agentic_checkout.json`
## /changelog/unreleased/fix-refund-amount-example-type.md
## Fix Refund amount example type in 2026-01-30 webhook spec
The `order_updated` example in `openapi.agentic_checkout_webhook.yaml` showed `amount: "1.00"` (string) for a refund. The `Refund.amount` schema in the same file defines `amount` as an `integer` in minor units (e.g. `100` cents for `$1.00`). The example contradicted the schema and could confuse implementers and tooling.
### Changes
- Corrected the refund example to use `amount: 100` (integer minor units, consistent with the schema and other examples in the file such as the `total` line item at line 117)
### Files Updated
- `spec/2026-01-30/openapi/openapi.agentic_checkout_webhook.yaml`
### Reference
- Issue: #220
## /changelog/unreleased/fulfillment-details-on-complete.md
# Unreleased Changes
## Fulfillment Details on Checkout Complete (SEP #196)
Add fulfillment_details to CheckoutSessionCompleteRequest, enabling agents to batch contact-only changes with payment submission.
### Changes
- **CheckoutSessionCompleteRequest**: Added optional `fulfillment_details` field
### Benefits
- **Eliminates unnecessary round trip**: Contact-only changes (name, email, phone) no longer require a separate update call before complete
- **Reduced checkout latency**: One API call instead of two at the most critical moment in the checkout flow
- **Address safeguard**: Address changes trigger 409 Conflict, forcing the agent back to the update-then-complete flow
## /changelog/unreleased/intent-traces-examples.md
### Added
- Intent traces examples covering all 10 reason codes: price_sensitivity, shipping_cost, shipping_speed, product_fit, trust_security, returns_policy, payment_options, comparison, timing_deferred, other
- Minimal trace example (reason_code only)
- Empty cancel request example (backward compatibility)
- Malformed trace error response example
## /changelog/unreleased/order-schema-alignment.md
## Order Schema: Post-Checkout Alignment
### Motivation
Sellers send order events — shipping, refunds, cancellations — to platforms, which fan them
out to agents. The order model needs clear, unambiguous semantics to support this pipeline
end-to-end.
This change addresses five categories of misalignment in the order schema:
1. **Quantity model was too narrow.** The 2-field model (`ordered`/`shipped`) couldn't represent
cancellations or returns (no way to say "3 ordered, 1 canceled, 2 shipped"). The 3-field
model (`ordered`/`current`/`fulfilled`) tracks the full lifecycle.
2. **Status values were shipping-centric.** `shipped` and `delivered` as line item statuses
don't apply to pickup or digital fulfillment. The new values (`fulfilled`, `removed`) are
fulfillment-type-agnostic and derived directly from the quantity fields.
3. **Order status overloaded "fulfilled".** Using `fulfilled` at both the order and line item
level would create confusion: `LineItem.status = "fulfilled"` means the seller has dispatched
the item (quantity-derived), while at the order level it would mean everything has been
received by the buyer. We use `completed` at the order level to avoid this ambiguity.
4. **Fulfillment event types had gaps.** Missing `canceled` and `undeliverable` forced
merchants to abuse `failed_attempt` for terminal failure states. `returned` was renamed to
`returned_to_sender` for precision.
5. **Adjustment types had redundancy.** `refund`/`partial_refund` is a false distinction (the
amount already tells you). `store_credit` was jargon-heavy. `chargeback` is a subtype of
`dispute`. `price_adjustment` was missing entirely.
### Breaking Changes
- **LineItem quantity**: 2-field model (`ordered`/`shipped`) → 3-field model
(`ordered`/`current`/`fulfilled`). `current` is now required. `fulfilled` replaces `shipped`
and applies to all fulfillment types (shipping, pickup, digital).
- **LineItem status**: `[processing, partial, shipped, delivered, canceled]` →
`[processing, partial, fulfilled, removed]`. Status is now deterministically derived from
quantity fields: `removed` if `current==0`, `fulfilled` if `fulfilled==current`, `partial` if
`0 < fulfilled < current`, `processing` otherwise.
- **Order status**: `delivered` → `completed`. The term `completed` avoids confusion with
`LineItem.status = "fulfilled"` (which triggers at dispatch time, not delivery time).
- **FulfillmentEvent type**: `returned` → `returned_to_sender`. Added `canceled` and
`undeliverable`.
- **Adjustment type**: `partial_refund` merged into `refund` (distinguish by amount).
`store_credit` → `credit`. `chargeback` merged into `dispute`. Added `price_adjustment`.
- **Open enums**: All order-related status and type fields are now open enums (`type: string`
with defined values in descriptions) rather than closed enums. Implementations MUST accept
unrecognized values gracefully. This enables forward and backward compatibility as the
protocol evolves without requiring schema-breaking changes for new values.
### Semantic model
The order schema now has distinct terminology at each level to avoid ambiguity:
| Level | Field | Values | Meaning |
|-------|-------|--------|---------|
| Order | `status` | `completed` | Buyer has received everything |
| LineItem | `status` | `fulfilled` | Seller's obligation met for this item (dispatched) |
| Fulfillment | `status` | `delivered` | Physical/digital delivery confirmed (unchanged) |
| FulfillmentEvent | `type` | `delivered` | The delivery event occurred (unchanged) |
### Files Changed
- `spec/*/json-schema/schema.agentic_checkout.json`
- `spec/*/openapi/openapi.agentic_checkout.yaml`
- `spec/*/openapi/openapi.agentic_checkout_webhook.yaml`
- `examples/*/orders/*.json`
- `rfcs/rfc.orders.md`
## /changelog/unreleased/stale-pr-reminder.md
# Add Stale PR Reminder Workflow
**Added** -- Stale PR reminder via GitHub Actions
## Overview
Adds a manually-triggered workflow using `actions/stale@v10` to identify and remind authors of PRs inactive for 90+ days. Comments are posted as
`github-actions[bot]`. Includes a dry-run mode for previewing affected PRs before sending reminders. No auto-close behavior — closing remains a manual maintainer
decision.
## Changes
- **Workflow**: Added `stale-reminder.yml` with `workflow_dispatch` trigger and `dry_run` input toggle
- **Label**: Requires new `stale` label (gray `#CFD3D7`, description: "PR inactive for 90+ days")
- **Auto-reset**: Any PR activity (comment, commit, or review) removes the `stale` label and resets the staleness clock
- **Scope**: PRs only — issues are excluded; draft PRs are exempt
### Files Added
- `.github/workflows/stale-reminder.yml`
## /changelog/unreleased/suggested-pricing.md
# Unreleased Changes
## Suggested Pricing on Checkout Create (SEP #197)
Add suggested_price to Item on CheckoutSessionCreateRequest, enabling agents to communicate price provenance to sellers for catalog price matching.
### Changes
- **PriceSource**: New schema with feed_id (required), channel, feed_update_id, and updated_at fields
- **SuggestedPrice**: New schema with amount, structured source (PriceSource), and observed_at fields
- **Item**: Added optional `suggested_price` field
### Benefits
- **Price consistency**: Sellers can honor catalog prices displayed to buyers, reducing checkout price discrepancies
- **Structured provenance**: Feed ID, channel, update version, and timestamp enable sellers to validate price claims against specific feed updates
- **Seller-controlled policy**: Time window and source verification are seller-defined, not protocol-mandated
## /docs/governance.md
# Agentic Commerce Protocol (ACP) Governance
## Overview
The **Agentic Commerce Protocol (ACP)** is an interaction model and open
standard for connecting buyers, their AI agents, and businesses to complete
purchases seamlessly. ACP's governance is designed to ensure clear
decision-making, transparent evolution of the specification, and a stable
foundation for long-term stewardship as the protocol matures.
---
## Shared Principles
ACP exists to promote open, secure, and interoperable commerce between agents,
payment providers, and sellers. All TSC members, including the Founding
Maintainers, commit to upholding the following principles. These serve as the
foundation for all governance decisions and the basis under which the Founding
Maintainers' veto authority may be exercised as a last resort.
1. **Mission Protection:** Decisions must not materially undermine ACP's core
mission of advancing open, secure, and interoperable agent-driven commerce.
2. **Neutrality Protection:** Decisions must not privilege a specific vendor,
platform, or payment provider in a way that harms neutrality.
3. **Security and Safety:** Changes must not introduce systemic security, fraud,
or safety risks.
4. **Protocol Integrity:** Changes must not fracture the standard or create
incompatible forks.
5. **Considered Decision-Making:** Particularly contentious decisions need more
time to bake and gain community consensus, even if they may pass the TSC.
---
## The Technical Steering Committee (TSC)
The TSC is the central governing body responsible for the protocol's evolution,
specification maintenance, and technical integrity. It serves as the
decision-making authority for all matters relating to the ACP standard.
### Composition and Structure
The TSC has up to 7 seats. Each seat is held by one organization, including
OpenAI and Stripe.
Seats are filled incrementally as qualified contributors emerge.
### Membership Criteria
TSC seats are appointed by the Founding Maintainers (OpenAI and Stripe) based
on the following criteria:
1. **Shared Vision:** A demonstrated commitment to advancing agent-driven
commerce and taking the ACP standard to the next level. Candidates must align
with ACP's mission and long-term direction.
2. **Contributions:** A visible track record of meaningful contributions to the
ACP repository. This includes authoring or co-authoring merged Pull Requests,
proposing Specification Enhancement Proposals (SEPs), and/or actively
participating in discussions by commenting, reviewing, and expressing
technical opinions.
3. **Time Commitment:** Members are expected to dedicate a few hours per week to
TSC responsibilities and to actively engage in weekly meetings.
The TSC reviews membership quarterly.
### Joining the TSC
Organizations interested in joining the TSC should reach out to anyone from the
TSC or Founding Maintainers for more details on the process.
### Member Expectations
- Dedicate a few hours weekly to the review of Pull Requests and SEPs.
- Actively participate in weekly TSC meetings.
- Drive discussions and provide technical guidance across official community
channels (Discord, GitHub).
- Guide and support Domain Working Groups (DWGs) where relevant.
### Strategic Value of Membership
- Direct influence on the standards governing how AI agents interact with global
commerce.
- Member organization logos featured on the ACP homepage and official
documentation.
- Members may formally use the title: "Member of the ACP Technical Steering
Committee."
- Weekly collaboration alongside technical leads from the ACP ecosystem.
### Current TSC Members
| Seat | Organization | Representative(s) |
|------|-------------|-------------------|
| 1 | OpenAI | aravindrao-openai |
| 2 | Stripe | prasad-stripe |
| 3 | Meta | lhwa |
---
## Domain Working Groups (DWGs)
Domain Working Groups are community-driven groups focused on adapting and
extending ACP for specific industry verticals or technical domains (e.g.,
Travel, Fitness & Wellness, Grocery Delivery, Donations).
### Formation
DWGs operate outside the core TSC but require formal recognition to carry
governance weight. Any group of contributors may self-organize around a domain,
but to be recognized as an official DWG they must:
- Include members from at least two distinct organizations.
- Submit a proposal to the TSC outlining the group's scope, goals, and initial
membership.
The TSC votes to approve or reject the proposal by simple majority.
### Autonomy
Once officially recognized, a DWG operates with a high degree of autonomy. Each
group defines its own cadence, operating norms, and the specific problems it
aims to address. Leadership within the group is self-organizing — domain experts
are expected to emerge naturally based on the work itself.
### Relationship to the TSC
- DWGs are expected to surface new features or changes back to the TSC as SEPs,
which follow the standard SEP review and voting process.
- For standard PRs within a DWG's domain, one approval from a recognized DWG
member counts toward the two approvals required for merging.
### Strategic Value of DWG Membership
- Shape how ACP is applied within your industry, ensuring the standard meets the
real-world needs of your domain.
- Establish your organization as a recognized domain authority within the ACP
ecosystem.
- DWG member organizations are listed on the ACP website under their respective
working group.
- Gain direct input into SEPs that affect your vertical before they reach the
broader TSC vote.
- Collaborate with peers across your industry to solve shared challenges around
agent-driven commerce.
---
## The Technical Review Process
### Standard Pull Requests (Non-SEP)
Regular PRs that do not require a SEP can be approved by any member of the TSC.
Merging requires a minimum of two approvals from TSC members. One approval from
a recognized DWG member counts toward the two approvals required for merging PRs
within that group's domain.
### Specification Enhancement Proposals (SEPs)
SEPs are the mechanism for proposing significant changes to the ACP
specification. All SEPs are decided by a vote of the TSC. Refer to the
[SEP Guidelines](./sep-guidelines.md).
The SEP lifecycle:
1. **Sponsorship:** Every SEP must be sponsored by a TSC member to proceed. The
sponsor is responsible for shepherding the proposal through the review
process.
2. **Community Review:** Once sponsored, a mandatory 7-business-day public
review window is opened for feedback and technical scrutiny. This review
period must span across at least one instance of the weekly TSC meeting.
3. **TSC Weekly Meeting:** The TSC holds a weekly 30-minute meeting dedicated to
discussing, debating, and voting on pending SEPs. Members who cannot attend
may express their votes or feedback asynchronously before or after the
meeting.
4. **Voting:** SEPs are adopted or rejected by a simple majority vote (50%+1) of
the TSC.
### Types of Changes
There are three categories of changes within the ACP project:
1. **Major Changes (Require SEPs)**: Any substantial, complex or controversial
change to the protocol shall be considered a Major Change. These must follow
the SEP process described above. Some examples of Major Changes:
- Adding, modifying, or removing features in the specification (e.g., new API
endpoints, messages, or data structures).
- Significant changes to how the specification is defined, presented, or
validated.
- Breaking changes that are not backwards-compatible.
- Complex or controversial topics that require community discussion.
2. **Process Changes (Require SEPs)**: Adjustments to how the project itself is
governed (including amending this document) or its processes shall be
considered a Process Change. This includes updates to governance roles or
responsibilities, decision-making rules, contributor processes, or other
structural revisions. These are non-technical but still significant changes
that also require a SEP to ensure transparency and consensus.
3. **Minor Changes (Do Not Require SEPs)**: Minor or operational updates that do
not materially alter the protocol nor governance structure do not require
SEPs. These may be merged following the standard pull request process with
two approvals. Some examples of Minor Changes:
- Documentation fixes or editorial clarifications
- Simple bugfixes
- Minor enum or data changes to support additional participants
- Tooling improvements
**Pull Request Templates**: Contributors should use the appropriate PR template
when submitting changes:
- Major and Process Changes: Use [sep-proposal.md](../.github/PULL_REQUEST_TEMPLATE/sep-proposal.md)
- Minor Changes: Use [minor-improvement.md](../.github/PULL_REQUEST_TEMPLATE/minor-improvement.md)
- Administrative Changes (admins only): Use [admin.md](../.github/PULL_REQUEST_TEMPLATE/admin.md) — for CLA signatory additions, Schedule A updates, and other corporate housekeeping. Title must start with `ADMIN:`.
- Releases (admins only): Use [release.md](../.github/PULL_REQUEST_TEMPLATE/release.md) — for promoting unreleased specs, examples, and changelog entries to a dated version. Title must start with `RELEASE:`.
---
## The Founding Maintainers
OpenAI and Stripe are the Founding Maintainers of ACP. Their role is to steward
the early growth of the protocol and its governance structures.
### Responsibilities
- Appoint and remove TSC members based on the published membership criteria.
- Ensure the protocol's long-term coherence, security, and alignment with its
founding mission.
- Each holds one seat on the TSC with the same voting rights as any other
member.
### Governance Evolution
The Founding Maintainers' appointment authority is intended as a transitional
mechanism for the protocol's early stages. As the TSC matures and the
contributor base grows, this structure is expected to evolve toward broader
participation and shared ownership of governance decisions.
### Founding Maintainers' Reserve Authority
In order to safeguard the core principles of ACP — including neutrality,
openness, and the integrity of the standard — the Founding Maintainers (OpenAI
and Stripe) reserve a limited veto authority over TSC decisions. This authority
exists solely to protect the protocol from outcomes that could compromise its
foundational mission, such as changes that disproportionately favor a single
member, introduce conflicts of interest, or undermine the trust and fairness the
ecosystem is built on. This veto is expected to be exercised in extremely rare
situations and is not intended for day-to-day governance. The Founding
Maintainers remain committed to working within the TSC process, and any exercise
of this authority will be accompanied by a clear, written explanation shared
with the full TSC.
---
## Future Evolution and Neutral Governance
The Founding Maintainers recognize the long-term goal of transitioning ACP
governance to a neutral foundation, similar to models used by the Linux
Foundation or OpenJS Foundation. Before a full transition to a neutral
foundation, the project will first formalize the creation and operation of the
Maintainers tier. This intermediate phase will expand representation, establish
voting and sponsorship mechanisms, and help test shared governance models prior
to establishing a permanent foundation. A full transition to a neutral
foundation will be taken up by the Founding Maintainers when:
- A healthy and active community has developed under the stewardship of the
Maintainers tier, demonstrating consistent participation and collaboration;
- ACP achieves broad adoption across independent stakeholders;
- Sufficient community and institutional participation exists to sustain
multi-party governance; and
- Legal and structural frameworks are in place to ensure neutrality and
continuity.
---
## Frequently Asked Questions
**Q: What is expected of organizations in a TSC member role?**
A: The primary expectation is active contribution to the development and success
of the protocol. This means authoring and reviewing PRs and SEPs, participating
in meetings, and helping advance the standard. This expectation applies equally
to all participants, regardless of size, market position, or existing
relationships with other contributors.
**Q: Can TSC members or contributors also participate in other competing or complementary protocols?**
A: Yes. There are no restrictions against working with other protocols.
Participants remain free to engage with any competing or complementary protocols
simultaneously.
**Q: What does "launch" mean for the TSC?**
A: Launch is the public announcement of the ACP governance model along with the
initial set of TSC members. The governance structure goes into effect at that
point, though not all 7 seats need to be filled. Remaining seats will be filled
over time as contributors meet the membership criteria.
**Q: How many TSC seats will be filled at launch?**
A: The exact number will depend on how many partners meet the membership
criteria ahead of the launch date.
**Q: What if a partner is hesitant to contribute because there's no guarantee of a TSC seat?**
A: We understand this is a chicken-and-egg situation. Let's work closely with
interested partners, make it clear that we want them at the table, and help them
land their first contributions. The goal is to onboard committed partners, not
to gatekeep.
**Q: Does the TSC only have room for large, well-known companies?**
A: Having recognizable names on the TSC matters for the credibility and
visibility of the standard, but the TSC is not limited to big logos. Seats are
earned through contributions and commitment. Smaller organizations that are
making strong contributions will be considered on a case-by-case basis. And even
outside the TSC, there are meaningful leadership opportunities within Domain
Working Groups where any contributor can make a significant impact.
**Q: How are contributions and proposals prioritized?**
A: Contributions that advance and expand protocol usage are prioritized based on
transparent, objective criteria. The protocol takes a strong stance on economic
incentives, user experience, and fraud prevention. Governance decisions are
applied consistently across all participants — no single organization receives
preferential treatment in how proposals are evaluated or adopted.
**Q: Can a TSC member lose their seat?**
A: Yes. Membership is reviewed quarterly. If a member organization is no longer
meeting the expectations: not engaging in meetings, not reviewing PRs or SEPs,
or not actively contributing — the TSC will first reach out and ask the
organization to re-commit. If engagement doesn't improve, the TSC may revisit
their seat. Members may also choose to step down voluntarily if their priorities
shift. The intent is not to be punitive, but to ensure every seat is held by
someone who is actively driving the standard forward.
**Q: Can anyone start a Domain Working Group?**
A: Yes, any group of contributors can self-organize around a domain. However, to
be officially recognized as a DWG — and for their approvals to carry weight in
the review process — the group must include members from at least two distinct
organizations and submit a proposal to the TSC for approval.
**Q: Can an organization hold a seat on both the TSC and a DWG?**
A: Yes. TSC membership and DWG participation are independent. An organization on
the TSC can also have representatives active in one or more DWGs. In fact, this
is encouraged — it helps ensure alignment between the core governance and
domain-specific work.
**Q: What if two DWGs propose conflicting changes to the specification?**
A: All changes to the specification ultimately go through the SEP process and
are voted on by the TSC. If two DWGs propose conflicting approaches, the TSC
will facilitate discussion between the groups during the review period and the
weekly meeting. The TSC vote determines which direction is adopted, ensuring
consistency across the protocol.
**Q: Who represents an organization on the TSC — is it always the same person?**
A: Each organization holds one seat, but the individual representing that
organization may change. It is up to the member organization to designate their
representative. We ask that organizations maintain consistency where possible so
that context and relationships are preserved, but understand that personnel
changes happen.
**Q: Is there a cost or fee associated with joining the TSC or a DWG?**
A: No. There are no membership fees. Participation in the TSC and DWGs is earned
through contributions and commitment, not financial investment. The only cost is
the time and effort to actively engage.
**Q: What happens if the TSC can't reach a majority on a SEP?**
A: Every SEP is decided by a simple majority vote. If a proposal doesn't pass by
(50%+1) vote, the author and sponsor are welcome to revise it based on the
feedback and resubmit.
**Q: Can someone contribute to ACP without being on the TSC or a DWG?**
A: Absolutely. ACP is an open standard and anyone can contribute by opening Pull
Requests, proposing SEPs, participating in discussions on GitHub and Discord, or
building implementations. As long as the Contributor License Agreement (CLA) is
signed and the code of conduct is followed, contributions are welcome from the
entire community. The TSC and DWGs are governance structures for decision-making,
not gatekeepers of contribution.
**Q: How does the TSC handle disagreements between members?**
A: All major decisions go through the SEP process with a mandatory
7-business-day review period and a weekly meeting for discussion. This gives
every member time to voice concerns and work through differences. When it comes
to a vote, a simple majority decides. The process is designed to encourage open
debate while keeping things moving forward.
**Q: What behavior is not allowed within ACP governance?**
A: ACP governance is built on mutual respect and fair play. The following are not
permitted:
- Using ACP channels or governance forums for product marketing or
self-promotion.
- Making direct comparisons between competing products or services within ACP
discussions.
- Pushing or pressuring the direction of the protocol to disproportionately
favor any single member or organization.
- Blocking or stalling proposals to disadvantage a competitor.
- Using a TSC or DWG seat to gain unfair competitive intelligence.
- Misrepresenting ACP affiliation or governance roles for commercial advantage.
All participants are expected to engage in good faith, with the shared goal of
advancing the standard for the benefit of the entire ecosystem. A revised code
of conduct and detailed guidelines tailored for the TSC will be published ahead
of launch.
**Q: Under what circumstances would the Founding Maintainers use their veto?**
A: The veto is a last resort, reserved for situations that threaten the
foundational principles of the protocol. These include: decisions that materially
undermine ACPs core mission, changes that privilege a specific vendor to platform
at the expense of neutrality, changes that introduce systemic security, fraud or
safety risks, changes that fracture the standard into incompatible forks and
particularly contentious decisions that need more time to make and gain broader
consensus, even if they have enough votes to pass in TSC
**Q: Can the veto be used to push through a change that the TSC has rejected?**
A: No. The veto can only be used to block a change, never to override the TSC
and force one through. If the Founding Mainterners want to see a change adopted,
they advocate for it through the same TSC process as everyone else.
**Q: What does a veto scenario look like in practice?**
A: For illustrative purposes: imagine the TSC adopts a change that requires all
ACP implementations to depend on a proprietary API controlled by a single
company. This would compromise the neutrality of the protocol and could be
vetoed. Or suppose a specification change is adopted that exposes agents
directly to raw payment credentials, significantly increasing PCI scope for all
participants, that's a systematic safety risk worth blocking. These are extreme
scenarios, and the expectation is that most concerns like these would be resolved
through normal TSC discussion well before a veto is ever considered.
**Q: What happens after a veto is exercised?**
A: A veto does not kill a proposal permanently. It pauses the change and sends
it back to the TSC for further discussion. The Founding Maintainers must provide
a clear, written explanation for the veto. The proposal author and sponsor are
welcome to revise and resubmit the proposal based on the feedback. The goal is
to reach a better outcome, not to shut down the conversation.
**Q: Does the veto authority apply to all TSC decisions or only SEPs?**
A: It applies to only SEPs. It does not apply to routine operational decisions,
standard PRs, DWG formation or day-to-day governance matters. Those remain fully
within the TSC's authority.
## /docs/mcp-binding.md
# MCP Transport Binding for Agentic Checkout
This document specifies the Model Context Protocol (MCP) binding for the
Agentic Commerce Protocol checkout API. It defines how ACP's REST operations
map to MCP tools over JSON-RPC 2.0.
## Overview
MCP is a second transport binding for ACP, alongside REST. It allows AI agents
to invoke checkout operations as native MCP tool calls instead of constructing
HTTP requests. The binding is purely additive — the REST API, JSON Schemas, and
protocol semantics are unchanged.
All domain schemas are reused from the existing JSON Schema bundle
(`schema.agentic_checkout.json`). The OpenRPC schema at
`spec/unreleased/openrpc/openrpc.agentic_checkout.json` references these via
`$ref`. No domain types are duplicated. These references use relative file
paths for spec-time validation. Implementers **MUST** resolve and bundle all
`$ref` targets before serving tool schemas to MCP clients.
### Transport
ACP MCP servers use JSON-RPC 2.0 over MCP's
[Streamable HTTP](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#streamable-http)
transport. The server exposes a single HTTP endpoint (e.g., `/mcp`) that is
separate from the REST endpoint paths.
### Discovery
ACP provides a well-known discovery document (`/.well-known/acp.json`) that
advertises the seller's capabilities, supported API versions, and available
transports. When a seller supports MCP, the `transports` array in the
discovery document includes `"mcp"`. Agents can check this field to determine
whether to use REST or MCP before making any API calls.
Capability negotiation for individual sessions still happens inline (the agent
sends `capabilities` in the create request, the merchant responds with the
negotiated set). The discovery document provides the seller's capabilities
only.
The required `meta.api_version` field presumes the agent knows a compatible
API version before its first tool call. Agents can obtain this from the
`protocol.supported_versions` array in `/.well-known/acp.json`, or from
merchant documentation.
## Tool Definitions
Each ACP REST operation maps to one MCP tool:
| MCP Tool | REST Operation | Description |
| :--------------------------- | :---------------------------------------------- | :------------------------------------------------------ |
| `create_checkout_session` | `POST /checkout_sessions` | Create a checkout session |
| `get_checkout_session` | `GET /checkout_sessions/{id}` | Retrieve the current state of a checkout session |
| `update_checkout_session` | `POST /checkout_sessions/{id}` | Update items, fulfillment details, or selected options |
| `complete_checkout_session` | `POST /checkout_sessions/{id}/complete` | Submit payment and finalize the order |
| `cancel_checkout_session` | `POST /checkout_sessions/{id}/cancel` | Cancel a session, optionally with an intent trace |
All 5 operations are exposed as MCP **Tools**, not Resources. Checkout sessions
are transient, agent-driven objects — the agent creates, mutates, and completes
them in a tight sequence. MCP Resources are better suited for future
capabilities like product catalog access or order history, where URI-based
addressing and subscriptions make more sense.
## Argument Structure
Every tool call uses a consistent three-field argument structure:
```json
{
"meta": { ... },
"id": "...",
"payload": { ... }
}
```
| Field | Purpose | Present on |
| :-------- | :----------------------------------- | :-------------------------------------------- |
| `meta` | Protocol metadata (from HTTP headers)| All tools (required) |
| `id` | Resource identifier (from path param)| get, update, complete, cancel (required) |
| `payload` | Domain data (from request body) | create, update, complete (required); cancel (optional); get (absent) |
When `payload` is marked optional (e.g., `cancel_checkout_session`), omitting
the field entirely is valid. Servers **MUST NOT** require `payload: null`.
### Why `payload`?
Wrapping the domain request body in a `payload` field means the OpenRPC schema
can `$ref` directly to existing ACP request schemas without composition:
| Tool | `payload` schema reference |
| :--------------------------- | :---------------------------------- |
| `create_checkout_session` | `CheckoutSessionCreateRequest` |
| `update_checkout_session` | `CheckoutSessionUpdateRequest` |
| `complete_checkout_session` | `CheckoutSessionCompleteRequest` |
| `cancel_checkout_session` | `CancelSessionRequest` |
| `get_checkout_session` | *(no payload)* |
This means the `payload` contents match the existing REST request body schemas
exactly. No schema duplication or composition is needed.
## Header Mapping
ACP uses several protocol-level HTTP headers (see
[required headers](https://www.agenticcommerce.dev/docs/reference/checkout#required-headers)).
These map to fields in the `meta` object:
| HTTP Header | MCP Field | Required | Notes |
| :----------------- | :--------------------- | :------- | :--------------------------------------------- |
| `API-Version` | `meta.api_version` | Yes | Date string, e.g. `"2026-01-30"` |
| `Idempotency-Key` | `meta.idempotency_key` | No | Recommended for create and complete |
| `Request-Id` | `meta.request_id` | No | Correlation ID |
| `User-Agent` | `meta.user_agent` | No | Agent identification |
| `Accept-Language` | `meta.accept_language` | No | Locale preference |
| `Signature` | `meta.signature` | No | Request signing |
| `Timestamp` | `meta.timestamp` | No | Request signing timestamp (RFC 3339) |
| `Authorization` | *(out-of-band)* | — | Handled via MCP server auth, not per-request |
The `Authorization` header is intentionally excluded from `meta`. MCP servers
handle authentication at the connection level (via server configuration or
OAuth), not per tool call. Including bearer tokens in tool arguments would
expose them in tool schemas visible to LLMs.
The `meta` object is extensible (`additionalProperties: true` in the OpenRPC
schema). Servers **SHOULD** ignore unrecognized `meta` fields to allow
forward-compatible header additions without requiring a schema version bump.
If future ACP versions introduce new protocol-level headers, corresponding
`meta` fields SHOULD be added to the MCP binding.
## Response Mapping
Successful REST responses (2xx) map to JSON-RPC `result` containing the same
response body. The full `CheckoutSession` or `CheckoutSessionWithOrder` object
is returned as-is:
```json
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"id": "cs_abc123",
"status": "incomplete",
"line_items": [ ... ],
"totals": [ ... ],
"capabilities": { ... },
"messages": [],
"links": []
}
}
```
## Error Handling
REST error responses (4xx, 5xx) map to JSON-RPC `error` objects. ACP's `Error`
schema (`type`, `code`, `message`, `param`) is placed in the JSON-RPC error's
`data` field:
```json
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32000,
"message": "Checkout session not found",
"data": {
"type": "invalid_request",
"code": "session_not_found",
"message": "Checkout session not found",
"param": "id"
}
}
}
```
All ACP errors use JSON-RPC error code `-32000` (server error) uniformly. The
useful error semantics are in ACP's `Error` object in `data` -- consumers
**MUST** inspect `data.type` and `data.code` to understand the error, not the
JSON-RPC error code. Clients that display or log JSON-RPC error codes without
inspecting `data` will see a uniform `-32000` for all ACP errors. This is a
known tradeoff: the JSON-RPC error code layer is intentionally thin, and the
ACP error model in `data` carries the actionable semantics.
The exception is `-32602` (Invalid params), which is reserved for malformed
requests that fail at the JSON-RPC level before reaching ACP business logic
(e.g., missing required fields in the JSON-RPC envelope itself).
### ACP Error Types in `data`
| `data.type` | Meaning |
| :----------------------- | :------------------------------------------------ |
| `invalid_request` | Malformed request, missing required fields |
| `request_not_idempotent` | Idempotency violation |
| `processing_error` | Unexpected server-side failure |
| `service_unavailable` | Temporary unavailability |
### Authentication and Authorization Errors
Authentication and authorization failures from the upstream merchant REST API
(HTTP 401, 403) are surfaced as JSON-RPC errors with code `-32000`. The
`data.type` will be `invalid_request` until ACP introduces dedicated
authentication/authorization error types in the core `Error` schema. For
example, a 403 from the merchant propagates as:
```json
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32000,
"message": "Unauthorized access to checkout session",
"data": {
"type": "invalid_request",
"code": "forbidden",
"message": "Unauthorized access to checkout session"
}
}
}
```
MCP server-level auth failures (e.g., invalid OAuth token to the MCP endpoint
itself) are outside the ACP error model and should use standard MCP/JSON-RPC
error handling.
## Capability Negotiation
Unchanged from REST. The `capabilities` object is a field inside `payload` for
`create_checkout_session` (just as it is in the REST request body), and the
negotiated capabilities appear in the response `CheckoutSession` object. The
protocol flow is identical to REST; only the wire format differs.
## Conformance
A conforming ACP MCP server **MUST**:
1. Implement JSON-RPC 2.0 over MCP Streamable HTTP transport.
2. Expose all 5 checkout tools defined in this specification.
3. Accept the `meta` object and apply its fields as protocol-level metadata.
4. Accept the `payload` object and treat its contents as the ACP request body.
5. Return ACP `CheckoutSession` / `CheckoutSessionWithOrder` objects in
JSON-RPC `result`.
6. Return ACP `Error` objects in JSON-RPC `error.data`.
7. Validate tool inputs against ACP JSON Schemas.
## Scope
This binding covers the Agentic Checkout API surface only. ACP also defines a
Delegate Payment API (`POST /agentic_commerce/delegate_payment`) that agents
use to obtain payment tokens from payment providers. Since delegate payment is
a separate API surface served by a different party (payment provider, not
merchant), it should be addressed in a follow-up SEP.
This is the first MCP binding for ACP. A follow-up SEP will define the MCP
binding for the Delegate Payment API to complete the full agent checkout flow
over MCP.
## Security Considerations
Authentication tokens are not included in tool arguments by design. MCP tool
schemas are visible to the LLM during planning, so keeping authentication at
the MCP server configuration level avoids token exposure in context windows.
Request signing (`meta.signature`, `meta.timestamp`) and idempotency
(`meta.idempotency_key`) are preserved from the REST binding with identical
semantics.
### Proxy Trust Boundary
When an MCP server operates as a proxy to a merchant's REST API, the proxy
processes all tool arguments including payment instrument tokens in
`complete_checkout_session`. Proxy operators that handle payment data
**SHOULD** evaluate PCI DSS scope requirements. Co-locating the MCP server
with the REST backend avoids introducing a new intermediary in the payment
data flow. Third-party hosted proxies that inspect or log payment payloads may
be in PCI scope even if they do not store card data.
## /docs/operating-model.md
# TSC Operating Model
This document defines the day-to-day operating cadence of the ACP Technical
Steering Committee. It complements the [Governance Model](./governance.md) and
[SEP Guidelines](./sep-guidelines.md).
---
## Weekly Meeting
- **Day:** Thursday (time TBD)
- **Duration:** 30 minutes
- **Who:** All TSC member organizations must attend or send a designated
representative.
- **Agenda:** Published to `#technical-steering-committee` on Discord at least
24 hours before the meeting. Any TSC member may add items.
- **Format:**
1. Triage handoff — outgoing triage lead summarizes the week's ingress.
2. SEP review — discuss and vote on any SEPs in the `in-review` state.
3. Open discussion — PRs, DWG updates, and any other business.
- **Async participation:** Members who cannot attend may submit votes or feedback
on the agenda thread before or after the meeting.
---
## Triage Rotation
Each week, one TSC member organization serves as the **triage lead**. The
rotation cycles through all TSC member organizations in seat order and
transitions at the start of the weekly Thursday meeting.
### Triage Lead Responsibilities
1. **Monitor ingress.** Review all new GitHub Issues, Pull Requests, and SEP
proposals that arrive during the week.
2. **Provide initial response.** Leave an initial comment acknowledging receipt,
tagging relevant reviewers, and labeling appropriately within 2 business days.
3. **Surface to the TSC.** Add noteworthy items to the next weekly meeting agenda
so the full TSC can discuss and prioritize them.
4. **Hand off cleanly.** At the Thursday meeting, brief the incoming triage lead
on anything still open or pending.
The rotation schedule will be maintained in a pinned post on Discord and updated
as new members join the TSC.
---
## Communication Channels
| Channel | Purpose |
|----------------------|------------------------------------------------------|
| **[Discord](https://discord.gg/53k84htnJ)** | Real-time coordination, triage discussion, community Q&A |
| **GitHub Issues/PRs**| Formal proposals, code review, SEP lifecycle |
| **GitHub Discussions**| Open-ended technical discussion and ideation |
| **Weekly Meeting** | Decision-making, SEP votes, triage handoff |
### Discord Structure
| Channel | Purpose |
|----------------------|------------------------------------------------------|
| `#announcements` | Read-only. Releases, SEP outcomes, governance updates. |
| `#general` | Open to all. Community discussion, questions, and informal SEP ideation. |
| `#technical-steering-committee` | TSC members only. Meeting agendas, triage threads, SEP review announcements, sponsorship coordination, and governance discussion. |
| `#working-groups` | DWG coordination (per-DWG channels as groups form). |
---
## SEP Lifecycle (Operational View)
This is the week-to-week flow; see [SEP Guidelines](./sep-guidelines.md) for
the full process.
1. **Ingress** — Anyone may file a new SEP as a GitHub Issue with `SEP` and
`proposal` tags. Community members can discuss ideas in `#general` on Discord
before filing. The triage lead acknowledges the issue and flags it to the TSC.
2. **Sponsorship** — A TSC member sponsors the SEP, adds the `draft` tag, and
assigns a milestone. Every SEP requires a TSC sponsor; the triage lead or any
TSC member may volunteer. Sponsorship discussion happens in
`#technical-steering-committee`.
3. **Community Review** — Sponsor moves the SEP to `in-review`. A mandatory
7-business-day review window opens, spanning at least one weekly meeting.
The sponsor posts a notice to `#technical-steering-committee` on Discord
with a summary and a link to the GitHub Issue so the broader community
can provide feedback.
4. **TSC Vote** — The SEP is discussed at the weekly meeting and decided by
simple majority (50%+1).
5. **Resolution** — Accepted SEPs move to implementation; rejected SEPs may be
revised and resubmitted.
---
## Membership Review
TSC membership is reviewed quarterly. Organizations that are consistently absent
from meetings and not contributing to triage, reviews, or discussions may be
asked to re-commit or step down per the [Governance Model](./governance.md).
## /docs/principles-mission.md
### ACP Principles and Mission
#### Mission
The **Agentic Commerce Protocol (ACP)** exists to promote open, secure, and
interoperable commerce between agents, payment providers, and sellers. Our
mission is to advance adoption and real-world use of ACP as a neutral, open
standard that evolves rapidly alongside the pace of AI while maintaining trust,
safety, and technical integrity.
---
#### Core Principles
These principles guide the ACP project. They are used by the Stewards to
evaluate changes, resolve disputes, and make directional decisions.
##### 1. Trust, Security and Compliance
ACP's first responsibility is to ensure that participants can **safely conduct
commerce** through the protocol. The protocol should help developers build
**secure, trustworthy, and compliant systems** that protect users and maintain
confidence across the ecosystem.
##### 2. Built for Real-World Use
The specification is meant to be used. This may seem obvious, but we insist on
the user journey (agents transacting with sellers) to be front and center.
Design changes should focus on real, deployable improvements with clear adoption
paths, not theoretical ideas. The protocol should evolve from actual participant
needs, not speculation. Additionally, we recognize that these commerce flows are
complex - we will write high quality documentation and provide testing tools to
ensure confidence in user deployment.
##### 3. Open and Neutral
ACP is **agnostic** to specific agents, payment providers, sellers, transport
layers, payment methods, etc. The specification does not index on any one
participant, business model, or technology. Implementations should build on top
of the ACP specification, not the reverse, ensuring that the protocol remains
open, extensible, and adaptable to future innovations. ACP should also integrate
smoothly with other open standards and protocols.
##### 4. Agile
ACP intends to remain agile and rapidly evolve to keep up with frontier model
capabilities as well as the changing needs of participants. We will incorporate
feedback and look to find the right balance between speed, stability and focus
to best serve users.
## /docs/sep-cart-capability.md
# SEP: Cart Capability for Pre-Checkout Basket Building
## SEP Metadata
- **SEP Number**: #187
- **Status**: `proposal`
- **Type**: [x] Major Change [ ] Process Change
- **Related Issues/RFCs**: `rfcs/rfc.cart.md`
---
## Abstract
This SEP introduces a **Cart** capability to ACP -- a lightweight CRUD interface for pre-checkout basket building. Agents frequently build baskets incrementally ("add this, remove that, what's the total?") before the buyer expresses purchase intent. Today, ACP requires creating a full checkout session for this, which triggers capability negotiation, payment handler configuration, and status lifecycle management -- all unnecessary overhead for browsing.
The cart provides four endpoints (`POST /carts`, `GET /carts/{id}`, `PUT /carts/{id}`, `POST /carts/{id}/cancel`) with estimated pricing and session persistence. No new domain types are introduced; carts reuse existing ACP types (LineItem, Buyer, Total, Message).
---
## Motivation
ACP's checkout session is designed for purchase finalization, but agents need a pre-purchase exploration phase. Without a cart:
* **Agents must create heavyweight checkout sessions for browsing** -- triggering capability negotiation, payment handler setup, and status lifecycle for what is essentially adding items to a basket.
* **Agents must track items client-side** -- meaning the seller has no visibility into browsing behavior, cannot provide estimated pricing, and cannot validate item availability until checkout.
* **No session persistence** -- there's no way to save a basket across agent sessions or share it via a URL for human-in-the-loop flows.
* **No incremental building** -- the common pattern of "add this... add that... remove that... check out" doesn't map cleanly to checkout session semantics.
Carts solve these by providing a binary-state (exists / not found) resource with estimated totals, no payment configuration, and no status lifecycle. The typical flow becomes: cart (browsing) -> checkout session (purchasing) -> order.
---
## Specification
This PR includes the following spec changes:
**New files:**
* `rfcs/rfc.cart.md` -- Full RFC with design, operations, schema, and conformance checklist
* `spec/unreleased/json-schema/schema.cart.json` -- Cart, CartCreateRequest, CartUpdateRequest schemas (all referencing existing ACP types via `$ref`)
* `spec/unreleased/openapi/openapi.cart.yaml` -- OpenAPI 3.1 for 4 REST endpoints
* `changelog/unreleased/cart.md` -- Changelog entry
**Modified files:**
* `spec/unreleased/json-schema/schema.agentic_checkout.json` -- Added `"carts"` to discovery services enum
* `rfcs/rfc.discovery.md` -- Added `"carts"` to services enum table and example
**Key design decisions:**
* **4 operations**: Create (`POST /carts`), Get (`GET /carts/{id}`), Update (`PUT /carts/{id}`), Cancel (`POST /carts/{id}/cancel`)
* **Full replacement on update** -- matches existing ACP checkout update semantics
* **Estimated (non-authoritative) pricing** -- totals on a cart are estimates; authoritative pricing comes at checkout
* **Session persistence** -- carts survive across agent sessions and can be shared via `continue_url`
* **No capabilities, no payment, no status lifecycle** -- these are checkout concerns
* **Binary state** -- a cart either exists or returns 404; there is no status machine
**Cart response object fields:**
* `id` (required) -- server-generated unique identifier
* `line_items` (required) -- reuses existing ACP LineItem type
* `buyer` (optional) -- reuses existing ACP Buyer type
* `currency` (required) -- ISO 4217 currency code, determined by seller
* `totals` (required) -- estimated cost breakdown (subtotal, tax if calculable, total)
* `messages` (optional) -- MessageInfo, MessageWarning, MessageError
* `continue_url` (optional) -- URI for cart handoff/session recovery
* `expires_at` (optional) -- RFC 3339 expiry timestamp
**Deferred to follow-up SEPs:**
* **Cart-to-checkout conversion** via a `cart_id` field on `CheckoutSessionCreateRequest` -- agents currently convert carts to checkouts manually by reading the cart and creating a checkout session with the retrieved items
* **Extension support** (e.g., discount codes during browsing) -- agents can apply discounts at checkout time instead
This SEP establishes the core cart resource; conversion and extension semantics will build on it additively.
---
## Rationale
**Why a separate resource instead of a "lightweight checkout"?**
Overloading checkout with a "pre-payment" mode would complicate the status lifecycle and capability negotiation contract. A separate cart resource with no status machine is simpler for both implementers and agents.
**Why full replacement instead of partial updates (add/remove item)?**
Consistent with ACP's existing checkout update pattern. Full replacement is simpler to implement and avoids the complexity of item-level CRUD operations (add, remove, change quantity as separate calls). The agent always has the full desired state and sends it.
**Why reuse existing types instead of cart-specific types?**
Carts and checkouts share the same commerce domain (items, buyers, totals). Reusing types via `$ref` ensures consistency and reduces the schema surface area.
**Why is `currency` not required on cart create (unlike checkout)?**
Carts are lightweight. The seller determines currency from context (locale, buyer location) or defaults. Requiring currency upfront adds friction for browsing. Currency is always present on the response (determined by the seller).
**Why defer cart-to-checkout conversion?**
Keeping the initial SEP focused on the core CRUD resource reduces scope and implementation complexity. The manual conversion path (read cart, create checkout with items) works today. A `cart_id` field on checkout create can be added additively in a follow-up SEP without breaking changes.
---
## Backward Compatibility
This is a purely additive change with no breaking changes:
* New endpoints (`/carts/*`) do not conflict with existing paths.
* `"carts"` in the discovery services enum is a new value; existing values are unaffected.
* Cart is an optional service; sellers that don't implement it simply omit `"carts"` from their discovery document.
No deprecation or migration is needed.
---
## Reference Implementation
Not yet available. The RFC and schema definitions in this PR serve as the specification from which implementations can be built.
---
## Security Implications
* **Authentication**: Cart endpoints use the same `Authorization: Bearer` mechanism as checkout. No new auth flows are introduced.
* **Data privacy**: Carts carry buyer email and item data, same sensitivity as checkout sessions. No additional PII exposure.
* **Cart enumeration**: Cart IDs are server-generated opaque strings. Sequential or predictable IDs SHOULD be avoided to prevent enumeration.
* **Expiry**: Carts support `expires_at` to prevent indefinite data retention. Sellers SHOULD set reasonable TTLs.
---
## Pre-Submission Checklist
- [x] I have created a GitHub Issue with the `SEP` and `proposal` tags
- [x] I have linked the SEP issue number above
- [x] I have discussed this proposal in the community (Discord/GitHub Discussions)
- [x] I have signed the Contributor License Agreement (CLA)
- [x] This PR includes updates to OpenAPI/JSON schemas
- [x] This PR includes example requests/responses (in the RFC and OpenAPI)
- [x] This PR includes a changelog entry file in `changelog/unreleased/cart.md`
- [x] I am seeking or have found a sponsor (Founding Maintainer)
---
## Additional Context
The cart capability was designed based on common agent interaction patterns observed in early ACP implementations, where agents frequently needed to build baskets incrementally before committing to a purchase. The design prioritizes simplicity and reuse of existing ACP types to minimize the implementation surface area for sellers.
The scope was intentionally narrowed to focus on the core cart CRUD resource. Cart-to-checkout conversion (`cart_id` on checkout create) and extension support (e.g., discounts on carts) are deferred to follow-up SEPs that will build on this foundation additively.
---
## Questions for Reviewers
1. **Update semantics**: Should cart update be `POST` (matching checkout) or `PUT` (more RESTful for full replacement)? The current proposal uses `POST` for consistency with ACP's existing patterns.
2. **Cart expiry defaults**: Should the spec recommend a default TTL (e.g., 24 hours, 7 days), or leave this entirely to the seller?
3. **Conversion path**: Is the manual cart-to-checkout conversion (read cart, create checkout) sufficient for the initial release, or should `cart_id` conversion be included in this SEP?
## /docs/sep-guidelines.md
# SEP Guidelines
- This document is heavily based on the
[MCP SEP process](https://modelcontextprotocol.io/community/sep-guidelines),
adapted for ACP.
> Specification Enhancement Proposal (SEP) guidelines for proposing changes to
> the Agentic Commerce Protocol
## What is a SEP?
SEP stands for Specification Enhancement Proposal. A SEP is a design document
providing information to the ACP community, or describing a new feature for the
Agentic Commerce Protocol or its processes or environment. The SEP should
provide a concise technical specification of the feature and a rationale for the
feature. We intend SEPs to be the primary mechanisms for proposing major new
features, for collecting community input on an issue, and for documenting the
design decisions that have gone into ACP. The SEP author is responsible for
building consensus within the community and documenting dissenting opinions.
Because the SEPs are maintained as text files in a versioned repository (GitHub
Issues), their revision history is the historical record of the feature
proposal.
## What qualifies a SEP?
The goal is to reserve the SEP process for changes that are substantial enough
to require broad community discussion, a formal design document, and a
historical record of the decision-making process. A regular GitHub issue or pull
request is often more appropriate for smaller, more direct changes. Consider
proposing a SEP if your change involves any of the following:
- **A New Feature or Protocol Change**: Any change that adds, modifies, or
removes features in the Agentic Commerce Protocol. This includes:
- Adding new API endpoints or methods.
- Changing the syntax or semantics of existing data structures or messages.
- Introducing a new standard for interoperability between different
ACP-compatible tools.
- Significant changes to how the specification itself is defined, presented, or
validated.
- **A Breaking Change**: Any change that is not backwards-compatible.
- **A Change to Governance or Process**: Any proposal that alters the project's
decision- making, contribution guidelines (like this document itself).
- **A Complex or Controversial Topic**: If a change is likely to have multiple
valid solutions or generate significant debate, the SEP process provides the
necessary framework to explore alternatives, document the rationale, and build
community consensus before implementation begins.
## SEP Types
ACP recognizes **two kinds of SEPs**:
1. **Major Changes (Require SEPs)** - Any substantial, complex, or controversial
change to the ACP specification. Examples include:
- Adding, modifying, or removing features in the specification.
- Significant changes to how the specification is defined, presented, or
validated.
- Breaking changes that are not backwards-compatible.
- Complex or controversial protocol topics requiring community discussion.
2. **Process Changes (Require SEPs)** - Adjustments to how the project is
governed or how core processes operate. This includes changes to governance
roles, responsibilities, decision-making rules, contributor processes, or any
structural revisions to the project itself.
## Submitting a SEP
The SEP process begins with a new idea for the Agentic Commerce Protocol. It is
highly recommended that a single SEP contain a single key proposal or new idea.
Small enhancements or patches often don't need a SEP and can be injected into
the ACP development workflow with a pull request to the ACP repo. The more
focused the SEP, the more successful it tends to be.
Each SEP must have an **SEP author** -- someone who writes the SEP using the
style and format described below, shepherds the discussions in the appropriate
forums, and attempts to build community consensus around the idea. The SEP
author should first attempt to ascertain whether the idea is SEP-able. Posting
to the ACP community forums (Discord, GitHub Discussions) is the best way to go
about this.
### SEP Workflow
SEPs should be submitted as a GitHub Issue in the
[primary repository](https://github.com/agentic-commerce-protocol/agentic-commerce-protocol).
The standard SEP workflow is:
1. You, the SEP author, create a well-formatted GitHub Issue with the `SEP` and
`proposal` tags. The SEP number is the same as the GitHub Issue number, the
two can be used interchangeably.
2. Find a Founding Maintainer or Maintainer (future tier) to sponsor your
proposal. Founding Maintainers and Maintainers will regularly go over the
list of open proposals to determine which proposals to sponsor.
3. Once a sponsor is found, the GitHub Issue is assigned to the sponsor. The
sponsor will add the `draft` tag, ensure the SEP number is in the title, and
assign a milestone.
4. The sponsor will informally review the proposal and may request changes based
on community feedback. When ready for formal review, the sponsor will add the
`in-review` tag.
5. After the `in-review` tag is added, the SEP enters formal review by the
Founding Maintainers team. The SEP may be accepted, rejected, or returned for
revision.
6. If the SEP has not found a sponsor within three months, Founding Maintainers
may close the SEP as `dormant`.
**Pull Request Template**: When creating a pull request for your SEP, use the
[sep-proposal.md](../.github/PULL_REQUEST_TEMPLATE/sep-proposal.md) template.
This template ensures you include all required sections and helps maintainers
review your proposal efficiently.
### SEP Format
Each SEP should have the following parts:
1. **Preamble** -- A short descriptive title, the names and contact info for
each author, the current status.
2. **Abstract** -- A short (~200 word) description of the technical / process
issue being addressed.
3. **Motivation** -- The motivation should clearly explain why the existing
protocol specification is inadequate to address the problem that the SEP
solves. The motivation is critical for SEPs that want to change the Agentic
Commerce Protocol. SEP submissions without sufficient motivation may be
rejected outright.
4. **Specification** -- The technical specification should describe the syntax
and semantics of any new protocol feature. The specification should be
detailed enough to allow competing, interoperable implementations. A PR with
the changes to the specification should be provided.
5. **Rationale** -- The rationale explains why particular design decisions were
made. It should describe alternate designs that were considered and related
work. The rationale should provide evidence of consensus within the community
and discuss important objections or concerns raised during discussion.
6. **Backward Compatibility** -- All SEPs that introduce backward
incompatibilities must include a section describing these incompatibilities
and their severity. The SEP must explain how the author proposes to deal with
these incompatibilities.
7. **Reference Implementation** -- The reference implementation must be
completed before any SEP is given status "Final", but it need not be
completed before the SEP is accepted. While there is merit to the approach of
reaching consensus on the specification and rationale before writing code,
the principle of "rough consensus and running code" is still useful when it
comes to resolving many discussions of protocol details.
8. **Security Implications** -- If there are security concerns in relation to
the SEP, those concerns should be explicitly written out to make sure
reviewers of the SEP are aware of them.
### SEP States
SEPs can be one of the following states:
- `proposal`: SEP proposal without a sponsor.
- `draft`: SEP proposal with a sponsor.
- `in-review`: SEP proposal ready for review.
- `accepted`: SEP accepted by Founding Maintainers, but still requires final
wording and reference implementation.
- `rejected`: SEP rejected by Founding Maintainers.
- `withdrawn`: SEP withdrawn.
- `final`: SEP finalized.
- `superseded`: SEP has been replaced by a newer SEP.
- `dormant`: SEP that has not found sponsors and was subsequently closed.
### SEP Review & Resolution
SEPs are reviewed by the ACP Founding Maintainers team on a bi-weekly basis.
For a SEP to be accepted it must meet certain minimum criteria:
- A prototype implementation demonstrating the proposal
- Clear benefit to the ACP ecosystem
- Community support and consensus
Once a SEP has been accepted, the reference implementation must be completed.
When the reference implementation is complete and incorporated into the main
source code repository, the status will be changed to "Final".
A SEP can also be "Rejected" or "Withdrawn". A SEP that is "Withdrawn" may be
re-submitted at a later date.
## Reporting SEP Bugs, or Submitting SEP Updates
How you report a bug, or submit a SEP update depends on several factors, such as
the maturity of the SEP, the preferences of the SEP author, and the nature of
your comments. For SEPs not yet reaching `final` state, it's probably best to
send your comments and changes directly to the SEP author. Once SEP is
finalized, you may want to submit corrections as a GitHub comment on the issue
or pull request to the reference implementation.
## Transferring SEP Ownership
It occasionally becomes necessary to transfer ownership of SEPs to a new SEP
author. In general, we'd like to retain the original author as a co-author of
the transferred SEP, but that's really up to the original author. A good reason
to transfer ownership is because the original author no longer has the time or
interest in updating it or following through with the SEP process, or has fallen
off the face of the 'net (i.e. is unreachable or not responding to email). A bad
reason to transfer ownership is because you don't agree with the direction of
the SEP. We try to build consensus around a SEP, but if that's not possible, you
can always submit a competing SEP.
## /docs/sep-markdown-specification.md
# SEP: Markdown Content Specification (CommonMark)
## SEP Metadata
- **SEP Number**: TBD
- **Status**: `proposal`
- **Type**: [x] Major Change [ ] Process Change
- **Related Issues/RFCs**: `rfcs/rfc.agentic_checkout.md`
---
## Abstract
ACP defines a `content_type` field with values `"plain"` and `"markdown"` on four message types (Disclosure, MessageInfo, MessageWarning, MessageError), but the specification does not define what "markdown" means. There is no normative reference to a markdown dialect, no restriction on raw HTML, and no guidance for agents rendering markdown content.
This ambiguity creates a cross-site scripting (XSS) risk: because standard Markdown permits inline HTML, seller-authored markdown could contain `<script>`, `<iframe>`, or event-handler attributes that execute in the agent's rendering context. It also creates an interoperability gap -- different parsers (GFM, Markdown.pl, CommonMark) produce different output from identical input.
This SEP adopts [CommonMark](https://spec.commonmark.org/0.31.2/) as the normative markdown standard for all `content_type: "markdown"` fields in ACP and explicitly disallows raw HTML elements. It establishes a shared responsibility model: sellers author compliant content, the server validates and rejects non-conforming input, and agents render using CommonMark-compliant parsers with HTML output disabled.
---
## Motivation
ACP's checkout specification uses markdown to convey rich content -- legal disclosures, informational messages, warnings, and errors -- from sellers to agents and ultimately to buyers. Markdown is the right tool for this: it is lightweight, human-readable, and widely supported. However, ACP currently treats "markdown" as a black box:
* **No dialect specified.** The `content_type: "markdown"` enum value does not reference any standard. Different markdown dialects disagree on edge cases (e.g., nested emphasis, link parsing, HTML handling), which means the same seller content can render differently across agents.
* **Raw HTML is implicitly permitted.** Standard Markdown and most dialects allow arbitrary inline HTML. A seller could include `<script>alert('xss')</script>` in a disclosure field, and the spec provides no basis for rejecting it. If an agent renders this content in a web context without sanitization, it becomes an XSS vector.
* **No rendering guidance for agents.** Agents have no specification-level guidance on which parser to use, whether to allow HTML output, or how to handle malformed input. This makes it difficult to build secure, interoperable implementations.
* **No validation basis for the server.** Without a formal spec, the server has no standard against which to validate inbound markdown content. It cannot distinguish valid from invalid markdown, and it cannot reject content that poses a security risk.
As ACP scales beyond a small set of trusted agents and sellers, these gaps become increasingly dangerous. A formal markdown specification is needed to close them.
---
## Specification
This PR includes the following spec changes:
**New files:**
* `docs/sep-markdown-specification.md` -- this SEP
* `changelog/unreleased/markdown-specification.md` -- changelog entry
**Modified files:**
* `spec/unreleased/json-schema/schema.agentic_checkout.json` -- updated `content_type` and `content` field descriptions on Disclosure, MessageInfo, MessageWarning, and MessageError to reference CommonMark and disallow raw HTML
* `spec/unreleased/openapi/openapi.agentic_checkout.yaml` -- same description updates mirrored
* `rfcs/rfc.agentic_checkout.md` -- added Markdown Content Specification subsection to the Data Model section
**Key design decisions:**
* **CommonMark 0.31.2 as normative reference** -- a stable, vendor-neutral, formally specified markdown standard with broad tooling support and a comprehensive conformance test suite.
* **Raw HTML MUST be disallowed** -- sellers MUST NOT include raw HTML elements in markdown content. The server MUST reject content containing raw HTML. Agents MUST render with HTML output disabled or sanitized. This eliminates the XSS attack surface at the protocol level.
* **No new schema fields** -- the semantic constraint is applied to the existing `content_type: "markdown"` enum value through enhanced field descriptions. This avoids schema churn and keeps the API surface stable.
* **Conformance language follows RFC 2119/8174** -- matching the normative language conventions already established in the ACP specification.
**Affected fields:**
The following four types carry `content_type` and `content` fields that are constrained by this specification:
| Type | Description |
|------|-------------|
| Disclosure | Legal disclosures or terms on line items that must be acknowledged by the buyer |
| MessageInfo | Informational messages from the seller (non-blocking) |
| MessageWarning | Warning messages with structured codes (non-blocking) |
| MessageError | Error messages with structured codes (blocking) |
For each type, when `content_type` is `"markdown"`:
* The `content` field MUST contain valid CommonMark as defined by [the CommonMark specification, version 0.31.2](https://spec.commonmark.org/0.31.2/).
* The `content` field MUST NOT contain raw HTML elements (as defined in [CommonMark Section 6.6 — Raw HTML](https://spec.commonmark.org/0.31.2/#raw-html)).
* Agents MUST render the content using a CommonMark-compliant parser with raw HTML output disabled or sanitized.
When `content_type` is `"plain"`, the `content` field is plain text with no formatting semantics.
**Shared responsibility model:**
| Party | Responsibility |
|-------|---------------|
| **Sellers** | Author markdown content that conforms to CommonMark without raw HTML elements |
| **Server (seller)** | Validate inbound markdown and reject content containing raw HTML (the gateway enforcement point) |
| **Agents** | Render markdown using a CommonMark-compliant parser with raw HTML output disabled or sanitized (defense-in-depth) |
---
## Rationale
**Why CommonMark instead of GitHub Flavored Markdown (GFM)?**
GFM is a superset of CommonMark maintained by a single vendor (GitHub). It adds tables, task lists, strikethrough, and autolinks -- features that are not relevant to ACP's disclosure and messaging use cases. Adopting CommonMark is strictly more conservative: it provides the smallest reasonable standard specification, and GFM extensions can be added incrementally in follow-up SEPs if needed. CommonMark is vendor-neutral and governed by the original contributors to Markdown.
**Why not define a custom markdown subset?**
A bespoke allowlist (e.g., "only bold, italic, links, and lists") would require building and maintaining a custom parser/validator with no community tooling support. Edge cases and parsing ambiguities are inevitable without a formal grammar. External partners (agents, sellers) would have no standard to point to. CommonMark provides all of this out of the box.
**Why disallow raw HTML rather than sanitize it?**
HTML sanitization is complex, error-prone, and parser-dependent. Different sanitizers make different choices about which elements and attributes to allow, creating inconsistent behavior across implementations. Disallowing raw HTML entirely is simpler to specify, validate, and implement. It eliminates the XSS attack surface completely rather than attempting to manage it. Most CommonMark parsers support disabling raw HTML natively (e.g., `cmark` with `CMARK_OPT_SAFE`, `markdown-it` with `html: false`).
**Why not add a new `markdown_specification` schema field?**
Adding a field would increase schema complexity and require version negotiation between agents and sellers. It is unnecessary since ACP currently supports only one markdown dialect. The constraint is best expressed through enhanced field descriptions -- matching ACP's existing convention of using normative language in descriptions (e.g., the RFC 9535 JSONPath reference on the `param` field). If a future SEP introduces alternative dialects, the `content_type` enum can be extended (e.g., `"commonmark"`, `"gfm"`).
**Why pin to CommonMark version 0.31.2?**
Pinning to a specific version ensures deterministic behavior: all implementations target the same specification. Floating to "latest" would mean the ACP spec's semantics change whenever CommonMark publishes an update, potentially without review. Version updates can be proposed as lightweight follow-up SEPs.
---
## Backward Compatibility
This is a non-breaking change that formalizes the semantics of an existing enum value:
* **No structural schema changes.** No fields are added, removed, or renamed. The `content_type` enum values (`"plain"`, `"markdown"`) are unchanged.
* **Compliant content is unaffected.** Sellers already producing valid CommonMark without raw HTML require no changes.
* **Non-compliant content is affected.** Sellers currently including raw HTML in markdown fields will need to remove it. This is expected to be rare, as markdown content in practice consists of headings, emphasis, links, and lists.
* **Migration path.** The server can implement a warning period before enforcing rejection -- logging non-conforming content before returning HTTP 422 errors. This gives sellers time to audit and update their content.
No deprecation timeline is needed since no existing feature is being removed.
---
## Reference Implementation
Not yet available. The field description updates in this PR serve as the normative specification from which implementations can be built.
Compliant CommonMark parsers that support disabling raw HTML output include:
* **JavaScript**: `commonmark.js` (with `safe: true`), `markdown-it` (with `html: false`)
* **C**: `cmark` (with `CMARK_OPT_SAFE`)
* **Rust**: `comrak` (with `unsafe_: false`)
* **Python**: `commonmark` (with `safe` mode), `markdown-it-py`
* **Go**: `goldmark` (with `html.WithUnsafe()` omitted)
The [CommonMark conformance test suite](https://spec.commonmark.org/0.31.2/spec.json) can be used to validate parser compliance.
---
## Security Implications
This SEP directly addresses a cross-site scripting (XSS) risk in ACP's markdown content fields.
* **Attack vector eliminated.** Raw HTML injection vectors -- `<script>`, `<iframe>`, `<img onerror>`, `<a onclick>`, and similar -- are blocked at the protocol level. Sellers MUST NOT include them; the server MUST reject them.
* **Defense-in-depth.** Agents MUST render with HTML output disabled even though the server should have already rejected raw HTML upstream. This provides protection against edge cases during validation rollout or implementation gaps.
* **No new attack surface.** This SEP constrains existing behavior; it does not introduce new endpoints, authentication flows, or data storage. The security posture strictly improves.
* **Compliance.** Formalizing the markdown specification provides an auditable standard for security reviews and compliance assessments.
---
## Pre-Submission Checklist
- [ ] I have created a GitHub Issue with the `SEP` and `proposal` tags
- [ ] I have linked the SEP issue number above
- [ ] I have discussed this proposal in the community (Discord/GitHub Discussions)
- [x] I have signed the Contributor License Agreement (CLA)
- [x] This PR includes updates to OpenAPI/JSON schemas
- [ ] This PR includes example requests/responses (if applicable)
- [x] This PR includes a changelog entry file in `changelog/unreleased/markdown-specification.md`
- [ ] I am seeking or have found a sponsor (Founding Maintainer)
---
## Additional Context
The CommonMark specification was chosen after evaluating three alternatives: GitHub Flavored Markdown (broader but vendor-controlled), a custom restricted subset (maximum control but high maintenance burden), and CommonMark (formally specified, vendor-neutral, broad ecosystem). CommonMark is supported by the original contributors to Markdown and has compliant parser implementations in every major programming language.
The markdown fields in ACP are currently used for legal disclosures on line items and for seller-to-agent messaging (info, warnings, errors). These use cases require basic formatting (emphasis, links, lists) but do not require HTML-level expressiveness, making CommonMark with raw HTML disallowed a natural fit.
Agents such as Microsoft Copilot already use CommonMark-based rendering internally, so adoption friction is expected to be minimal.
---
## Questions for Reviewers
1. **Version pinning**: Should the spec reference a specific CommonMark version (0.31.2) or "the latest stable release"? Pinning is more predictable; floating is more future-proof.
2. **Rejection strictness**: Should server-side rejection of raw HTML be a MUST (hard reject, HTTP 422) or a SHOULD (recommended, with a warning period)?
3. **Parser recommendations**: Should the spec recommend specific CommonMark parser libraries per language, or is the reference to the CommonMark specification sufficient?
4. **Raw HTML use cases**: Are there legitimate use cases for raw HTML in disclosures or messages that this proposal would break?
## /examples/2025-09-29/examples.agentic_checkout.json
```json path="/examples/2025-09-29/examples.agentic_checkout.json"
{
"create_checkout_session_request": {
"items": [
{
"id": "item_123",
"quantity": 2.5
}
],
"fulfillment_address": {
"name": "John Doe",
"line_one": "1234 Chat Road,",
"line_two": "",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94131"
}
},
"create_checkout_session_response": {
"id": "checkout_session_123",
"payment_provider": {
"provider": "stripe",
"supported_payment_methods": ["card"]
},
"status": "ready_for_payment",
"currency": "usd",
"line_items": [
{
"id": "line_item_123",
"item": {
"id": "item_123",
"quantity": 2.5
},
"base_amount": 300,
"discount": 0,
"subtotal": 300,
"tax": 30,
"total": 330
}
],
"fulfillment_address": {
"name": "John Doe",
"line_one": "1234 Chat Road,",
"line_two": "",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94131"
},
"fulfillment_option_id": "fulfillment_option_123",
"totals": [
{
"type": "items_base_amount",
"display_text": "Item(s) total",
"amount": 300
},
{
"type": "subtotal",
"display_text": "Subtotal",
"amount": 300
},
{
"type": "tax",
"display_text": "Tax",
"amount": 30
},
{
"type": "fulfillment",
"display_text": "Fulfillment",
"amount": 100
},
{
"type": "total",
"display_text": "Total",
"amount": 430
}
],
"fulfillment_options": [
{
"type": "shipping",
"id": "fulfillment_option_123",
"title": "Standard",
"subtitle": "Arrives in 4-5 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-12T07:20:50.52Z",
"latest_delivery_time": "2025-10-13T07:20:50.52Z",
"subtotal": 100,
"tax": 0,
"total": 100
},
{
"type": "shipping",
"id": "fulfillment_option_456",
"title": "Express",
"subtitle": "Arrives in 1-2 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-09T07:20:50.52Z",
"latest_delivery_time": "2025-10-10T07:20:50.52Z",
"subtotal": 500,
"tax": 0,
"total": 500
}
],
"messages": [],
"links": [
{
"type": "terms_of_use",
"url": "https://www.testshop.com/legal/terms-of-use"
}
]
},
"update_checkout_session_request": {
"fulfillment_option_id": "fulfillment_option_456"
},
"update_checkout_session_response": {
"id": "checkout_session_123",
"status": "ready_for_payment",
"currency": "usd",
"line_items": [
{
"id": "line_item_123",
"item": {
"id": "item_123",
"quantity": 2.5
},
"base_amount": 300,
"discount": 0,
"subtotal": 300,
"tax": 30,
"total": 330
}
],
"fulfillment_address": {
"name": "John Doe",
"line_one": "1234 Chat Road,",
"line_two": "",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94131"
},
"fulfillment_option_id": "fulfillment_option_456",
"totals": [
{
"type": "items_base_amount",
"display_text": "Item(s) total",
"amount": 300
},
{
"type": "subtotal",
"display_text": "Subtotal",
"amount": 300
},
{
"type": "tax",
"display_text": "Tax",
"amount": 30
},
{
"type": "fulfillment",
"display_text": "Fulfillment",
"amount": 500
},
{
"type": "total",
"display_text": "Total",
"amount": 830
}
],
"fulfillment_options": [
{
"type": "shipping",
"id": "fulfillment_option_123",
"title": "Standard",
"subtitle": "Arrives in 4-5 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-12T07:20:50.52Z",
"latest_delivery_time": "2025-10-13T07:20:50.52Z",
"subtotal": 100,
"tax": 0,
"total": 100
},
{
"type": "shipping",
"id": "fulfillment_option_456",
"title": "Express",
"subtitle": "Arrives in 1-2 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-09T07:20:50.52Z",
"latest_delivery_time": "2025-10-10T07:20:50.52Z",
"subtotal": 500,
"tax": 0,
"total": 500
}
],
"messages": [],
"links": [
{
"type": "terms_of_use",
"url": "https://www.testshop.com/legal/terms-of-use"
}
]
},
"complete_checkout_session_request": {
"buyer": {
"first_name": "John",
"last_name": "Smith",
"email": "johnsmith@mail.com",
"phone_number": "15552003434"
},
"payment_data": {
"token": "spt_123",
"provider": "stripe",
"billing_address": {
"name": "John Smith",
"line_one": "1234 Chat Road,",
"line_two": "",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94131"
}
}
},
"complete_checkout_session_response": {
"id": "checkout_session_123",
"buyer": {
"first_name": "John",
"last_name": "Smith",
"email": "johnsmith@mail.com",
"phone_number": "15552003434"
},
"status": "completed",
"currency": "usd",
"line_items": [
{
"id": "line_item_123",
"item": {
"id": "item_123",
"quantity": 2.5
},
"base_amount": 300,
"discount": 0,
"subtotal": 300,
"tax": 30,
"total": 330
}
],
"fulfillment_address": {
"name": "John Doe",
"line_one": "1234 Chat Road,",
"line_two": "",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94131"
},
"fulfillment_option_id": "fulfillment_option_123",
"totals": [
{
"type": "items_base_amount",
"display_text": "Item(s) total",
"amount": 300
},
{
"type": "subtotal",
"display_text": "Subtotal",
"amount": 300
},
{
"type": "tax",
"display_text": "Tax",
"amount": 30
},
{
"type": "fulfillment",
"display_text": "Fulfillment",
"amount": 100
},
{
"type": "total",
"display_text": "Total",
"amount": 430
}
],
"fulfillment_options": [
{
"type": "shipping",
"id": "fulfillment_option_123",
"title": "Standard",
"subtitle": "Arrives in 4-5 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-12T07:20:50.52Z",
"latest_delivery_time": "2025-10-13T07:20:50.52Z",
"subtotal": 100,
"tax": 0,
"total": 100
},
{
"type": "shipping",
"id": "fulfillment_option_456",
"title": "Express",
"subtitle": "Arrives in 1-2 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-09T07:20:50.52Z",
"latest_delivery_time": "2025-10-10T07:20:50.52Z",
"subtotal": 500,
"tax": 0,
"total": 500
}
],
"messages": [],
"links": [
{
"type": "terms_of_use",
"url": "https://www.testshop.com/legal/terms-of-use"
}
]
},
"get_checkout_session_response": {
"id": "checkout_session_123",
"status": "ready_for_payment",
"currency": "usd",
"line_items": [
{
"id": "line_item_123",
"item": {
"id": "item_123",
"quantity": 2.5
},
"base_amount": 300,
"discount": 0,
"subtotal": 300,
"tax": 30,
"total": 330
}
],
"fulfillment_address": {
"name": "John Doe",
"line_one": "1234 Chat Road,",
"line_two": "",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94131"
},
"fulfillment_option_id": "fulfillment_option_123",
"totals": [
{
"type": "items_base_amount",
"display_text": "Item(s) total",
"amount": 300
},
{
"type": "subtotal",
"display_text": "Subtotal",
"amount": 300
},
{
"type": "tax",
"display_text": "Tax",
"amount": 30
},
{
"type": "fulfillment",
"display_text": "Fulfillment",
"amount": 100
},
{
"type": "total",
"display_text": "Total",
"amount": 430
}
],
"fulfillment_options": [
{
"type": "shipping",
"id": "fulfillment_option_123",
"title": "Standard",
"subtitle": "Arrives in 4-5 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-12T07:20:50.52Z",
"latest_delivery_time": "2025-10-13T07:20:50.52Z",
"subtotal": 100,
"tax": 0,
"total": 100
},
{
"type": "shipping",
"id": "fulfillment_option_456",
"title": "Express",
"subtitle": "Arrives in 1-2 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-09T07:20:50.52Z",
"latest_delivery_time": "2025-10-10T07:20:50.52Z",
"subtotal": 500,
"tax": 0,
"total": 500
}
],
"messages": [],
"links": [
{
"type": "terms_of_use",
"url": "https://www.testshop.com/legal/terms-of-use"
}
]
},
"cancel_checkout_session_response": {
"id": "checkout_session_123",
"status": "canceled",
"currency": "usd",
"line_items": [
{
"id": "line_item_123",
"item": {
"id": "item_123",
"quantity": 2.5
},
"base_amount": 300,
"discount": 0,
"subtotal": 300,
"tax": 30,
"total": 330
}
],
"fulfillment_address": {
"name": "John Doe",
"line_one": "1234 Chat Road,",
"line_two": "",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94131"
},
"fulfillment_option_id": "fulfillment_option_123",
"totals": [
{
"type": "items_base_amount",
"display_text": "Item(s) total",
"amount": 300
},
{
"type": "subtotal",
"display_text": "Subtotal",
"amount": 300
},
{
"type": "tax",
"display_text": "Tax",
"amount": 30
},
{
"type": "fulfillment",
"display_text": "Fulfillment",
"amount": 100
},
{
"type": "total",
"display_text": "Total",
"amount": 430
}
],
"fulfillment_options": [
{
"type": "shipping",
"id": "fulfillment_option_123",
"title": "Standard",
"subtitle": "Arrives in 4-5 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-12T07:20:50.52Z",
"latest_delivery_time": "2025-10-13T07:20:50.52Z",
"subtotal": 100,
"tax": 0,
"total": 100
}
],
"messages": [
{
"type": "info",
"content_type": "plain",
"content": "Checkout session has been canceled."
}
],
"links": [
{
"type": "terms_of_use",
"url": "https://www.testshop.com/legal/terms-of-use"
}
]
},
"webhook_order_create_event": {
"type": "order_create",
"data": {
"type": "order",
"checkout_session_id": "checkout_session_123",
"permalink_url": "https://www.testshop.com/orders/checkout_session_123",
"status": "created",
"refunds": []
}
},
"webhook_order_update_event": {
"type": "order_update",
"data": {
"type": "order",
"checkout_session_id": "checkout_session_123",
"permalink_url": "https://www.testshop.com/orders/checkout_session_123",
"status": "shipped",
"refunds": [
{
"type": "original_payment",
"amount": 100
}
]
}
}
}
```
## /examples/2025-09-29/examples.delegate_payment.json
```json path="/examples/2025-09-29/examples.delegate_payment.json"
{
"delegate_payment_request": {
"payment_method": {
"type": "card",
"card_number_type": "fpan",
"virtual": false,
"number": "4242424242424242",
"exp_month": "11",
"exp_year": "2026",
"name": "Jane Doe",
"cvc": "223",
"checks_performed": ["avs", "cvv"],
"iin": "424242",
"display_card_funding_type": "credit",
"display_wallet_type": "apple_pay",
"display_brand": "visa",
"display_last4": "4242",
"metadata": {
"issuing_bank": "temp"
}
},
"allowance": {
"reason": "one_time",
"max_amount": 2000,
"currency": "usd",
"checkout_session_id": "csn_01HV3P3XYZ9ABC",
"merchant_id": "acme_store",
"expires_at": "2025-10-09T07:20:50.52Z"
},
"billing_address": {
"name": "Ada Lovelace",
"line_one": "1234 Chat Road",
"line_two": "",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94131"
},
"risk_signals": [
{
"type": "card_testing",
"score": 10,
"action": "manual_review"
}
],
"metadata": {
"campaign": "q4",
"source": "chatgpt_checkout"
}
},
"delegate_payment_success_response": {
"id": "vt_01J8Z3WXYZ9ABC",
"created": "2025-09-29T11:00:00Z",
"metadata": {
"source": "agent_checkout",
"merchant_id": "acme_store",
"idempotency_key": "idem_abc123"
}
},
"delegate_payment_error_invalid_card": {
"type": "invalid_request",
"code": "invalid_card",
"message": "Invalid card number provided",
"param": "payment_method.number"
},
"delegate_payment_error_idempotency_conflict": {
"type": "invalid_request",
"code": "idempotency_conflict",
"message": "Same Idempotency-Key used with different parameters"
},
"delegate_payment_error_rate_limit": {
"type": "rate_limit_exceeded",
"code": "too_many_requests",
"message": "Too many requests, please retry later"
}
}
```
## /examples/2025-12-12/examples.agentic_checkout.json
```json path="/examples/2025-12-12/examples.agentic_checkout.json"
{
"create_checkout_session_request": {
"items": [
{
"id": "item_123",
"quantity": 1
}
],
"fulfillment_details": {
"name": "John Doe",
"phone_number": "15551234567",
"email": "johndoe@example.com",
"address": {
"name": "John Doe",
"line_one": "1234 Chat Road,",
"line_two": "",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94131"
}
}
},
"create_checkout_session_request_with_first_touch_attribution": {
"items": [
{
"id": "item_123",
"quantity": 1
}
],
"affiliate_attribution": {
"provider": "impact.com",
"token": "atp_01J8Z3WXYZ9ABC",
"publisher_id": "pub_123",
"touchpoint": "first"
}
},
"create_checkout_session_response": {
"id": "checkout_session_123",
"payment_provider": {
"provider": "stripe",
"supported_payment_methods": [
{
"type": "card",
"supported_card_networks": ["amex", "discover", "mastercard", "visa"]
}
]
},
"status": "ready_for_payment",
"currency": "usd",
"line_items": [
{
"id": "line_item_123",
"item": {
"id": "item_123",
"quantity": 1
},
"base_amount": 300,
"discount": 0,
"subtotal": 300,
"tax": 30,
"total": 330,
"name": "Vintage Denim Jacket",
"description": "Classic blue denim jacket with brass buttons and adjustable waist tabs",
"images": [
"https://www.testshop.com/products/item_123/image1.jpg",
"https://www.testshop.com/products/item_123/image2.jpg"
],
"unit_amount": 300,
"custom_attributes": [
{
"display_name": "Size",
"value": "Medium"
},
{
"display_name": "Color",
"value": "Blue"
}
],
"disclosures": [
{
"type": "disclaimer",
"content_type": "plain",
"content": "This item is vintage and may show signs of previous wear."
}
]
}
],
"fulfillment_details": {
"name": "John Doe",
"phone_number": "15551234567",
"email": "johndoe@example.com",
"address": {
"name": "John Doe",
"line_one": "1234 Chat Road,",
"line_two": "",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94131"
}
},
"selected_fulfillment_options": [
{
"type": "shipping",
"shipping": {
"option_id": "fulfillment_option_123",
"item_ids": ["item_123"]
}
}
],
"totals": [
{
"type": "items_base_amount",
"display_text": "Item(s) total",
"amount": 300
},
{
"type": "subtotal",
"display_text": "Subtotal",
"amount": 300
},
{
"type": "tax",
"display_text": "Tax",
"amount": 30
},
{
"type": "fulfillment",
"display_text": "Fulfillment",
"amount": 100
},
{
"type": "fee",
"display_text": "Service Fee",
"amount": 50,
"description": "Processing and handling fee"
},
{
"type": "total",
"display_text": "Total",
"amount": 480
}
],
"fulfillment_options": [
{
"type": "shipping",
"id": "fulfillment_option_123",
"title": "Standard",
"subtitle": "Arrives in 4-5 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-12T07:20:50.52Z",
"latest_delivery_time": "2025-10-13T07:20:50.52Z",
"subtotal": 100,
"tax": 0,
"total": 100
},
{
"type": "shipping",
"id": "fulfillment_option_456",
"title": "Express",
"subtitle": "Arrives in 1-2 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-09T07:20:50.52Z",
"latest_delivery_time": "2025-10-10T07:20:50.52Z",
"subtotal": 500,
"tax": 0,
"total": 500
}
],
"messages": [],
"links": [
{
"type": "terms_of_use",
"url": "https://www.testshop.com/legal/terms-of-use"
},
{
"type": "return_policy",
"url": "https://www.testshop.com/legal/return-policy"
}
]
},
"update_checkout_session_request": {
"selected_fulfillment_options": [
{
"type": "shipping",
"shipping": {
"option_id": "fulfillment_option_456",
"item_ids": ["item_123"]
}
}
]
},
"update_checkout_session_response": {
"id": "checkout_session_123",
"status": "ready_for_payment",
"currency": "usd",
"line_items": [
{
"id": "line_item_123",
"item": {
"id": "item_123",
"quantity": 1
},
"base_amount": 300,
"discount": 0,
"subtotal": 300,
"tax": 30,
"total": 330
}
],
"fulfillment_details": {
"name": "John Doe",
"phone_number": "15551234567",
"email": "johndoe@example.com",
"address": {
"name": "John Doe",
"line_one": "1234 Chat Road,",
"line_two": "",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94131"
}
},
"selected_fulfillment_options": [
{
"type": "shipping",
"shipping": {
"option_id": "fulfillment_option_456",
"item_ids": ["item_123"]
}
}
],
"totals": [
{
"type": "items_base_amount",
"display_text": "Item(s) total",
"amount": 300
},
{
"type": "subtotal",
"display_text": "Subtotal",
"amount": 300
},
{
"type": "tax",
"display_text": "Tax",
"amount": 30
},
{
"type": "fulfillment",
"display_text": "Fulfillment",
"amount": 500
},
{
"type": "total",
"display_text": "Total",
"amount": 830
}
],
"fulfillment_options": [
{
"type": "shipping",
"id": "fulfillment_option_123",
"title": "Standard",
"subtitle": "Arrives in 4-5 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-12T07:20:50.52Z",
"latest_delivery_time": "2025-10-13T07:20:50.52Z",
"subtotal": 100,
"tax": 0,
"total": 100
},
{
"type": "shipping",
"id": "fulfillment_option_456",
"title": "Express",
"subtitle": "Arrives in 1-2 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-09T07:20:50.52Z",
"latest_delivery_time": "2025-10-10T07:20:50.52Z",
"subtotal": 500,
"tax": 0,
"total": 500
}
],
"messages": [],
"links": [
{
"type": "terms_of_use",
"url": "https://www.testshop.com/legal/terms-of-use"
},
{
"type": "return_policy",
"url": "https://www.testshop.com/legal/return-policy"
}
]
},
"complete_checkout_session_request": {
"buyer": {
"first_name": "John",
"last_name": "Smith",
"email": "johnsmith@mail.com",
"phone_number": "15552003434"
},
"payment_data": {
"token": "spt_123",
"provider": "stripe",
"billing_address": {
"name": "John Smith",
"line_one": "1234 Chat Road,",
"line_two": "",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94131"
}
}
},
"complete_checkout_session_request_with_last_touch_attribution": {
"buyer": {
"first_name": "John",
"last_name": "Smith",
"email": "johnsmith@mail.com",
"phone_number": "15552003434"
},
"payment_data": {
"token": "spt_123",
"provider": "stripe",
"billing_address": {
"name": "John Smith",
"line_one": "1234 Chat Road,",
"line_two": "",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94131"
}
},
"affiliate_attribution": {
"provider": "impact.com",
"token": "atp_01J8Z3WXYZ9ABC",
"publisher_id": "pub_123",
"touchpoint": "last"
}
},
"complete_checkout_session_response": {
"id": "checkout_session_123",
"buyer": {
"first_name": "John",
"last_name": "Smith",
"email": "johnsmith@mail.com",
"phone_number": "15552003434"
},
"status": "completed",
"currency": "usd",
"line_items": [
{
"id": "line_item_123",
"item": {
"id": "item_123",
"quantity": 1
},
"base_amount": 300,
"discount": 0,
"subtotal": 300,
"tax": 30,
"total": 330,
"name": "Vintage Denim Jacket",
"description": "Classic blue denim jacket with brass buttons and adjustable waist tabs",
"images": [
"https://www.testshop.com/products/item_123/image1.jpg"
],
"unit_amount": 300,
"marketplace_seller_details": {
"name": "VintageClothingCo"
}
}
],
"fulfillment_details": {
"name": "John Doe",
"phone_number": "15551234567",
"email": "johndoe@example.com",
"address": {
"name": "John Doe",
"line_one": "1234 Chat Road,",
"line_two": "",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94131"
}
},
"selected_fulfillment_options": [
{
"type": "shipping",
"shipping": {
"option_id": "fulfillment_option_123",
"item_ids": ["item_123"]
}
}
],
"totals": [
{
"type": "items_base_amount",
"display_text": "Item(s) total",
"amount": 300
},
{
"type": "subtotal",
"display_text": "Subtotal",
"amount": 300
},
{
"type": "tax",
"display_text": "Tax",
"amount": 30
},
{
"type": "fulfillment",
"display_text": "Fulfillment",
"amount": 100
},
{
"type": "total",
"display_text": "Total",
"amount": 430
}
],
"fulfillment_options": [
{
"type": "shipping",
"id": "fulfillment_option_123",
"title": "Standard",
"subtitle": "Arrives in 4-5 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-12T07:20:50.52Z",
"latest_delivery_time": "2025-10-13T07:20:50.52Z",
"subtotal": 100,
"tax": 0,
"total": 100
},
{
"type": "shipping",
"id": "fulfillment_option_456",
"title": "Express",
"subtitle": "Arrives in 1-2 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-09T07:20:50.52Z",
"latest_delivery_time": "2025-10-10T07:20:50.52Z",
"subtotal": 500,
"tax": 0,
"total": 500
}
],
"messages": [],
"links": [
{
"type": "terms_of_use",
"url": "https://www.testshop.com/legal/terms-of-use"
},
{
"type": "return_policy",
"url": "https://www.testshop.com/legal/return-policy"
}
],
"order": {
"id": "ord_abc123",
"checkout_session_id": "checkout_session_123",
"permalink_url": "https://www.testshop.com/orders/ord_abc123"
}
},
"get_checkout_session_response": {
"id": "checkout_session_123",
"status": "ready_for_payment",
"currency": "usd",
"line_items": [
{
"id": "line_item_123",
"item": {
"id": "item_123",
"quantity": 1
},
"base_amount": 300,
"discount": 0,
"subtotal": 300,
"tax": 30,
"total": 330
}
],
"fulfillment_details": {
"name": "John Doe",
"phone_number": "15551234567",
"email": "johndoe@example.com",
"address": {
"name": "John Doe",
"line_one": "1234 Chat Road,",
"line_two": "",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94131"
}
},
"selected_fulfillment_options": [
{
"type": "shipping",
"shipping": {
"option_id": "fulfillment_option_123",
"item_ids": ["item_123"]
}
}
],
"totals": [
{
"type": "items_base_amount",
"display_text": "Item(s) total",
"amount": 300
},
{
"type": "subtotal",
"display_text": "Subtotal",
"amount": 300
},
{
"type": "tax",
"display_text": "Tax",
"amount": 30
},
{
"type": "fulfillment",
"display_text": "Fulfillment",
"amount": 100
},
{
"type": "total",
"display_text": "Total",
"amount": 430
}
],
"fulfillment_options": [
{
"type": "shipping",
"id": "fulfillment_option_123",
"title": "Standard",
"subtitle": "Arrives in 4-5 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-12T07:20:50.52Z",
"latest_delivery_time": "2025-10-13T07:20:50.52Z",
"subtotal": 100,
"tax": 0,
"total": 100
},
{
"type": "shipping",
"id": "fulfillment_option_456",
"title": "Express",
"subtitle": "Arrives in 1-2 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-09T07:20:50.52Z",
"latest_delivery_time": "2025-10-10T07:20:50.52Z",
"subtotal": 500,
"tax": 0,
"total": 500
}
],
"messages": [],
"links": [
{
"type": "terms_of_use",
"url": "https://www.testshop.com/legal/terms-of-use"
},
{
"type": "return_policy",
"url": "https://www.testshop.com/legal/return-policy"
}
]
},
"cancel_checkout_session_request": {
"intent_trace": {
"reason_code": "shipping_cost",
"trace_summary": "User loves the item but isn't willing to pay $10 for standard shipping.",
"metadata": {
"target_shipping_cost": 0,
"competitor_reference": "amazon_prime"
}
}
},
"cancel_checkout_session_request_timing_deferred": {
"intent_trace": {
"reason_code": "timing_deferred",
"trace_summary": "User confirmed product fit and price but plans to purchase after next paycheck.",
"metadata": {
"anticipated_timeframe": "2_weeks",
"deferral_trigger": "budget_cycle"
}
}
},
"cancel_checkout_session_response": {
"id": "checkout_session_123",
"status": "canceled",
"currency": "usd",
"line_items": [
{
"id": "line_item_123",
"item": {
"id": "item_123",
"quantity": 1
},
"base_amount": 300,
"discount": 0,
"subtotal": 300,
"tax": 30,
"total": 330
}
],
"fulfillment_details": {
"name": "John Doe",
"phone_number": "15551234567",
"email": "johndoe@example.com",
"address": {
"name": "John Doe",
"line_one": "1234 Chat Road,",
"line_two": "",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94131"
}
},
"selected_fulfillment_options": [
{
"type": "shipping",
"shipping": {
"option_id": "fulfillment_option_123",
"item_ids": ["item_123"]
}
}
],
"totals": [
{
"type": "items_base_amount",
"display_text": "Item(s) total",
"amount": 300
},
{
"type": "subtotal",
"display_text": "Subtotal",
"amount": 300
},
{
"type": "tax",
"display_text": "Tax",
"amount": 30
},
{
"type": "fulfillment",
"display_text": "Fulfillment",
"amount": 100
},
{
"type": "total",
"display_text": "Total",
"amount": 430
}
],
"fulfillment_options": [
{
"type": "shipping",
"id": "fulfillment_option_123",
"title": "Standard",
"subtitle": "Arrives in 4-5 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-12T07:20:50.52Z",
"latest_delivery_time": "2025-10-13T07:20:50.52Z",
"subtotal": 100,
"tax": 0,
"total": 100
}
],
"messages": [
{
"type": "info",
"content_type": "plain",
"content": "Checkout session has been canceled."
}
],
"links": [
{
"type": "terms_of_use",
"url": "https://www.testshop.com/legal/terms-of-use"
},
{
"type": "return_policy",
"url": "https://www.testshop.com/legal/return-policy"
}
]
},
"webhook_order_create_event": {
"type": "order_create",
"data": {
"type": "order",
"checkout_session_id": "checkout_session_123",
"permalink_url": "https://www.testshop.com/orders/checkout_session_123",
"status": "created",
"refunds": []
}
},
"webhook_order_update_event": {
"type": "order_update",
"data": {
"type": "order",
"checkout_session_id": "checkout_session_123",
"permalink_url": "https://www.testshop.com/orders/checkout_session_123",
"status": "shipped",
"refunds": [
{
"type": "original_payment",
"amount": 100
}
]
}
}
}
```
## /examples/2025-12-12/examples.delegate_payment.json
```json path="/examples/2025-12-12/examples.delegate_payment.json"
{
"delegate_payment_request": {
"payment_method": {
"type": "card",
"card_number_type": "fpan",
"virtual": false,
"number": "4242424242424242",
"exp_month": "11",
"exp_year": "2026",
"name": "Jane Doe",
"cvc": "223",
"checks_performed": ["avs", "cvv"],
"iin": "424242",
"display_card_funding_type": "credit",
"display_wallet_type": "apple_pay",
"display_brand": "visa",
"display_last4": "4242",
"metadata": {
"issuing_bank": "temp"
}
},
"allowance": {
"reason": "one_time",
"max_amount": 2000,
"currency": "usd",
"checkout_session_id": "csn_01HV3P3XYZ9ABC",
"merchant_id": "acme_store",
"expires_at": "2025-10-09T07:20:50.52Z"
},
"billing_address": {
"name": "Ada Lovelace",
"line_one": "1234 Chat Road",
"line_two": "",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94131"
},
"risk_signals": [
{
"type": "card_testing",
"score": 10,
"action": "manual_review"
}
],
"metadata": {
"campaign": "q4",
"source": "chatgpt_checkout"
}
},
"delegate_payment_success_response": {
"id": "vt_01J8Z3WXYZ9ABC",
"created": "2025-09-29T11:00:00Z",
"metadata": {
"source": "agent_checkout",
"merchant_id": "acme_store",
"idempotency_key": "idem_abc123"
}
},
"delegate_payment_error_invalid_card": {
"type": "invalid_request",
"code": "invalid_card",
"message": "Invalid card number provided",
"param": "payment_method.number"
},
"delegate_payment_error_idempotency_conflict": {
"type": "invalid_request",
"code": "idempotency_conflict",
"message": "Same Idempotency-Key used with different parameters"
},
"delegate_payment_error_rate_limit": {
"type": "rate_limit_exceeded",
"code": "too_many_requests",
"message": "Too many requests, please retry later"
}
}
```
## /examples/2026-01-16/examples.agentic_checkout.json
```json path="/examples/2026-01-16/examples.agentic_checkout.json"
{
"create_checkout_session_request": {
"items": [
{
"id": "item_123",
"quantity": 1
}
],
"fulfillment_details": {
"name": "John Doe",
"phone_number": "15551234567",
"email": "johndoe@example.com",
"address": {
"name": "John Doe",
"line_one": "1234 Chat Road,",
"line_two": "",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94131"
}
}
},
"create_checkout_session_request_with_first_touch_attribution": {
"items": [
{
"id": "item_123",
"quantity": 1
}
],
"affiliate_attribution": {
"provider": "impact.com",
"token": "atp_01J8Z3WXYZ9ABC",
"publisher_id": "pub_123",
"touchpoint": "first"
}
},
"create_checkout_session_response": {
"id": "checkout_session_123",
"payment_provider": {
"provider": "stripe",
"merchant_id": "acct_1234567890",
"supported_payment_methods": [
{
"type": "card",
"supported_card_networks": ["amex", "discover", "mastercard", "visa"]
}
]
},
"authentication_provider": {
"provider": "stripe",
"merchant_id": "acct_1234567890",
"supported_authentication_methods": ["3ds"]
},
"status": "ready_for_payment",
"currency": "usd",
"line_items": [
{
"id": "line_item_123",
"item": {
"id": "item_123",
"quantity": 1
},
"base_amount": 300,
"discount": 0,
"subtotal": 300,
"tax": 30,
"total": 330,
"name": "Vintage Denim Jacket",
"description": "Classic blue denim jacket with brass buttons and adjustable waist tabs",
"images": [
"https://www.testshop.com/products/item_123/image1.jpg",
"https://www.testshop.com/products/item_123/image2.jpg"
],
"unit_amount": 300,
"custom_attributes": [
{
"display_name": "Size",
"value": "Medium"
},
{
"display_name": "Color",
"value": "Blue"
}
],
"disclosures": [
{
"type": "disclaimer",
"content_type": "plain",
"content": "This item is vintage and may show signs of previous wear."
}
]
}
],
"fulfillment_details": {
"name": "John Doe",
"phone_number": "15551234567",
"email": "johndoe@example.com",
"address": {
"name": "John Doe",
"line_one": "1234 Chat Road,",
"line_two": "",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94131"
}
},
"selected_fulfillment_options": [
{
"type": "shipping",
"shipping": {
"option_id": "fulfillment_option_123",
"item_ids": ["item_123"]
}
}
],
"totals": [
{
"type": "items_base_amount",
"display_text": "Item(s) total",
"amount": 300
},
{
"type": "subtotal",
"display_text": "Subtotal",
"amount": 300
},
{
"type": "tax",
"display_text": "Tax",
"amount": 30
},
{
"type": "fulfillment",
"display_text": "Fulfillment",
"amount": 100
},
{
"type": "fee",
"display_text": "Service Fee",
"amount": 50,
"description": "Processing and handling fee"
},
{
"type": "total",
"display_text": "Total",
"amount": 480
}
],
"fulfillment_options": [
{
"type": "shipping",
"id": "fulfillment_option_123",
"title": "Standard",
"description": "Arrives in 4-5 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-12T07:20:50.52Z",
"latest_delivery_time": "2025-10-13T07:20:50.52Z",
"totals": [
{ "type": "total", "display_text": "Shipping", "amount": 100 }
]
},
{
"type": "shipping",
"id": "fulfillment_option_456",
"title": "Express",
"description": "Arrives in 1-2 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-09T07:20:50.52Z",
"latest_delivery_time": "2025-10-10T07:20:50.52Z",
"totals": [
{ "type": "total", "display_text": "Express Shipping", "amount": 500 }
]
}
],
"messages": [],
"links": [
{
"type": "terms_of_use",
"url": "https://www.testshop.com/legal/terms-of-use"
},
{
"type": "return_policy",
"url": "https://www.testshop.com/legal/return-policy"
}
]
},
"update_checkout_session_request": {
"selected_fulfillment_options": [
{
"type": "shipping",
"shipping": {
"option_id": "fulfillment_option_456",
"item_ids": ["item_123"]
}
}
]
},
"update_checkout_session_response": {
"id": "checkout_session_123",
"status": "ready_for_payment",
"currency": "usd",
"line_items": [
{
"id": "line_item_123",
"item": {
"id": "item_123",
"quantity": 1
},
"base_amount": 300,
"discount": 0,
"subtotal": 300,
"tax": 30,
"total": 330
}
],
"fulfillment_details": {
"name": "John Doe",
"phone_number": "15551234567",
"email": "johndoe@example.com",
"address": {
"name": "John Doe",
"line_one": "1234 Chat Road,",
"line_two": "",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94131"
}
},
"selected_fulfillment_options": [
{
"type": "shipping",
"shipping": {
"option_id": "fulfillment_option_456",
"item_ids": ["item_123"]
}
}
],
"totals": [
{
"type": "items_base_amount",
"display_text": "Item(s) total",
"amount": 300
},
{
"type": "subtotal",
"display_text": "Subtotal",
"amount": 300
},
{
"type": "tax",
"display_text": "Tax",
"amount": 30
},
{
"type": "fulfillment",
"display_text": "Fulfillment",
"amount": 500
},
{
"type": "total",
"display_text": "Total",
"amount": 830
}
],
"fulfillment_options": [
{
"type": "shipping",
"id": "fulfillment_option_123",
"title": "Standard",
"description": "Arrives in 4-5 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-12T07:20:50.52Z",
"latest_delivery_time": "2025-10-13T07:20:50.52Z",
"totals": [
{ "type": "total", "display_text": "Shipping", "amount": 100 }
]
},
{
"type": "shipping",
"id": "fulfillment_option_456",
"title": "Express",
"description": "Arrives in 1-2 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-09T07:20:50.52Z",
"latest_delivery_time": "2025-10-10T07:20:50.52Z",
"totals": [
{ "type": "total", "display_text": "Express Shipping", "amount": 500 }
]
}
],
"messages": [],
"links": [
{
"type": "terms_of_use",
"url": "https://www.testshop.com/legal/terms-of-use"
},
{
"type": "return_policy",
"url": "https://www.testshop.com/legal/return-policy"
}
]
},
"complete_checkout_session_request": {
"buyer": {
"first_name": "John",
"last_name": "Smith",
"email": "johnsmith@mail.com",
"phone_number": "15552003434"
},
"payment_data": {
"token": "spt_123",
"provider": "stripe",
"billing_address": {
"name": "John Smith",
"line_one": "1234 Chat Road,",
"line_two": "",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94131"
}
}
},
"complete_checkout_session_request_with_last_touch_attribution": {
"buyer": {
"first_name": "John",
"last_name": "Smith",
"email": "johnsmith@mail.com",
"phone_number": "15552003434"
},
"payment_data": {
"token": "spt_123",
"provider": "stripe",
"billing_address": {
"name": "John Smith",
"line_one": "1234 Chat Road,",
"line_two": "",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94131"
}
},
"affiliate_attribution": {
"provider": "impact.com",
"token": "atp_01J8Z3WXYZ9ABC",
"publisher_id": "pub_123",
"touchpoint": "last"
}
},
"complete_checkout_session_response": {
"id": "checkout_session_123",
"buyer": {
"first_name": "John",
"last_name": "Smith",
"email": "johnsmith@mail.com",
"phone_number": "15552003434"
},
"status": "completed",
"currency": "usd",
"line_items": [
{
"id": "line_item_123",
"item": {
"id": "item_123",
"quantity": 1
},
"base_amount": 300,
"discount": 0,
"subtotal": 300,
"tax": 30,
"total": 330,
"name": "Vintage Denim Jacket",
"description": "Classic blue denim jacket with brass buttons and adjustable waist tabs",
"images": [
"https://www.testshop.com/products/item_123/image1.jpg"
],
"unit_amount": 300,
"marketplace_seller_details": {
"name": "VintageClothingCo"
}
}
],
"fulfillment_details": {
"name": "John Doe",
"phone_number": "15551234567",
"email": "johndoe@example.com",
"address": {
"name": "John Doe",
"line_one": "1234 Chat Road,",
"line_two": "",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94131"
}
},
"selected_fulfillment_options": [
{
"type": "shipping",
"shipping": {
"option_id": "fulfillment_option_123",
"item_ids": ["item_123"]
}
}
],
"totals": [
{
"type": "items_base_amount",
"display_text": "Item(s) total",
"amount": 300
},
{
"type": "subtotal",
"display_text": "Subtotal",
"amount": 300
},
{
"type": "tax",
"display_text": "Tax",
"amount": 30
},
{
"type": "fulfillment",
"display_text": "Fulfillment",
"amount": 100
},
{
"type": "total",
"display_text": "Total",
"amount": 430
}
],
"fulfillment_options": [
{
"type": "shipping",
"id": "fulfillment_option_123",
"title": "Standard",
"description": "Arrives in 4-5 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-12T07:20:50.52Z",
"latest_delivery_time": "2025-10-13T07:20:50.52Z",
"totals": [
{ "type": "total", "display_text": "Shipping", "amount": 100 }
]
},
{
"type": "shipping",
"id": "fulfillment_option_456",
"title": "Express",
"description": "Arrives in 1-2 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-09T07:20:50.52Z",
"latest_delivery_time": "2025-10-10T07:20:50.52Z",
"totals": [
{ "type": "total", "display_text": "Express Shipping", "amount": 500 }
]
}
],
"messages": [],
"links": [
{
"type": "terms_of_use",
"url": "https://www.testshop.com/legal/terms-of-use"
},
{
"type": "return_policy",
"url": "https://www.testshop.com/legal/return-policy"
}
],
"order": {
"id": "ord_abc123",
"checkout_session_id": "checkout_session_123",
"permalink_url": "https://www.testshop.com/orders/ord_abc123"
}
},
"get_checkout_session_response": {
"id": "checkout_session_123",
"status": "ready_for_payment",
"currency": "usd",
"line_items": [
{
"id": "line_item_123",
"item": {
"id": "item_123",
"quantity": 1
},
"base_amount": 300,
"discount": 0,
"subtotal": 300,
"tax": 30,
"total": 330
}
],
"fulfillment_details": {
"name": "John Doe",
"phone_number": "15551234567",
"email": "johndoe@example.com",
"address": {
"name": "John Doe",
"line_one": "1234 Chat Road,",
"line_two": "",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94131"
}
},
"selected_fulfillment_options": [
{
"type": "shipping",
"shipping": {
"option_id": "fulfillment_option_123",
"item_ids": ["item_123"]
}
}
],
"totals": [
{
"type": "items_base_amount",
"display_text": "Item(s) total",
"amount": 300
},
{
"type": "subtotal",
"display_text": "Subtotal",
"amount": 300
},
{
"type": "tax",
"display_text": "Tax",
"amount": 30
},
{
"type": "fulfillment",
"display_text": "Fulfillment",
"amount": 100
},
{
"type": "total",
"display_text": "Total",
"amount": 430
}
],
"fulfillment_options": [
{
"type": "shipping",
"id": "fulfillment_option_123",
"title": "Standard",
"description": "Arrives in 4-5 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-12T07:20:50.52Z",
"latest_delivery_time": "2025-10-13T07:20:50.52Z",
"totals": [
{ "type": "total", "display_text": "Shipping", "amount": 100 }
]
},
{
"type": "shipping",
"id": "fulfillment_option_456",
"title": "Express",
"description": "Arrives in 1-2 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-09T07:20:50.52Z",
"latest_delivery_time": "2025-10-10T07:20:50.52Z",
"totals": [
{ "type": "total", "display_text": "Express Shipping", "amount": 500 }
]
}
],
"messages": [],
"links": [
{
"type": "terms_of_use",
"url": "https://www.testshop.com/legal/terms-of-use"
},
{
"type": "return_policy",
"url": "https://www.testshop.com/legal/return-policy"
}
]
},
"cancel_checkout_session_request": {
"intent_trace": {
"reason_code": "shipping_cost",
"trace_summary": "User loves the item but isn't willing to pay $10 for standard shipping.",
"metadata": {
"target_shipping_cost": 0,
"competitor_reference": "amazon_prime"
}
}
},
"cancel_checkout_session_request_timing_deferred": {
"intent_trace": {
"reason_code": "timing_deferred",
"trace_summary": "User confirmed product fit and price but plans to purchase after next paycheck.",
"metadata": {
"anticipated_timeframe": "2_weeks",
"deferral_trigger": "budget_cycle"
}
}
},
"cancel_checkout_session_response": {
"id": "checkout_session_123",
"status": "canceled",
"currency": "usd",
"line_items": [
{
"id": "line_item_123",
"item": {
"id": "item_123",
"quantity": 1
},
"base_amount": 300,
"discount": 0,
"subtotal": 300,
"tax": 30,
"total": 330
}
],
"fulfillment_details": {
"name": "John Doe",
"phone_number": "15551234567",
"email": "johndoe@example.com",
"address": {
"name": "John Doe",
"line_one": "1234 Chat Road,",
"line_two": "",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94131"
}
},
"selected_fulfillment_options": [
{
"type": "shipping",
"shipping": {
"option_id": "fulfillment_option_123",
"item_ids": ["item_123"]
}
}
],
"totals": [
{
"type": "items_base_amount",
"display_text": "Item(s) total",
"amount": 300
},
{
"type": "subtotal",
"display_text": "Subtotal",
"amount": 300
},
{
"type": "tax",
"display_text": "Tax",
"amount": 30
},
{
"type": "fulfillment",
"display_text": "Fulfillment",
"amount": 100
},
{
"type": "total",
"display_text": "Total",
"amount": 430
}
],
"fulfillment_options": [
{
"type": "shipping",
"id": "fulfillment_option_123",
"title": "Standard",
"description": "Arrives in 4-5 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-12T07:20:50.52Z",
"latest_delivery_time": "2025-10-13T07:20:50.52Z",
"totals": [
{ "type": "total", "display_text": "Shipping", "amount": 100 }
]
},
{
"type": "shipping",
"id": "fulfillment_option_456",
"title": "Express",
"description": "Arrives in 1-2 days",
"carrier": "USPS",
"earliest_delivery_time": "2025-10-09T07:20:50.52Z",
"latest_delivery_time": "2025-10-10T07:20:50.52Z",
"totals": [
{ "type": "total", "display_text": "Express Shipping", "amount": 500 }
]
}
],
"messages": [
{
"type": "info",
"content_type": "plain",
"content": "Checkout session has been canceled."
}
],
"links": [
{
"type": "terms_of_use",
"url": "https://www.testshop.com/legal/terms-of-use"
},
{
"type": "return_policy",
"url": "https://www.testshop.com/legal/return-policy"
}
]
},
"webhook_order_create_event": {
"type": "order_create",
"data": {
"type": "order",
"checkout_session_id": "checkout_session_123",
"permalink_url": "https://www.testshop.com/orders/checkout_session_123",
"status": "created",
"refunds": []
}
},
"webhook_order_update_event": {
"type": "order_update",
"data": {
"type": "order",
"checkout_session_id": "checkout_session_123",
"permalink_url": "https://www.testshop.com/orders/checkout_session_123",
"status": "shipped",
"refunds": [
{
"type": "original_payment",
"amount": 100
}
]
}
},
"checkout_session_authentication_required": {
"id": "checkout_session_3ds_001",
"payment_provider": {
"provider": "stripe",
"merchant_id": "acct_1234567890",
"supported_payment_methods": [
{
"type": "card",
"supported_card_networks": ["amex", "discover", "mastercard", "visa"]
}
]
},
"authentication_provider": {
"provider": "stripe",
"merchant_id": "acct_1234567890",
"supported_authentication_methods": ["3ds"]
},
"status": "authentication_required",
"currency": "usd",
"line_items": [
{
"id": "line_item_3ds_001",
"item": {
"id": "item_3ds_001",
"quantity": 1
},
"base_amount": 5000,
"discount": 0,
"subtotal": 5000,
"tax": 375,
"total": 5375,
"name": "Premium Leather Boots",
"unit_amount": 5000
}
],
"fulfillment_details": {
"name": "Alice Example",
"phone_number": "15551234567",
"email": "alice@example.com",
"address": {
"name": "Alice Example",
"line_one": "1 Example St",
"line_two": "Unit 2",
"city": "Oakland",
"state": "CA",
"country": "US",
"postal_code": "94607"
}
},
"selected_fulfillment_options": [
{
"type": "shipping",
"shipping": {
"option_id": "ful_overnight_01",
"item_ids": ["item_3ds_001"]
}
}
],
"totals": [
{
"type": "items_base_amount",
"display_text": "Item(s) total",
"amount": 5000
},
{
"type": "subtotal",
"display_text": "Subtotal",
"amount": 5000
},
{
"type": "tax",
"display_text": "Tax",
"amount": 375
},
{
"type": "fulfillment",
"display_text": "Fulfillment",
"amount": 2500
},
{
"type": "total",
"display_text": "Total",
"amount": 7875
}
],
"fulfillment_options": [
{
"type": "shipping",
"id": "ful_overnight_01",
"title": "Overnight",
"description": "Next-business-day delivery",
"carrier": "UPS",
"earliest_delivery_time": "2026-01-13T08:00:00Z",
"latest_delivery_time": "2026-01-13T20:00:00Z",
"totals": [
{ "type": "total", "display_text": "Overnight Shipping", "amount": 2500 }
]
}
],
"messages": [],
"links": [
{
"type": "terms_of_use",
"url": "https://www.testshop.com/legal/terms-of-use"
}
],
"authentication_metadata": {
"channel": {
"type": "browser",
"browser": {
"accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"ip_address": "203.0.113.42",
"javascript_enabled": true,
"language": "en-US",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 12_3) AppleWebKit/605.1.15 (KHTML, like Gecko)",
"color_depth": 24,
"java_enabled": false,
"screen_height": 1440,
"screen_width": 900,
"timezone_offset": -480
}
},
"acquirer_details": {
"acquirer_bin": "123456",
"acquirer_country": "US",
"acquirer_merchant_id": "merchant_789",
"merchant_name": "Test Merchant",
"requestor_id": "requestor_42"
},
"directory_server": "visa",
"flow_preference": {
"type": "challenge",
"challenge": {
"type": "preferred"
}
}
}
},
"complete_session_with_authentication_result_request": {
"buyer": {
"first_name": "Alice",
"last_name": "Example",
"email": "alice@example.com"
},
"payment_data": {
"token": "spt_3ds_token_001",
"provider": "stripe",
"billing_address": {
"name": "Alice Example",
"line_one": "1 Example St",
"line_two": "Unit 2",
"city": "Oakland",
"state": "CA",
"country": "US",
"postal_code": "94607"
}
},
"authentication_result": {
"outcome": "authenticated",
"outcome_details": {
"three_ds_cryptogram": "ABCDEFGHIJKLMNOPQRSTUVWX==",
"electronic_commerce_indicator": "05",
"transaction_id": "dsTransId_12345",
"version": "2.2.0"
}
}
},
"authentication_result_example": {
"outcome": "authenticated",
"outcome_details": {
"three_ds_cryptogram": "ABCDEFGHIJKLMNOPQRSTUVWX==",
"electronic_commerce_indicator": "05",
"transaction_id": "dsTransId_12345",
"version": "2.2.0"
}
},
"error_400_requires_3ds": {
"type": "invalid_request",
"code": "requires_3ds",
"message": "This checkout session requires issuer authentication. The request must include 'authentication_result' as provided by the issuer authentication flow.",
"param": "$.authentication_result"
}
}
```
## /examples/2026-01-16/examples.capability_negotiation.json
```json path="/examples/2026-01-16/examples.capability_negotiation.json"
{
"successful_negotiation_request": {
"items": [
{
"id": "item_123",
"quantity": 1
}
],
"agent_capabilities": {
"interventions": {
"supported": ["3ds_redirect", "3ds_challenge", "address_verification"],
"max_redirects": 1,
"redirect_context": "in_app",
"max_interaction_depth": 2,
"display_context": "webview"
},
"features": {
"async_completion": true,
"session_persistence": true
}
}
},
"successful_negotiation_response": {
"id": "cs_abc123",
"status": "ready_for_payment",
"currency": "usd",
"seller_capabilities": {
"payment_methods": ["card", "card.network_token", "wallet.apple_pay"],
"interventions": {
"required": [],
"supported": ["3ds", "3ds2", "3ds_redirect", "3ds_challenge"],
"enforcement": "conditional"
},
"features": {
"network_tokenization": true,
"partial_auth": false,
"saved_payment_methods": true
}
},
"payment_provider": {
"provider": "stripe"
},
"line_items": [
{
"id": "line_item_abc",
"item": {
"id": "item_123",
"quantity": 1
},
"base_amount": 2999,
"discount": 0,
"subtotal": 2999,
"tax": 247,
"total": 3246
}
],
"totals": [
{
"type": "subtotal",
"display_text": "Subtotal",
"amount": 2999
},
{
"type": "tax",
"display_text": "Tax",
"amount": 247
},
{
"type": "total",
"display_text": "Total",
"amount": 3246
}
],
"fulfillment_options": [],
"messages": [],
"links": []
},
"incompatible_payment_method_request": {
"items": [
{
"id": "item_456",
"quantity": 1
}
],
"agent_capabilities": {
"features": {
"async_completion": true
}
}
},
"incompatible_payment_method_response": {
"id": "cs_def456",
"status": "not_ready_for_payment",
"currency": "usd",
"seller_capabilities": {
"payment_methods": ["card", "card.network_token"],
"interventions": {
"supported": ["3ds", "3ds_redirect"]
}
},
"payment_provider": {
"provider": "stripe"
},
"line_items": [
{
"id": "line_item_def",
"item": {
"id": "item_456",
"quantity": 1
},
"base_amount": 5000,
"discount": 0,
"subtotal": 5000,
"tax": 500,
"total": 5500
}
],
"totals": [
{
"type": "subtotal",
"display_text": "Subtotal",
"amount": 5000
},
{
"type": "tax",
"display_text": "Tax",
"amount": 500
},
{
"type": "total",
"display_text": "Total",
"amount": 5500
}
],
"fulfillment_options": [],
"messages": [
{
"type": "error",
"code": "payment_method_unsupported",
"content_type": "plain",
"content": "Bank transfers are not accepted. Please use a credit or debit card."
}
],
"links": []
},
"authentication_requirement_request": {
"items": [
{
"id": "item_789",
"quantity": 1
}
],
"agent_capabilities": {
"interventions": {
"supported": []
}
}
},
"authentication_requirement_response": {
"id": "cs_ghi789",
"status": "ready_for_payment",
"currency": "eur",
"seller_capabilities": {
"payment_methods": ["card"],
"interventions": {
"required": ["3ds"],
"supported": ["3ds", "3ds2", "3ds_redirect"],
"enforcement": "always"
}
},
"payment_provider": {
"provider": "stripe"
},
"line_items": [
{
"id": "line_item_ghi",
"item": {
"id": "item_789",
"quantity": 1
},
"base_amount": 25000,
"discount": 0,
"subtotal": 25000,
"tax": 5000,
"total": 30000
}
],
"totals": [
{
"type": "subtotal",
"display_text": "Subtotal",
"amount": 25000
},
{
"type": "tax",
"display_text": "Tax",
"amount": 5000
},
{
"type": "total",
"display_text": "Total",
"amount": 30000
}
],
"fulfillment_options": [],
"messages": [
{
"type": "info",
"content_type": "plain",
"content": "This purchase will require 3D Secure authentication at checkout."
}
],
"links": []
},
"bnpl_capable_request": {
"items": [
{
"id": "item_101",
"quantity": 1
}
],
"agent_capabilities": {
"interventions": {
"supported": ["3ds_redirect"],
"redirect_context": "external_browser",
"max_interaction_depth": 1,
"display_context": "redirect"
}
}
},
"bnpl_capable_response": {
"id": "cs_jkl101",
"status": "ready_for_payment",
"currency": "usd",
"seller_capabilities": {
"payment_methods": ["card", "bnpl.klarna", "bnpl.affirm"],
"interventions": {
"supported": ["3ds", "3ds_redirect"],
"enforcement": "conditional"
},
"features": {
"async_completion": true
}
},
"payment_provider": {
"provider": "stripe"
},
"line_items": [
{
"id": "line_item_jkl",
"item": {
"id": "item_101",
"quantity": 1
},
"base_amount": 89900,
"discount": 0,
"subtotal": 89900,
"tax": 7400,
"total": 97300
}
],
"totals": [
{
"type": "subtotal",
"display_text": "Subtotal",
"amount": 89900
},
{
"type": "tax",
"display_text": "Tax",
"amount": 7400
},
{
"type": "total",
"display_text": "Total",
"amount": 97300
}
],
"fulfillment_options": [],
"messages": [
{
"type": "info",
"content_type": "plain",
"content": "Pay in 4 interest-free installments with Klarna."
}
],
"links": []
},
"network_tokenization_request": {
"items": [
{
"id": "item_202",
"quantity": 1
}
],
"agent_capabilities": {
"interventions": {
"supported": ["3ds_frictionless"],
"redirect_context": "none"
},
"features": {
"session_persistence": true
}
}
},
"network_tokenization_response": {
"id": "cs_mno202",
"status": "ready_for_payment",
"currency": "usd",
"seller_capabilities": {
"payment_methods": ["card", "card.network_token"],
"interventions": {
"supported": ["3ds", "3ds2", "3ds_frictionless", "3ds_challenge"],
"enforcement": "conditional"
},
"features": {
"network_tokenization": true,
"saved_payment_methods": true
}
},
"payment_provider": {
"provider": "stripe"
},
"line_items": [
{
"id": "line_item_mno",
"item": {
"id": "item_202",
"quantity": 1
},
"base_amount": 14999,
"discount": 1500,
"subtotal": 13499,
"tax": 1111,
"total": 14610
}
],
"totals": [
{
"type": "items_base_amount",
"display_text": "Item(s) total",
"amount": 14999
},
{
"type": "items_discount",
"display_text": "Discount",
"amount": -1500
},
{
"type": "subtotal",
"display_text": "Subtotal",
"amount": 13499
},
{
"type": "tax",
"display_text": "Tax",
"amount": 1111
},
{
"type": "total",
"display_text": "Total",
"amount": 14610
}
],
"fulfillment_options": [],
"messages": [],
"links": []
},
"digital_wallet_request": {
"items": [
{
"id": "item_303",
"quantity": 2
}
],
"agent_capabilities": {
"interventions": {
"supported": ["biometric"],
"redirect_context": "none",
"display_context": "native"
}
}
},
"digital_wallet_response": {
"id": "cs_pqr303",
"status": "ready_for_payment",
"currency": "usd",
"seller_capabilities": {
"payment_methods": ["card", "card.digital_wallet", "wallet.apple_pay", "wallet.google_pay"],
"interventions": {
"supported": ["biometric", "3ds", "3ds_frictionless"],
"enforcement": "conditional"
},
"features": {
"network_tokenization": true
}
},
"payment_provider": {
"provider": "stripe"
},
"line_items": [
{
"id": "line_item_pqr",
"item": {
"id": "item_303",
"quantity": 2
},
"base_amount": 7998,
"discount": 0,
"subtotal": 7998,
"tax": 659,
"total": 8657
}
],
"totals": [
{
"type": "subtotal",
"display_text": "Subtotal",
"amount": 7998
},
{
"type": "tax",
"display_text": "Tax",
"amount": 659
},
{
"type": "total",
"display_text": "Total",
"amount": 8657
}
],
"fulfillment_options": [],
"messages": [],
"links": []
},
"minimal_agent_capabilities_request": {
"items": [
{
"id": "item_404",
"quantity": 1
}
],
"agent_capabilities": {
"payment_methods": ["card"]
}
},
"minimal_seller_capabilities_response": {
"id": "cs_stu404",
"status": "ready_for_payment",
"currency": "usd",
"seller_capabilities": {
"payment_methods": ["card"]
},
"payment_provider": {
"provider": "stripe"
},
"line_items": [
{
"id": "line_item_stu",
"item": {
"id": "item_404",
"quantity": 1
},
"base_amount": 1999,
"discount": 0,
"subtotal": 1999,
"tax": 164,
"total": 2163
}
],
"totals": [
{
"type": "subtotal",
"display_text": "Subtotal",
"amount": 1999
},
{
"type": "tax",
"display_text": "Tax",
"amount": 164
},
{
"type": "total",
"display_text": "Total",
"amount": 2163
}
],
"fulfillment_options": [],
"messages": [],
"links": []
}
}
```
## /examples/2026-01-16/examples.delegate_payment.json
```json path="/examples/2026-01-16/examples.delegate_payment.json"
{
"delegate_payment_request": {
"payment_method": {
"type": "card",
"card_number_type": "fpan",
"virtual": false,
"number": "4242424242424242",
"exp_month": "11",
"exp_year": "2026",
"name": "Jane Doe",
"cvc": "223",
"checks_performed": ["avs", "cvv"],
"iin": "424242",
"display_card_funding_type": "credit",
"display_wallet_type": "apple_pay",
"display_brand": "visa",
"display_last4": "4242",
"metadata": {
"issuing_bank": "temp"
}
},
"allowance": {
"reason": "one_time",
"max_amount": 2000,
"currency": "usd",
"checkout_session_id": "csn_01HV3P3XYZ9ABC",
"merchant_id": "acme_store",
"expires_at": "2025-10-09T07:20:50.52Z"
},
"billing_address": {
"name": "Ada Lovelace",
"line_one": "1234 Chat Road",
"line_two": "",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94131"
},
"risk_signals": [
{
"type": "card_testing",
"score": 10,
"action": "manual_review"
}
],
"metadata": {
"campaign": "q4",
"source": "chatgpt_checkout"
}
},
"delegate_payment_success_response": {
"id": "vt_01J8Z3WXYZ9ABC",
"created": "2025-09-29T11:00:00Z",
"metadata": {
"source": "agent_checkout",
"merchant_id": "acme_store",
"idempotency_key": "idem_abc123"
}
},
"delegate_payment_error_invalid_card": {
"type": "invalid_request",
"code": "invalid_card",
"message": "Invalid card number provided",
"param": "payment_method.number"
},
"delegate_payment_error_idempotency_conflict": {
"type": "invalid_request",
"code": "idempotency_conflict",
"message": "Same Idempotency-Key used with different parameters"
},
"delegate_payment_error_rate_limit": {
"type": "rate_limit_exceeded",
"code": "too_many_requests",
"message": "Too many requests, please retry later"
}
}
```
## /examples/2026-01-30/discount-extension/README.md
# Discount Extension Examples
This directory contains examples demonstrating the ACP Discount Extension functionality.
## Examples
### [order-level-discount.json](./order-level-discount.json)
Basic example of applying a fixed-amount discount code (`SAVE10` = $10 off) to an order.
### [percentage-discount-with-allocations.json](./percentage-discount-with-allocations.json)
Demonstrates a percentage discount (20% off) with detailed `allocations` showing exactly how the discount was distributed across multiple line items.
### [automatic-discount.json](./automatic-discount.json)
Shows an automatic discount applied by the merchant without any code input. In this example, free shipping is automatically applied when the order exceeds $50.
### [rejected-discount-code.json](./rejected-discount-code.json)
Demonstrates how rejected discount codes are communicated via:
- The `discounts.rejected` array with the code and reason
- The `messages[]` array to surface warnings to users
One code succeeds (`SAVE10`), one is rejected as expired (`EXPIRED50`).
### [stacked-discounts.json](./stacked-discounts.json)
Complex example showing multiple discounts stacked together with:
- Priority ordering (which discount is calculated first)
- Different allocation methods (`each` vs `across`)
- `each` discounts include allocations; `across` discounts apply to order total
## Key Concepts
### Request Format
```json
{
"discounts": {
"codes": ["DISCOUNT_CODE_1", "DISCOUNT_CODE_2"]
}
}
```
### Response Format
```json
{
"capabilities": {
"payment_methods": ["card"],
"extensions": [
{
"name": "discount",
"extends": [
"$.CheckoutSessionCreateRequest.discounts",
"$.CheckoutSessionUpdateRequest.discounts",
"$.CheckoutSession.discounts"
]
}
]
},
"discounts": {
"codes": ["DISCOUNT_CODE_1", "DISCOUNT_CODE_2"],
"applied": [
{
"id": "di_abc123",
"code": "DISCOUNT_CODE_1",
"coupon": {
"id": "coupon_xyz",
"name": "Discount Name",
"percent_off": 20
},
"amount": 1000,
"allocations": [...]
}
],
"rejected": [
{
"code": "DISCOUNT_CODE_2",
"reason": "discount_code_expired",
"message": "Code expired on December 1st"
}
]
}
}
```
### The `extends` Field
The `extends` field uses JSONPath expressions to precisely identify which schema fields are added by the extension:
| JSONPath | Description |
|----------|-------------|
| `$.CheckoutSessionCreateRequest.discounts` | Adds `discounts` to create requests |
| `$.CheckoutSessionUpdateRequest.discounts` | Adds `discounts` to update requests |
| `$.CheckoutSession.discounts` | Adds `discounts` to session responses |
### The `schema` Field (Optional)
The optional `schema` field provides a URL to a JSON Schema defining the structure of the extension's added fields:
```json
{
"name": "discount",
"extends": ["$.CheckoutSession.discounts"],
"schema": "https://agenticcommerce.dev/schemas/discount/2026-01-27.json"
}
```
This enables:
- **Runtime validation** of extension data
- **SDK generation** from the schema
- **Interoperability** with unknown extensions
### Allocation Methods
| Method | Description | Allocations |
|--------|-------------|-------------|
| `each` | Discount calculated independently for each item | Typically included |
| `across` | Discount applied to order total | Typically omitted |
### Priority Ordering
When multiple discounts are stacked, `priority` determines calculation order:
- Priority 1 is applied first
- Lower numbers = earlier in calculation
- Each subsequent discount is calculated on the already-discounted amount
## Related Documentation
- [RFC: Extensions Framework](../../rfcs/rfc.extensions.md)
- [RFC: Discount Extension](../../rfcs/rfc.discount_extension.md)
- [JSON Schema](../../spec/unreleased/json-schema/schema.discount.json)
## /examples/2026-04-17/orders/simple-order.json
```json path="/examples/2026-04-17/orders/simple-order.json"
{
"$schema": "../../../spec/2026-04-17/json-schema/schema.agentic_checkout.json#/$defs/Order",
"_description": "Minimal order with only required fields. Backward-compatible with existing implementations.",
"id": "ord_minimal_123",
"checkout_session_id": "cs_abc789",
"permalink_url": "https://merchant.example.com/orders/ord_minimal_123"
}
```
## /examples/orders/simple-order.json
```json path="/examples/orders/simple-order.json"
{
"$schema": "../../spec/unreleased/json-schema/schema.agentic_checkout.json#/$defs/Order",
"_description": "Minimal order with only required fields. Backward-compatible with existing implementations.",
"id": "ord_minimal_123",
"checkout_session_id": "cs_abc789",
"permalink_url": "https://merchant.example.com/orders/ord_minimal_123"
}
```
## /scripts/pre-commit-hook.sh
```sh path="/scripts/pre-commit-hook.sh"
#!/bin/bash
#
# Git pre-commit hook for validating specification consistency
#
# To install:
# ln -s ../../scripts/pre-commit-hook.sh .git/hooks/pre-commit
#
# To bypass for emergency commits:
# git commit --no-verify
#
echo "🔍 Running specification consistency checks..."
# Run validation
pnpm run validate:all
# Capture exit code
EXIT_CODE=$?
if [ $EXIT_CODE -ne 0 ]; then
echo ""
echo "❌ Validation failed! Commit blocked."
echo ""
echo "To fix:"
echo " 1. Review the errors above"
echo " 2. Run 'pnpm run validate:all' to test fixes"
echo " 3. Try committing again"
echo ""
echo "To bypass (not recommended):"
echo " git commit --no-verify"
echo ""
exit 1
fi
echo "✅ All validations passed!"
exit 0
```
The content has been capped at 50000 tokens. The user could consider applying other filters to refine the result. The better and more specific the context, the better the LLM can follow instructions. If the context seems verbose, the user can refine the filter using uithub. Thank you for using https://uithub.com - Perfect LLM context for any GitHub repo.