Dan Ramos

2.6K posts

Dan Ramos banner
Dan Ramos

Dan Ramos

@DevDanIO

Healthcare growth marketing / Building Revenue Intelligence SaaS https://t.co/Qzx1EwWIgS

New Jersey Katılım Kasım 2009
912 Takip Edilen457 Takipçiler
Sabitlenmiş Tweet
Dan Ramos
Dan Ramos@DevDanIO·
Tracking ROAS in healthcare has been a bitch, longer sales cycles, consultations, insurance reimbursement... so many things to factor. So I spent the last several months building out a dashboard that connects Ad accounts/CRM/EHR. Life is good now - highcountrydigital.io
Dan Ramos tweet media
English
0
0
1
50
Matt Pocock
Matt Pocock@mattpocockuk·
/grill-me is my most popular skill ever. I get 5-10 messages a day about how it’s changed people’s workflows for the better But… I’ve stopped using it for code. Here’s the improved version:
English
92
174
3.1K
260.6K
dennis hegstad
dennis hegstad@dennishegstad·
@levelsio @stripe we lost a $15k fraud order back in 2020 with a customer who had 4 months of history, logging in, support chats, upgrading/downgrading plans, change CC's... in the end, American express sided with the charge back fraud and we lost the funds.
English
12
2
45
37.9K
@levelsio
@levelsio@levelsio·
Dispute fraud is a massive issue on @Stripe and with credit cards in general Americans use disputes as an easy way to get their money back after they change their mind on their purchase On my sites only 10% of disputes isn’t fraudulent But I lose 100% of disputes
Ashley Rudland@ashleyrudland

I constantly have funds held in reserve at Stripe for this reason. We go through periods of 0% disruptes then at random 5% in one month. And in 99% of cases it’s because we didn’t refund in 2 hours from the request. It’s dispute fraud basically.

English
74
26
511
394.3K
Dan Ramos
Dan Ramos@DevDanIO·
@levelsio @stripe I could have used this 2 weeks ago. Fighting over $10k in disputes, spent almost a week gathering evidence and consolidating everything and still lost, forced to take things to court now
English
0
0
0
462
@levelsio
@levelsio@levelsio·
🏆 For the first time in a decade on @Stripe I've started winning disputes with my vibe coded dispute responder I used to ignore disputes so I almost always lost them, now I've started winning, this one is the first big dispute for $1,199 USD! Whenever a dispute comes in, my site gets a webhook notice from Stripe, it then starts collecting evidence and generates a PDF with entire user's details, when they signed up, and most importantly what they did in the app In this case the user used the app for months, generated thousands of photos then tried to get the money back from their bank The evidence has to be REALLY detailed, and REALLY good, which is why it's perfect to vibe code it, you can get quite detailed with different types of users and activity on your app, and put that all in the PDF I'm shocked because I again I never would win disputes before People in US especially abuse the [ chargeback ] or [ dispute ] en masse, unlike the rest of the world, it's easily built into their banking app next to every transaction, so it's one tap to get free stuff. And why not? You get free stuff! It's destructive for business owners like me on many levels, if I get over 1% disputes on my account, I risk getting shutdown permanently by Stripe, Visa and MasterCard, like permanently for life, not just my business but on my personal name too, it's ruthless Disputes are also super expensive for business owners: you don't just pay back the amount they disputed, for every dispute you pay $30, which you only get back if you win! But with AI we can now create our own tools to fight back against dispute abuse and finally win! 🎉
@levelsio tweet media
@levelsio@levelsio

