Backend engineer at Pictory, working on billing and payments. Remote from India (IST).
Pictory is an AI video product. I joined as a trainee in 2022 and moved to the backend team in 2023. Most of my work since has been the billing stack: subscriptions and plan changes, checkout, affiliate payouts, and the credits that meter AI usage.
We are a small team, so I usually get to see a system through from design to rollout and the fixes after. The write-ups below say where others did part of the work.
Work
Four systems in production.
01INR billing and RBI e-mandates
led the backend work
Context
The Reserve Bank of India's e-mandate rules require recurring card debits to run against a registered mandate, with cardholder authentication at registration and a notification to the cardholder before each debit. Our subscriptions billed in USD with no mandate, so renewals on Indian cards failed.
What I built
INR as a second billing currency, e-mandate registration for Indian cards through the payment provider, and mandate-based recurring debits for renewals. The billing system had assumed one currency and became multi-currency.
Result
Indian customers subscribe on local cards again; renewals debit a registered mandate.
02Credits and quotas for AI usage
designed and built
Context
Every plan includes an allowance of credits spent on image, video and audio generation. Several generation paths spend from the same balance, so the check and the debit have to be consistent or a user can spend more than they have.
What I built
One credits service that every generation path debits through. The balance check and the debit happen as one operation, so two concurrent jobs cannot both pass the check. The same service handles plan changes: an upgrade or downgrade adjusts the customer's allowance.
Decisions
One debit path rather than a quota check per generation path. Having several call sites with slightly different checks is how overspend happens.
Result
Usage is enforced in one place, and upgrades and downgrades go through the same service.
03Affiliate payouts from Stripe and PayPal webhooks
built the backend
Context
Affiliates earn a commission on referred purchases. Purchase events arrive as Stripe and PayPal webhooks, and both providers redeliver on timeout, so a payout path that isn't idempotent will eventually pay someone twice.
What I built
Webhook consumers for both providers, the payout APIs, and abuse detection on referrals. The APIs that create payouts are idempotent: a redelivered webhook or a retried request is a no-op, not a second payout.
Result
Duplicate payouts are prevented by design, and referral abuse is caught before a payout is approved.
04Checkout before signup
React checkout and backend purchase path
Context
Buying a plan took about two minutes and required creating an account before paying.
What I built
A purchase path where payment comes first and the account is attached afterwards, with Redis caching on the purchase path.
Result
Time to complete a purchase went from about two minutes to about ten seconds, measured before and after the change.
Also
Editor memory. Virtualised the visuals tab of the video editor so only on-screen assets are rendered. Memory on a project with about 1,000 assets went from roughly 1 GB to 138 MB, measured before and after.
Braintree. Integrated it as an additional card processor with one other engineer and took it live for new customers.
Cancel flow. A churn-mitigation step in the cancellation path, instrumented in Amplitude. Same area: reactivation and account data deletion.
Trainee year. An internal support tool (Lambda, DynamoDB, Flask, React) that automated common ticket resolutions, including a generic DynamoDB update-expression builder so a new form field didn't need a backend deploy. Also wrote and tested the APIs (Jest, Frisby) exposed to an enterprise customer.
A webhook reliability layer with an LLM on the failure path only. It verifies the Stripe signature with a timestamp tolerance window, stores each event once under a unique constraint on the event id so redeliveries are no-ops, then processes it. Each failed attempt bumps a counter; at three the event is dead-lettered. Retries are explicit: any event can be replayed from its stored payload, re-running the existing row rather than re-ingesting it.
Dead-lettered events are triaged on demand, one per call or in batch, with a single forced-tool-use LLM call that classifies them as transient, config error, genuine payment failure, or needs a human, and writes a suggested action and a self-reported confidence back to the row. The classifier backend is pluggable: the Anthropic Messages API or any OpenAI-compatible endpoint. A 500-event synthetic corpus with held-out labels, the eval harness, the seeder and 20 tests (ingest, replay, signature, classifier contract) ship with the project.
Yapp.A support chatbot you point at your own docs. Ingests URLs, sitemaps, PDFs and YouTube transcripts through a job queue, chunks and embeds into pgvector, answers with retrieval, and ships as an embeddable chat widget. Next.js, TypeScript, Prisma, Supabase.
PostureGuard.Runs MediaPipe pose in the browser via WASM, never sends video anywhere, and alerts after one second of confirmed slouching. Vanilla JS, Chrome MV3.