The problem
A small shop's stock arrives through one door. A supplier sends a purchase order and an invoice. Then the carrier scans "delivery attempted, business closed" while the owner was open, and the owner has nothing to show the dispute desk. The shop's Ring doorbell already saw who stood at the door and when. Nobody was using it.
Why it costs real money. A disputed delivery is stock the shop has paid for or ordered and does not have, and the owner usually can't prove the carrier's scan was wrong. That lands on businesses with no slack. In the Federal Reserve's 2026 Small Business Credit Survey of about 6,500 US employer firms, 54% struggled to pay operating expenses (payroll, rent, inventory), 50% had uneven cash flow, and 73% were hit by rising costs of goods and wages. 46% had trouble hiring or keeping staff, so nobody is free to watch the door, take a delivery or chase a carrier.
What nobody measures. We found no survey that counts disputed carrier scans, so we make no dollar claim for Shopfront. The figures above are the cash-flow reality a lost or unprovable delivery lands on. What Shopfront changes is the evidence: for each expected delivery, the shop sees whether the door recorded a courier near the scan time, and for a false "business closed" scan it gets a dispute pack to review. It reports "nothing recorded at the door" as exactly that, never as proof.
Who it is for. Owners of one-door shops (bakery, cafe, boutique) who already have a Ring doorbell and receive supplier deliveries.
What it does
Shopfront is a receiving desk for one-door shops. Try the demo: live on AWS. Code: github.com/danielAsaboro/shopfront (MIT).
- Orders and invoices in. A CSV export becomes the list of expected deliveries; bad rows are reported by line number. How it works, tested in test_orders.py and test_receiving_desk.py.
- Ring as the receipt. A signed Ring webhook whose motion sub_type is
package_deliverymarks a courier visit with no model call (webhook receiver, test_webhooks.py). Other events go to Amazon Bedrock with the Ring frame, or fall back to time-of-day rules, and every label shows who made it and why (classifier docs). - Optimal matching. Expected deliveries are matched to courier visits as an optimal assignment, so one visit never backs two receipts (receipts.md, property tests).
- False "business closed" scans. The carrier's attempt time is checked against the shop's posted hours and the door activity around it. Five outcomes, each worded to the evidence it cites; "nothing recorded" is never presented as proof (reconcile.py, test_reconcile.py).
- Disputes. A Strands agent on Amazon Bedrock answers from five read-only tools and returns every tool call with the answer. The dispute pack and its draft are for the owner to review; Shopfront never sends them (dispute.py, test_dispute_pack.py).
- Fails closed. If Ring refuses a call, the page names the reason (for example TOKEN_REJECTED or MEDIA_NOT_FOUND) instead of showing made-up numbers (Ring client, test_ring_api.py).
Proof, and what is not proven
Every claim is labelled in the README proof table: live only with a request ID, otherwise "local test".
| Claim | Evidence |
|---|---|
| Ring Partner API called with a real Developer Playground token: devices 200, Event History 200 (empty) | ring-proof-20261015T082514Z.json |
| Ring live view (WHEP) session opened: 201, WebRTC connected | ring-live-view-20261015T0826Z.json |
| Invalid token maps to a named state (401, X-Request-ID recorded) | ring-invalid-token-check-20261014T175049Z.json |
| AWS stack deployed in us-east-1; signed webhook replays passed all ten checks | aws-deploy-20261023T105924Z.json, infra/template.yaml, docs/aws.md |
| Matcher, scan checks, webhooks, dispute packs | local tests in tests/ |
How we built it
Python, FastAPI, httpx and boto3. Ring: Event History, image download, token refresh, live view and HMAC-SHA256 webhooks that de-duplicate on request_id. AWS: Bedrock Converse with an image block (Claude Haiku 4.5) and a Strands agent, plus a SAM stack of Lambda Function URLs, DynamoDB, Secrets Manager, KMS, S3, SQS, SNS and CloudWatch for the webhook endpoint and the public demo. Amazon Bedrock AgentCore is not used.
Challenges
- The Playground sends no webhooks, so we replay signed payloads in Ring's documented shape. Every replayed event and every dispute pack built on one says so.
- Ring has no "door answered" signal, so we report what the door recorded and never claim a delivery was missed (limits).
- Greedy matching had two real bugs that property tests exposed; it is now an optimal assignment.
What we learned
A claim is only worth making when it points to a request ID or a test. The honest proof table cost us a "live" row or two, and that is the point.
What's next
A Ring Appstore app with one-way account linking, a measured Bedrock courier precision on frames labelled by two people (eval harness), and webhook-driven same-day alerts.
Disclosures
Solo entry. Built with AI coding assistance (Claude Code). New project, first commit 8 October 2026, inside the submission window.
Built With
- amazon-bedrock
- aws-lambda
- boto3
- fastapi
- python
- ring
- strands
Log in or sign up for Devpost to join the conversation.