✅ Done 💳 Made an auto-dispute response system for Interior AI to see how easy it'd be It syncs old disputes but also catches new disputes via Stripe webhook and then auto submits evidence to try win them, it even includes the interior designs they generated in the evidence PDF to prove they used it! Here's the prompt/skill I made: ---- Build an auto-dispute-response system for Stripe that: 1. Shared evidence collection (app/dispute_evidence.php) Create a shared file with functions used by both the webhook and sync worker. This avoids duplicating evidence logic. Key functions: - getDisputeUserPlan($user, $stripe) — pulls the user's subscription plan from Stripe API (source of truth, since local DB plan field gets cleared on cancellation). Falls back to local DB fields if Stripe call fails. Maps product IDs to plan names and includes price/interval and canceled status. - collectDisputeEvidence($stripe, $user, $email, $charge, $photosDb) — collects all text and file evidence, returns an array ready to submit to Stripe. - generateServiceDocPdf($stripe, $user, $email, $photos_done, $recent_photos, $total_amount_paid) — generates a PDF with customer info, usage summary, recent activity table, and up to 6 actual product images (resized to JPEG at 500px wide / quality 75 to stay under Stripe's 5MB file upload limit). Returns both the Stripe file ID and raw PDF data. Important: pull total_amount_paid from Stripe charges API (sum of succeeded, non-refunded charges) instead of trusting the local DB which can be null/stale. 2. Webhook handler (in stripe_webhook.php) Catch `charge.dispute.created` events. When a dispute comes in: - Get the dispute, charge, and customer objects from Stripe - Look up the user in the local database by stripe_customer_id - Save the dispute to a `disputes` SQLite database (fields: dispute_id, charge_id, payment_intent_id, stripe_customer_id, user_id, email, amount, currency, reason, status, epoch_created, epoch_evidence_submitted, evidence_json, stripe_response, epoch_resolved, outcome) - Call collectDisputeEvidence() to collect all evidence (text + file uploads) - Submit evidence to Stripe via $stripe->disputes->update($dispute_id, ['evidence' => $evidence]) - Send a Telegram notification that a new dispute came in and evidence was auto-submitted Also catch `charge.dispute.updated` and `charge.dispute.closed` events to track dispute outcomes (won/lost) in the database and send Telegram notifications with the result (with emoji: checkmark for won, x for lost, warning for other). 3. Evidence fields submitted to Stripe TEXT fields (write strings directly): - product_description — describe what the product/service is - customer_name — from Stripe customer object - customer_email_address — from Stripe customer object - access_activity_log — detailed usage log: signup date, number of items/actions done, last active date, subscription plan (from Stripe), platform, total amount paid (from Stripe), recent activity with timestamps - uncategorized_text — the "why we should win" argument: customer signed up on X, actively used the service doing Y things, total amount paid, service was delivered digitally/instantly, customer never contacted us for a refund before disputing - refund_policy_disclosure — when the refund policy was presented (during checkout, always accessible at /legal) - cancellation_policy_disclosure — when cancellation policy was shown (during checkout, accessible at /legal, can cancel anytime from dashboard) - refund_refusal_explanation — customer didn't contact us for a refund before filing the dispute - cancellation_rebuttal — proof customer actively used the service and never requested cancellation - service_date — date of the charge (Y-m-d format) FILE UPLOAD fields (upload file to Stripe first via $stripe->files->create(['purpose'=>'dispute_evidence', 'file'=>fopen($path,'r')]), then pass the returned file_xxxxx ID): - receipt — pull the invoice PDF directly from Stripe ($stripe->invoices->retrieve($charge->invoice)->invoice_pdf gives a ready-made PDF URL, just download it and upload as dispute evidence) - service_documentation — generate a PDF containing: customer info section, service usage summary, recent activity table, and up to 6 actual product images/screenshots the customer received. Resize images before embedding (500px wide, JPEG quality 75) to stay under Stripe's 5MB file upload limit. Also save both PDFs to your file storage (e.g. Cloudflare R2, S3) with hashed filenames so they're not guessable but viewable from the admin dashboard. Store the storage URLs in the evidence_json as _receipt_r2_url and _service_doc_r2_url (underscore prefix so they're easy to identify as internal fields). DO NOT use these fields for text — they expect file upload IDs only: service_documentation, cancellation_policy, refund_policy, customer_communication, customer_signature, receipt, shipping_documentation, duplicate_charge_documentation, uncategorized_file 4. CLI sync worker (workers/syncDisputes.php) A script that pulls ALL existing disputes from Stripe's API (paginated with $stripe->disputes->all(['limit' => 100]) and starting_after for pagination), saves them to the local disputes database, and for any that still have needs_response or warning_needs_response status and haven't had evidence submitted yet — auto-submits evidence using the shared collectDisputeEvidence() function. This is needed because the webhook only catches future disputes, not existing ones. Too heavy to run on frontend — run via CLI only (php workers/syncDisputes.php). Saves a JSON cache file with sync results so the dashboard can show last sync time. 5. Mini dashboard (disputes.php with ?key= auth) A simple HTML page protected by ?key= query parameter that shows: - Stats boxes: total disputes, pending, won, lost, disputed last 30 days (amount + count), disputed last 12 months (amount + count), total $ disputed - A note showing the CLI sync command and last sync time from cache - A test form where you enter a stripe_customer_id to preview what evidence would be submitted (without actually submitting) — useful for debugging - A table of all disputes: date, email, amount, reason, status (color-coded badges), evidence submission status, links to both detail view and Stripe dashboard Detail view (action=view&id=dispute_id): - Shows all dispute info, link to Stripe, and a "Regenerate Evidence" button - Shows PDF file links (receipt + service documentation) if available - Shows Stripe file upload IDs - Shows all text evidence fields Regenerate Evidence (action=regen&id=dispute_id): - Regenerates the receipt and service documentation PDFs and uploads to file storage - Updates the evidence_json in the database with new PDF URLs - IMPORTANT: Use fastcgi_finish_request() to send the HTTP response immediately (redirect back to detail page with "regenerating in background" notice), then continue generating PDFs in the background. This prevents frontend timeouts since downloading images and generating PDFs can take 30+ seconds. Add an nginx rewrite for the page (e.g. rewrite ^/disputes/?$ /disputes.php). Make sure it's in the correct nginx config file (check which one the symlink in sites-enabled actually points to). 6. Telegram notifications - New dispute: "{site name} - New dispute from {email} for ${amount} ({reason}). Evidence auto-submitted to Stripe. {stripe_dashboard_link}" - Evidence failed: "{site name} - New dispute from {email} for ${amount} ({reason}). Evidence submission FAILED: {error}" - Dispute won: "{site name} - Dispute WON (checkmark) for {email} - ${amount} ({reason}) {stripe_dashboard_link}" - Dispute lost: "{site name} - Dispute LOST (x) for {email} - ${amount} ({reason}) {stripe_dashboard_link}" - DB permission error: "{site name} - DISPUTE DB ERROR: {error} - check permissions on data/disputes.db" 7. Make sure these Stripe webhook events are enabled in the Stripe dashboard: - charge.dispute.created - charge.dispute.updated - charge.dispute.closed 8. Database permissions The disputes.db file must be writable by the web server user (e.g. www-data). If you create it from CLI as root, fix ownership to match your other DB files. PHP-FPM runs as a different user than root. 9. Dependencies - FPDF (setasign/fpdf) for PDF generation — install via composer require setasign/fpdf - GD extension for image resizing (usually already installed) - Stripe PHP SDK (already installed if you have Stripe webhooks) - AWS S3 SDK for R2/S3 uploads (already installed if using Cloudflare R2)

