Skip to content

Add fattureincloud-style and escrow-style adapters - #47

Merged
deblasis merged 2 commits into
mainfrom
add-fattureincloud-and-escrow-adapters
Aug 15, 2026
Merged

Add fattureincloud-style and escrow-style adapters#47
deblasis merged 2 commits into
mainfrom
add-fattureincloud-and-escrow-adapters

Conversation

@deblasis

Copy link
Copy Markdown
Contributor

What

Two new reference adapters, contributed from real integration work (a
marketplace that verifies company revenue and needed local sims for
bookkeeping and escrow flows).

fattureincloud-style

A Fatture in Cloud-style bookkeeping API v2 simulator — useful for
testing anything that reads supplier-side documents ("what does this
company spend, and on what?") or issues invoices.

  • Surface (40 endpoints): entities (companies), received documents
    and issued documents (full CRUD + the metodata /info endpoint),
    suppliers, clients, products (full CRUD), taxes, cashbook, webhooks,
    archive.
  • Conventions modelled deliberately — the parts of the API's shape
    that client code gets wrong when a sim is thinner than the real thing:
    • Laravel-style pagination envelopes (current_page/last_page/
      total) — a client that assumes one page is wrong in test, not in
      production.
    • {"data": {...}} wrappers on single resources.
    • Company-id scoping where a foreign or unknown id is an
      indistinguishable 404.
    • Genuine 401 with the v2 error shape for a missing bearer (any
      non-empty bearer is accepted for frictionless local testing).
    • Amounts as decimal strings ("9800.00") — casting instead of
      parsing is how a real integration ships a NaN.
  • Not modelled (documented in the README): the OAuth token dance,
    e-invoice send/retrieve side effects, email dispatch — no local-test
    observable behaviour.

escrow-style

An Escrow.com-style transaction API simulator (public 2017-09-01
surface) — the licensed-escrow lifecycle without remote accounts or money.

  • Create with parties (buyer + seller required), items with payment
    schedules, caller-controlled or defaulted fee split (buyer pays 3.25%).
  • Per-party agreement via PATCH with {"action": "agree", "customer"};
    secured-state transitions on funding.
  • Lookup by numeric id or caller reference; webhook registration.
  • A clearly-namespaced /sim/transaction/{id}/fund affordance stands in
    for the buyer paying on the provider's hosted page — which no API can
    drive. Namespaced so it can never be confused with API surface.

Verification

  • stunt adapter lint clean on both (zero warnings).
  • Conformance tests in internal/engine/ following the existing
    adyen_style_test.go pattern: 401/404 paths, pagination envelope,
    decimal-string amounts, metodata categories, CRUD round-trips, and the
    full create → agree (×2) → fund → secured escrow lifecycle.
  • go test ./... green.

🤖 Generated with Claude Code

Dev and others added 2 commits August 15, 2026 14:29
Two new reference adapters, both with conformance tests.

fattureincloud-style: a Fatture in Cloud-style bookkeeping API v2
simulator — entities, received/issued documents (CRUD + metodata),
suppliers, clients, products (CRUD), taxes, cashbook, webhooks, archive.
It models the conventions client code gets wrong against thinner sims:
Laravel pagination envelopes (last_page must be followed), {data}
wrappers, company-id scoping where a foreign id is an indistinguishable
404, genuine 401s for missing bearers, and amounts as decimal strings.

escrow-style: an Escrow.com-style transaction API simulator (public
2017-09-01 surface) — create with parties/items/schedules and a
caller-controlled or defaulted fee split, per-party agreement via PATCH,
secured-state transitions, lookup by id or reference, webhook
registration, and a clearly-namespaced /sim fund affordance standing in
for the hosted payment page no API can drive.

Both pass `stunt adapter lint` clean; `go test ./internal/engine/` covers
the 401/404 paths, pagination, decimal-string amounts, the metodata
endpoint, and the full agree→fund lifecycle.
…n schema, platform conformance

Reviewer findings on PR #47 (2 criticals, 8 majors, 8 minors):

fattureincloud-style:
- CRITICAL: routes re-schemed to the real v2 API — /c/{company_id}/...
  resources, /user/companies discovery (no invented create-company),
  /c/{company_id}/company/info; tests updated
- json.loads (not a builtin; 500s) -> json_safe_decode with raw_body as
  the authoritative source (undecodable bodies surfaced as empty dicts
  via req.body); malformed JSON -> 400 flat OAuth shape
- webhook subscriptions: company-scoped /c/{company_id}/subscriptions in
  the real shape (data.sink/types/config, SUB ids, verified/warnings),
  delivering SIGNED events (X-Signature base64 HMAC-SHA256, documented
  synthetic secret) on document/entity CRUD
- /taxes is the v2 F24 collection (CRUD), not v1 VAT bands
- archive upload accepts real multipart via parse_multipart (blob-backed)
- platform builtins: query_select filters, paginate-based Laravel
  envelope; error shapes (401 flat, 404+ SCREAMING_SNAKE nested);
  int ids; _batch/internal keys stripped; concurrency_key on PUT/DELETE
- seeded company (discovery needs one to exist)

escrow-style:
- CRITICAL: Transaction no longer carries a top-level status (the_bad_boys
  et al removed): funding on items[].schedule[].status.secured, item
  lifecycle on items[].status; close_date/is_cancelled added
- basic auth (401 + WWW-Authenticate, documented synthetic credentials);
  real nested validation error shape; customer_type dropped
- initiating party auto-agreed at creation; agree requires customer;
  amounts/fees as decimal strings (integer-cent math); clock-derived
  timestamps; webhook ids stable between create/list (int-rendered)
- webhooks actually fire on lifecycle transitions (unsigned-by-design);
  list endpoint added (paginate); concurrency_key on PATCH/fund
@deblasis
deblasis merged commit 58734b7 into main Aug 15, 2026
1 check passed
@deblasis
deblasis deleted the add-fattureincloud-and-escrow-adapters branch August 15, 2026 17:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant