Skip to content

feat: add Target provider - #110

Merged
eshaffer321 merged 3 commits into
eshaffer321:mainfrom
daslicious:feat/target-provider
Oct 31, 2026
Merged

eshaffer321 merged 3 commits into
eshaffer321:mainfrom
daslicious:feat/target-provider

Conversation

@daslicious

Copy link
Copy Markdown
Contributor

Adds itemize target: syncs Target in-store receipts (those linked to Target Circle) and online orders into Monarch, like the other providers.

How it works

Target has no public API, so the provider uses the JSON APIs that target.com's own order pages call. The client is a separate module, daslicious/target-go (MIT), in the same way costco-go and walmart-client-go are separate. Its PROTOCOL.md documents the endpoints, login renewal and how orders map to card charges.

  • Login: you sign in once in an Incognito window, copy the orders page's history request as cURL, and pipe it to itemize target set-session -account <name>. The login is saved only if Target accepts the replayed request. Before each run, the 24-hour access token is renewed and the rotated refresh token is saved immediately. The refresh token lasts 180 days, and the session file is shared under a lock file. The README section has the steps.
  • Charges: a receipt matches its card tenders. Reusable-bag discounts, gift cards and manufacturer coupons are left out of the amount. Target charges an online order once per shipment, so an order charged in parts is synced as one order per charge (<order>, <order>-2, …), priced from that charge's invoice lines. Cancelled items, and orders paid entirely by gift card, are left out.
  • Items: each item has Target's unit price, quantity and product type. The Circle Card 5% discount and tax are spread by the existing splitter. Orders go through the Simple handler with the default matcher settings.
  • Commands: itemize target (sync), target orders (prints orders as JSON, no Monarch), target refresh, target set-session. Target is also registered for itemize serve, using the default login.
  • Errors scripts can match: target auth check failed (expired login) and target blocked the request (bot protection). Requests are paced 3–5 s apart.

Testing

  • go test -race ./... passes. golangci-lint v2.14.0 reports 0 issues.
  • The fixtures keep Target's real response shapes (HTML entities in descriptions, amounts sent as strings, Central-time offsets), but all ids, stores, dates and items are made up.
  • I've run this provider daily since 2026-10-11 on two Target logins, as part of a fork with a few other local patches.
  • I ran a full-history check against two years of one household's Target purchases (94 online orders, 50 receipts): 142 of 143 posted orders and charges matched a bank transaction to the cent. The remaining one is an invoice paid as two card payments.
  • I also dry-ran this branch (upstream main plus this commit only) against both logins. Every order not already split matched its Monarch transaction within the default 5-day window; the bank posts Target charges 1–3 days after the order date.

Notes for review

  • If you'd rather not depend on a module under my account, I can move the client into internal/ instead.
  • I didn't add a config struct: the session directory comes from ITEMIZE_TARGET_DIR, defaulting to ~/.itemize/target, the same convention as ~/.itemize/amazon. I'm happy to move it into config.yaml.

🤖 Generated with Claude Code

daslicious and others added 3 commits October 26, 2026 14:22
Syncs Target in-store receipts (linked to Target Circle) and online orders.
Target has no public API, so the provider uses the JSON APIs target.com's own
order pages call, through github.com/daslicious/target-go (client, session
handling, field notes in its PROTOCOL.md).

- Login: a DevTools "Copy as cURL" of the orders page's history request,
  saved with `itemize target set-session -account <name>` after Target accepts
  it. Each run renews the 24-hour access token first and saves the rotated
  refresh token at once (shared lock file, so other tools can use the login).
- Card charges: receipts match their card tenders; reusable-bag discounts, gift
  cards and manufacturer coupons are left out. An online order charged once
  per shipment becomes one order per charge (<order>, <order>-2, ...), priced
  from its invoice lines. Cancelled items and orders paid entirely by gift
  card are left out.
- Items carry Target's unit price, quantity and product type; the Circle Card
  5% and tax are spread by the splitter. Items Target sends without a name take
  it from the history entry; otherwise the order fails and is retried later.
- Commands: `itemize target` (sync), `target orders` (JSON, no Monarch),
  `target refresh`, `target set-session`. Also registered for `itemize serve`.
- Errors scripts can match: `target auth check failed`,
  `target blocked the request` (bot protection; requests are paced 3-5 s).

Checked against two years of one household's Target history (94 online
orders, 50 receipts): 142 of 143 posted orders and charges match a bank
transaction to the cent. Test fixtures keep Target's response shapes with
made-up ids, stores, dates and items.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov

codecov Bot commented Oct 31, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.81315% with 41 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.88%. Comparing base (c450097) to head (d4e6b49).

Files with missing lines Patch % Lines
internal/adapters/providers/target/provider.go 79.41% 19 Missing and 9 partials ⚠️
internal/adapters/providers/target/order.go 91.50% 11 Missing and 2 partials ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #110      +/-   ##
==========================================
+ Coverage   66.12%   66.88%   +0.76%     
==========================================
  Files          51       53       +2     
  Lines        7164     7453     +289     
==========================================
+ Hits         4737     4985     +248     
- Misses       2081     2111      +30     
- Partials      346      357      +11     
Flag Coverage Δ
unittests 66.88% <85.81%> (+0.76%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
internal/application/service/sync_service.go 35.05% <ø> (ø)
internal/adapters/providers/target/order.go 91.50% <91.50%> (ø)
internal/adapters/providers/target/provider.go 79.41% <79.41%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@eshaffer321
eshaffer321 merged commit 1ca6210 into eshaffer321:main Oct 31, 2026
14 checks passed
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.

2 participants