Subscription recovery
Recover Pro access after a reinstall
If you already paid and only wiped your local setup, use the same billing email to open the portal. You do not need to buy Pro again for the same GitHub account or organization.
Local recovery is separate from billing recovery. Before reinstalling everything from scratch, run ecc list-installed, ecc doctor, and ecc repair to restore the local Claude setup.
Same billing email
Use the invoice email to reopen the existing subscription and avoid a new charge.
Same GitHub install
Reinstall ECC on the same repo or organization that already owns Pro.
No duplicate charge
Only start checkout if you're activating a brand-new install or a different organization.
Redirecting to the existing billing portal...
Check if Pro is active
Confirm your paid plan is linked to the GitHub App install. Enter your GitHub login and the installation ID (shown on the GitHub App settings page URL, or in the bot's comments).
Prefer the terminal? Run npx ecc-tools status --account <login> or node scripts/ecc-local-daemon.mjs status --account <login> for the same PASS/FAIL report.
Relink a paid subscription
Paid but the GitHub App says "Upgrade Required"? This happens after uninstalling and reinstalling the App. Enter the billing email and the current installation ID to relink the existing subscription — no new checkout needed.
Cancel without the portal
If the billing portal is blocked (for example by duplicate billing records), cancel directly here. Enter the billing email and the last 4 digits of the card on file to prove ownership. All active subscriptions on the email are scheduled to cancel at the end of the billing period — no further charges.
Before you go
ECC 2.0.0 stable just shipped: 261 skills, the orch-* orchestrator family, and the control-pane substrate. If you're cancelling over a missing feature, it may already be here.
What you can do here
View invoices
Download receipts and payment history
Update payment
Change card or payment method
Cancel anytime
Cancels at end of billing period
Confirm access
Check the active subscription before you start a new checkout
If you were charged twice, stop here and use the existing portal session first. A new checkout is only for a new GitHub install or a different organization.
' +
'Tier: ' + escapeText(s.tier) + ' · Seats: ' + escapeText(s.seatCount) + ' · Analyses remaining: ' + escapeText(s.analysesRemaining == null ? 'unlimited' : s.analysesRemaining) + '
'
for (var i = 0; i < (s.checks || []).length; i++) {
var check = s.checks[i]
lines += '' + (check.ok ? 'PASS' : 'FAIL') + ' ' + escapeText(check.name) + ' — ' + escapeText(check.detail) + '
'
}
if (!s.proActive) {
lines += ''
}
showResult(resultEl, lines, !s.proActive)
} else {
showResult(resultEl, escapeText(data.error || 'Status check failed. Verify the GitHub login and installation ID.'), true)
}
} catch (err) {
showResult(resultEl, 'Something went wrong. Try again or email affaan@ecc.tools.', true)
}
btn.disabled = false
btn.textContent = 'Check Pro status'
})
document.getElementById('relink-form').addEventListener('submit', async function(e) {
e.preventDefault()
var email = document.getElementById('relink-email').value.trim()
var installationId = document.getElementById('relink-installation').value.trim()
var btn = document.getElementById('relink-btn')
var resultEl = document.getElementById('relink-result')
btn.disabled = true
btn.textContent = 'Relinking...'
try {
var res = await fetch(ECC_API_BASE + '/api/billing/relink', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: email, installationId: installationId })
})
var data = await res.json()
if (data.success) {
showResult(resultEl, 'Subscription relinked
' + escapeText((data.data && data.data.message) || 'Your paid plan is now linked to this installation.') + '
Use the status check above to confirm Pro is active.
', false)
} else {
showResult(resultEl, escapeText(data.error || 'Relink failed. Check the billing email and installation ID.'), true)
}
} catch (err) {
showResult(resultEl, 'Something went wrong. Try again or email affaan@ecc.tools.', true)
}
btn.disabled = false
btn.textContent = 'Relink subscription'
})
document.getElementById('cancel-form').addEventListener('submit', async function(e) {
e.preventDefault()
var email = document.getElementById('cancel-email').value.trim()
var cardLast4 = document.getElementById('cancel-card').value.trim()
var btn = document.getElementById('cancel-btn')
var resultEl = document.getElementById('cancel-result')
if (!window.confirm('Schedule every active subscription on ' + email + ' to cancel at the end of the billing period?')) return
btn.disabled = true
btn.textContent = 'Cancelling...'
try {
var res = await fetch(ECC_API_BASE + '/api/billing/cancel', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: email, cardLast4: cardLast4, confirm: true })
})
var data = await res.json()
if (data.success) {
showResult(resultEl, 'Cancellation scheduled
' + escapeText((data.data && data.data.message) || 'All active subscriptions will cancel at the end of the billing period. No further charges.') + '
', false)
} else {
showResult(resultEl, escapeText(data.error || 'Cancellation failed. Check the email and card digits, or email affaan@ecc.tools.'), true)
}
} catch (err) {
showResult(resultEl, 'Something went wrong. Try again or email affaan@ecc.tools.', true)
}
btn.disabled = false
btn.textContent = 'Cancel at period end'
});
(function() {
var params = new URLSearchParams(window.location.search)
var recoveryBanner = document.getElementById('account-recovery-banner')
if (!recoveryBanner) return
if (params.get('recovery') !== 'existing_subscription') return
var account = params.get('account')
var source = params.get('billingSource') || 'existing'
recoveryBanner.textContent = account
? 'The ' + account + ' workspace already has an active ' + source + ' subscription. Do not start a new checkout. Use this portal flow or email affaan@ecc.tools if you suspect a duplicate charge.'
: 'An active subscription already exists for this workspace. Do not start a new checkout. Use this portal flow or email affaan@ecc.tools if you suspect a duplicate charge.'
recoveryBanner.style.display = 'block'
})()
document.getElementById('portal-form').addEventListener('submit', async (e) => {
e.preventDefault()
const email = document.getElementById('portal-email').value.trim()
const btn = document.getElementById('portal-btn')
const errEl = document.getElementById('portal-error')
const loadEl = document.getElementById('portal-loading')
errEl.style.display = 'none'
loadEl.style.display = 'block'
btn.disabled = true
btn.textContent = 'Loading...'
try {
const res = await fetch('/api/billing/portal', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email })
})
const data = await res.json()
if (data.success && data.data?.url) {
window.location.href = data.data.url
} else {
errEl.textContent = data.error || 'No subscription found for this email. Check that you used the same email you subscribed with.'
errEl.style.display = 'block'
loadEl.style.display = 'none'
btn.disabled = false
btn.textContent = 'Open Billing Portal'
}
} catch (err) {
errEl.textContent = 'Something went wrong. Please try again or email affaan@ecc.tools.'
errEl.style.display = 'block'
loadEl.style.display = 'none'
btn.disabled = false
btn.textContent = 'Open Billing Portal'
}
})
Start with ECC
Move from OSS discovery to repo-native rollout.
The ECC model stays additive: open-source distribution first, GitHub App automation when repository workflows matter,
and enterprise support when the organization needs policy, rollout help, and governance.
210K+ stars
Public repos free
AgentShield protection layer