Skip to content

Repository files navigation

PunchOut Sandbox

A hosted virtual supplier for testing e-procurement integrations. cXML PunchOut, OCI, order confirmation, dispatch notification, and the invoice flow back — pointed at by anyone building a buyer-side punchout client who has nowhere else to point it.

It also answers the question a validator cannot: what survives ingestion. cXML imposes almost no length limits, so every limit that truncates your data is imposed by the buyer platform and none of them publish it. /ingest applies what Ariba, Coupa, JAGGAER and Oracle each do on receipt and shows you what is left.

Live at punchoutsandbox.com. Free, no paid tier, MIT.


Why this exists

Every free punchout tool in existence runs the wrong way. They simulate a buyer so that a supplier can check their catalogue works. Nobody built the mirror image, so a developer writing the buyer side has nothing to test against — and can only test their integration against itself.

That distinction is the whole point, and it is worth being precise about:

Round-tripping your own buildextract proves the two halves agree with each other. It does not prove either conforms to the spec. If both share a misreading, every test passes and the first real supplier rejects every document.

What is missing is an independent judge — and, per RESEARCH.md, no vendor or network anywhere issues one. TradeCentric, Greenwing, Cloudfy, Coupa, SAP Ariba and Jaggaer all do bilateral, buyer-coordinated sign-off instead. There is no portable conformance report at any price.

This service is that judge. Everything else here is a plausible-looking shop that exists so the judge has something to judge.

What it does

  • Serves a real punchout session. Point your cXML PunchOutSetupRequest or OCI call-up at it, browse a catalogue of 96 products with genuine UNSPSC codes, return a conformant cart. Full OCI support including DETAIL, VALIDATE and BACKGROUND_SEARCH.
  • Validates every document against the actual cXML DTDs (vendored 1.2.071), in both directions, and tells you exactly what is wrong and where — every error with its line number, element and a hint.
  • Separates errors from advisories. Errors come from the DTD and are not a matter of opinion. Advisories are things a DTD cannot express but that break real integrations — a dropped SupplierPartAuxiliaryID, mixed currencies, totals that do not add up, each where EA was meant.
  • Runs the whole downstream flow: purchase order in, then order confirmation, dispatch notice and invoices with multi-country tax (VAT, GST, sales tax, reverse charge) across 27 jurisdictions — POSTed to your own cXML inbox so you can test the half nobody can normally test.
  • Shows what survives ingestion. /ingest applies what each buyer platform silently truncates, rounds or defaults.
  • Hands you documents built to break your parser. /samples serves a worked example of every message, plus an adversarial set: conformant cXML that disagrees with the order in exactly one way a real supplier really does — despatched in a different unit, partially shipped, confirmed at a changed price.
  • Has a machine path. JSON API, credentials in headers, no browser anywhere — see below.

Status

Live and in use. Deployed on AWS Lambda behind Cloudflare, £0/month, no billing and no SLA. See BRIEF.md §8 for the honest commercial read: this is deliberately a free tool, not a product. It is worth more as credibility and reach into the audience that buys procurement software than as revenue.

Protocols cXML PunchOut, SAP OCI
Documents PunchOutSetupRequest · PunchOutOrderMessage · OrderRequest · ConfirmationRequest · ShipNoticeRequest · InvoiceDetailRequest
Tests 13 suites, plus a 147-check QA suite that runs against the deployed site
Not built multipart/related attachments; OCI SOURCING (SAP never implemented it either)

Its first serious use by an outside integrator found six defects in their implementation in an afternoon — and three in this one, all since fixed and each now pinned by a test.

Repository layout

app/                 the Lambda application
  xml_safe.py        THE hardened parser — nothing else may touch raw XML
  validation.py      the independent judge; this module is the product
  cxml/dtd/          vendored cXML 1.2.071 DTDs (see that directory's README)
  ui/                design system and templates
  api.py             the JSON machine path
  platforms.py       what each buyer platform does to a cart on ingestion
  samples.py         worked and adversarial example documents
infra/               Python CDK — DataStack + SiteStack
  scripts/           Cloudflare DNS, edge secret, SES, search verification
BRIEF.md             the idea, the case against, and the verdict
RESEARCH.md          market evidence behind that verdict
HOSTING.md           hosting, the AWS account layout, and the QA findings
INTEGRATING.md       quick start for buyer-side developers
docs/reference/      the conformance material, published at /reference

Integrating against it

INTEGRATING.md is the quick start: credentials, the JSON API, the four integration points, and the five things that otherwise cost an afternoon. The full documentation goes deeper.

For agents and scripts

No browser needed at any point:

curl -sX POST https://punchoutsandbox.com/api/signup -d '{"email":"you@company.com"}'

Then POST /api/validate with X-Sandbox-Identity / X-Sandbox-Secret headers returns the full conformance report as JSON — every error with its line, element and hint. POST /api/ingest returns what each buyer platform would do to a cart. Worked, DTD-valid examples of every document are at /samples.

The punchout round trip is headless too: a live punchout session authorises the storefront on its own, because the shopper is the buyer's employee and the buyer's system already authenticated for them.

Running locally

python3 -m venv .venv && .venv/bin/pip install -r requirements.txt

Then start the dev server — it uses in-memory stores, so no AWS credentials are needed:

.venv/bin/python -m app.handler

Running the tests

Each suite is a plain script that prints what it checked and why, and exits non-zero on failure. No test runner, no fixtures to learn.

for t in tests/test_*.py; do .venv/bin/python "$t" || break; done

They are worth reading as documentation. test_orders.py and test_invoice.py validate every generated document against the real cXML DTDs, which is the claim this whole project rests on; test_dtd_licence.py enforces the terms those DTDs ship under.

Deploying

cd infra && cdk deploy --all && python scripts/deploy_cloudflare_dns.py

Cloudflare credentials come from the environment (CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID) and are never committed. See the deploy script's docstring.

Licence

This project's own code is MIT — see LICENSE.

The vendored cXML DTDs in app/cxml/dtd/ are not. They are copyright Ariba, Inc. and ship under the cXML License Agreement, which permits copying and distributing the unmodified Specification provided the licence is attached. Both conditions are enforced by tests/test_dtd_licence.py rather than left as good intentions: it checksums every DTD and fails if one is edited.

Practical upshot: MIT's permission to modify stops at those files. If a DTD needs changing, the change belongs upstream, not here.

The licence URL printed inside the DTDs themselves (cxml.org/home/license.asp) is dead and returns 404; the live agreement is at cxml.org/license.html. app/cxml/dtd/README.md has the full reasoning.

Generated invoices and PDFs are synthetic, always watermarked as test artifacts, and always for invented companies. Never generate documents carrying a real company's name or branding.

About

No description or website provided.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages