Inspiration

In Lagos and Cotonou, gated compounds, small shops and clinics depend on one person at the gate: the gateman. Anyone can claim to be a delivery rider, a technician or a relative. Delivery scams, fake "officials" and distraction thefts are everyday risks, and the people who own the property are often far away. Many of them are family members living abroad who pay for the security but cannot see who is at the gate.

I wanted a doorbell that does more than ring. It should find out who is there and why, and put a clear decision in the hands of the right person, even when the network or the visitor's phone is not cooperating.

What it does

GateGuard turns a Ring doorbell press into a verified visit:

Ring event in. A signed Ring webhook (HMAC-SHA256 X-Signature) reaches the GateGuard API. Unsigned or tampered requests are rejected. Verification call. GateGuard places a short call to the visitor with CALL-E, my AI calling engine, and asks who they are and why they are here. The structured result (name, purpose, concern) comes back as data. Second opinion. Amazon Bedrock (Claude Haiku 4.5) reads the same answers and independently flags anything suspicious, with a plain-English reason. Decision. A web dashboard shows the visitor card with both opinions. A family member or manager approves or denies from anywhere. Fallback. If the visitor cannot be called, or the network is poor, the event goes to the gateman's phone app, which shows the same queue with large Let in and Turn away buttons. Both screens read the same API, so the dashboard and the phone always agree.

How I built it

API: NestJS and TypeScript in a monorepo. An API-key guard protects every route, and the Ring webhook has its own signature guard. Calling engine: CALL-E, with a dry-run mode and a double-confirmation guard before any live call can be placed. Results are requested as a strict JSON schema. AI second opinion: Amazon Bedrock InvokeModel with Claude Haiku 4.5 through a cross-region inference profile. On the server it uses an IAM role, so no keys are stored. Web: React and Vite dashboard that updates every few seconds. Mobile: React Native with Expo and TypeScript, built for a gateman on a small phone. Hosting: AWS EC2 on Amazon Linux 2023, with Nginx, PM2 and HTTPS from Let's Encrypt, deployed with a push to GitHub and a one-line pull on the server. Ring: webhook receiver with signature verification, plus account-link endpoints for Ring's OAuth flow.

Challenges

Ring has no event simulator. Ring's docs describe webhooks that fire from real devices, and staging needs a registered device in the US. I built and tested the receiver against signed payloads in Ring's documented v1.1 shape, and I am being open about that in this submission. Account linking docs describe two models. The nonce-based flow and the older redirect-and-code flow are both documented, and the portal's field names did not map cleanly onto either. Bedrock gotchas. A retired model, the need for a cross-region inference profile, and an "Operation not allowed" error until the AWS account finished verification each cost time. Security details. Refusing the example API key on any non-local request, verifying signatures against the raw body, and never logging full phone numbers.

What I learned

Signature verification must use the raw request body. A second, independent AI opinion catches cases a single call misses. Offline fallbacks are a core part of the design in places where connectivity cannot be assumed. And an honest demo mode is better than a faked live one.

What is next

Persist events and decisions in Amazon DynamoDB. Finish Ring account linking and test with a real device as a staging user. Push notifications to the family approver, and a voice or WhatsApp approval option. Per-site rules: trusted delivery companies, house codes and visiting hours. Support for Benin's French-language calls and Nigerian Pidgin.

Share this project:

Updates

Submission history