Sari la conținut
← Înapoi la blog
payments · stripe · braintree · engineering4 min de citit18 aprilie 2026

Migrarea unui stack de plăți de la Braintree la Stripe — un playbook tranzacțional

Un playbook testat în producție pentru a muta mii de abonați recurenți între procesatori tranzacțional, cu import idempotent, anulare automată în Braintree și un trail CSV pe care îl poți apăra în fața departamentului financiar.

Dacă cauți pe Google „migrare Braintree la Stripe” vei găsi zeci de postări de marketing și exact zero playbook-uri utile. Asta nu e una dintre acele postări. Asta e ce am făcut de fapt ca să mutăm mii de donatori lunari pentru o redacție independentă de știri de la PayPal/Braintree la Stripe — cu continuitatea datei de facturare, retry-uri idempotente și un trail CSV pe care finanțele l-au putut reconcilia.

De ce oamenii strică asta

O migrare de abonamente nu e o migrare de date. O migrare de date se termină când rândurile se potrivesc. O migrare de abonamente se termină când următoarea încasare reușește la noul procesator. Între aceste două momente trăiește fiecare eșec interesant: nepotriviri de clienți, nepotriviri de monedă, date de facturare la mijlocul ciclului, starea de dunning, „clientul chiar voia să anuleze luna trecută?”, și plăcerea unică de a fi taxat de două ori.

Cea mai mare greșeală pe care o fac echipele: tratează migrarea ca un import CSV one-shot. Nu e un import CSV. E o tranzacție distribuită între doi procesatori de plăți, o bază de date, aplicația ta și un pipeline de email.

Modelul pe care l-am folosit

Am modelat migrarea ca un pipeline tranzacțional cu patru etape idempotente, fiecare cu propriul input și output CSV:

  1. Export și normalizare — extrage fiecare abonament Braintree activ, fă join cu maparea de clienți Stripe, produce un singur CSV canonic. Idempotent: re-rularea ar trebui să producă același fișier (modulo abonamente noi).
  2. Import Stripe cu prevenirea duplicatelor — pentru fiecare rând, creează abonamentul Stripe dacă și numai dacă nu există unul echivalent. Folosește idempotency-key la fiecare apel API Stripe, derivat din ID-ul abonamentului Braintree.
  3. Anulare Braintree, doar după succes Stripe — pentru fiecare import Stripe reușit, anulează abonamentul Braintree corespunzător în aceeași tranzacție logică. Dacă pasul Stripe a reușit, pasul Braintree trebuie să reușească în cele din urmă; facem retry la erori tranzitorii și expunem cele persistente.
  4. Raportare — fiecare succes și fiecare eșec e adăugat în două fișiere CSV. Nimic nu se pierde în tăcere. Finanțele pot reconcilia în Excel.

Părțile non-evidente

Maparea ID-urilor de clienți e contractul. Menține braintree_subscription_id → stripe_customer_id → stripe_subscription_id ca tabel de primă clasă, nu ca CSV. CSV-ul e un snapshot; tabelul e sursa de adevăr. Fiecare retry re-interoghează tabelul.

Cheile de idempotență nu sunt opționale. Stripe va crea bucuros un al doilea abonament dacă îl ceri de două ori. Folosește o cheie deterministă ca migration_v2:bt_<subscription_id> ca retry-urile să fie sigure.

Anulează ultimul, niciodată primul. Dacă anulezi Braintree înainte ca Stripe să confirme noul abonament, ești la un blip de rețea distanță de a taxa cel mai loial client cu zero luna asta și de a te trezi cu un incendiu de refund-uri.

Nu o rula ca un singur batch mare. Rulează-o în valuri de 50–200, cu un om care se uită la raport între valuri. Primul val va scoate la iveală o clasă de erori pe care nu ai prevăzut-o. Întotdeauna există una.

Salvează fiecare payload. Stochează JSON-ul complet al abonamentului Braintree și JSON-ul complet al răspunsului Stripe lângă rândul de mapare. Când cineva peste șase luni întreabă „de ce am taxat acest client cu €29,99 în loc de €25”, ai răspunsul în 30 de secunde.

Ce poți copia

Arhitectura în engleză simplă:

migration-orchestrator.js
├── braintree-to-stripe-csv-generator.js      → step 1
├── stripe-subscription-importer.js           → step 2 (idempotent, batched)
├── braintree-cancellation-service.js         → step 3 (only after step 2 succeeded)
└── csv-reporter.js                           → step 4 (success + error CSVs)

Adaugă un flag --dry-run la fiecare pas. Adaugă o variabilă de mediu BATCH_SIZE. Refuză să pornească dacă STRIPE_SECRET_KEY arată ca o cheie de test într-o rulare „production” (și invers). Loghează fiecare apel API cu cheia lui de idempotență.

Ce absolut nu poți sări

Un mediu de test cu abonamente Braintree sandbox reale și clienți Stripe de test reali. Migrează-le pe acelea prima dată. Rulează anularea. Re-rulează orchestratorul. A doua oară trebuie să fie un no-op.

Dacă orchestratorul nu e sigur de re-rulat într-o dimineață de marți în timp ce clienții își încarcă aplicația, nu ești gata.

Rezultatul

Mii de donatori mutați între procesatori cu continuitatea datei de facturare păstrată. Fiecare abonament avea un rezultat înregistrat în CSV-ul de succes sau de eroare — pe o platformă care deja procesa sute de mii de tranzacții de plată pe an. Echipa și-a păstrat espresso-ul de dimineață.

Dacă te uiți la o migrare similară: tehnologia e jumătatea ușoară. Jumătatea grea e să recunoști din start că asta e o tranzacție între două sisteme pe care nu le controlezi complet, să proiectezi pentru retry-uri de la minutul zero și să refuzi să livrezi orchestratorul până când e sigur să-l rulezi de două ori la rând.

Asta e tot articolul. Nu există truc inteligent. Există doar disciplină.

Continuă lectura