English
113
202
6.2K
932.1K
Theo - t3.gg
Theo - t3.gg@theo·
If you recognize this image, I hope you enjoy your upcoming retirement
Theo - t3.gg tweet media
English
545
101
4.5K
636.3K
Dan Ramos
Dan Ramos@DevDanIO·
@FavaMandies @ryanflorence And people have been able to build websites w Wordpress for decades but still pay someone else to do it. Just because you can do it doesn’t mean most people will. Maintenance is also a major thing that is somehow always overlooked
English
0
0
0
17
Fava Mandies
Fava Mandies@FavaMandies·
@ryanflorence What you're missing is, anyone can now write that software. There are far more elevators than 100 years ago, but virtually no elevator operators, since it's a job we can all now do.
English
4
0
4
820
Ryan Florence
Ryan Florence@ryanflorence·
1/3: You're probably not going to lose your job. Here's some Econ 101 AI shifts the supply curve to the right. We can produce way more software with way less So we increase "Quantity Demanded" (not "Demand") with the same resources You don't lose your job, you just make more.
Ryan Florence tweet media
English
30
19
277
61.5K
Dan Ramos
Dan Ramos@DevDanIO·
I’ve done deep engineering work across 20-30 companies in my career and there’s one thing I’ve found consistent at each one: Code quality is directly correlated to eng compensation. If paying job from accounting to vibe code apps is the future, I think we’ll be fine guys
English
0
0
1
22
Dan Ramos
Dan Ramos@DevDanIO·
Blank screen
Dan Ramos tweet media
English
0
0
0
14
Dan Ramos
Dan Ramos@DevDanIO·
Lets keep this going
Dan Ramos tweet media
English
1
0
0
11
Dan Ramos
Dan Ramos@DevDanIO·
I’m convince 1/2 of meta is vibe coded Horizontal scrolling, race conditions, overlapping content, 3 second animations. Google and meta pull from the same talent pool, how does Google never have these issues ?!
Dan Ramos tweet media
English
1
0
0
79
Bastien Fachan
Bastien Fachan@BastienFachan·
It boils me with rage that Lindsey Vonn was even allowed to start this bloody race in the first place. A heartbreaking albeit sadly predictable outcome. twitter.com/RC_Sports/stat…
English
617
177
4.7K
2.1M
Dan Ramos
Dan Ramos@DevDanIO·
Took about 3 seconds to decide drop $300 on @thekitze tinkerer.club this morning once I saw who was in the club, this should be good
English
1
2
6
748
Dan Ramos
Dan Ramos@DevDanIO·
Spent 4 weeks building a basic CDP not knowing what a CDP was. Thought it was pretty trivial until I learned about CDPs and how complex they are. Now I’m throwing out 4 weeks of code to learn @RudderStack . Thankful for this tool but sometimes ignorance is bliss :/
English
0
0
0
43
Dan Ramos
Dan Ramos@DevDanIO·
My kids keyboard taught me I’ve been using the wrong hand to type the letter “B” for the past 30 years . Anyone else stroke the B w the right ?
Dan Ramos tweet media
English
0
0
0
24
Dan Ramos
Dan Ramos@DevDanIO·
I couldn't find a good healthcare KPI tracker for small-mid size practices so I built my own. A simple to use interface that pulls data from your ads accounts, CRM and EHR. Get clarity into your practice like CAC, LTV, Time to lead, Revenue/patient, etc
Dan Ramos tweet media
English
0
0
0
34
Dan Ramos
Dan Ramos@DevDanIO·
Anyone know if there's dynamic number insertion as a service? I need the bare basics thats i can integrate into a saas, don't want to pay for something full featured like call rail
English
0
0
0
24
Dan Ramos
Dan Ramos@DevDanIO·
Hey healthcare providers, how the hell you reporting on things like LTV, cac, revenue by provider, charges vs cash collected , etc? All EHRs I use have garbage reporting, extracting this data seems like a huge time sink #insurance #chiropractor #acupuncture #healthcare
English
0
0
0
18
Dan Ramos
Dan Ramos@DevDanIO·
We're at this weird inflection point w/ AI coding tools. Until recently, adopting the latest and greatest tools/tech stack ensured you were taking a 20-30% hit in productivity while you learned something new. Now theres a real chance you immediately boost productivity > 20%
English
1
0
0
18