- Add clickwrap authorization checkbox to fcc-compliance, state-puc, neca-ocn order pages - Store engagement_accepted_at/ip/version in compliance_orders (migration 074) - Add 499-A past-due/multi-year eSign engagement letter generator - Gate 499-A handler on engagement signature for past-due/multi-year orders - Remove price/tax/fee headers from all 19 intake pages (post-payment only) - Fix duplicate confirmation email for compliance_batch orders - Add USAC past-due fee negotiation research doc Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
320 lines
16 KiB
HTML
320 lines
16 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<meta name="description" content="Obtain a NECA Operating Company Number (OCN) for your telecom carrier. Required for STIR/SHAKEN, LRN, and numbering authority. $2,650 all-in.">
|
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
|
<title>NECA OCN Registration — Performance West Inc.</title>
|
|
<script>
|
|
window.__PW_API = (function() {
|
|
var h = window.location.hostname;
|
|
if (h === "localhost" || h === "127.0.0.1") return "http://" + h + ":3001";
|
|
if (h === "dev.performancewest.net") return "https://api.dev.performancewest.net";
|
|
return "https://api.performancewest.net";
|
|
})();
|
|
</script>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
<style>
|
|
*{box-sizing:border-box;margin:0;padding:0}
|
|
body{font-family:'Inter',system-ui,sans-serif;color:#1f2937;background:#f9fafb;line-height:1.6}
|
|
a{color:#1e3a5f;text-decoration:none}
|
|
.wrap{max-width:680px;margin:0 auto;padding:2rem 1.25rem 4rem}
|
|
h1{font-size:1.65rem;font-weight:700;color:#111827;margin-bottom:.25rem}
|
|
.subtitle{font-size:.9rem;color:#6b7280;margin-bottom:1.5rem}
|
|
.card{background:#fff;border:1px solid #e5e7eb;border-radius:12px;padding:1.25rem;margin-bottom:1rem}
|
|
.card h2{font-size:1.05rem;font-weight:700;color:#1e3a5f;margin-bottom:.75rem}
|
|
.label{display:block;font-size:.82rem;font-weight:600;color:#374151;margin-bottom:.3rem;margin-top:.6rem}
|
|
select,input[type=text],input[type=email],input[type=tel]{width:100%;padding:.5rem .7rem;border:1px solid #d1d5db;border-radius:8px;font-size:.88rem;background:#fff}
|
|
select:focus,input:focus{outline:none;border-color:#1e3a5f;box-shadow:0 0 0 2px rgba(30,58,95,.15)}
|
|
.btn{display:inline-flex;align-items:center;justify-content:center;gap:.4rem;padding:.65rem 1.5rem;border-radius:8px;font-weight:600;font-size:.92rem;cursor:pointer;border:none;transition:all .15s}
|
|
.btn-primary{background:#1e3a5f;color:#fff}.btn-primary:hover{background:#162e4d}
|
|
.btn-primary:disabled{opacity:.5;cursor:not-allowed}
|
|
.info-banner{padding:.6rem .9rem;background:#ecfdf5;border-left:3px solid #059669;border-radius:0 6px 6px 0;font-size:.85rem;color:#065f46;margin-bottom:1.25rem}
|
|
.price-box{background:#f0f4f8;border:2px solid #1e3a5f;border-radius:10px;padding:1rem;text-align:center;margin-bottom:1.25rem}
|
|
.price-box .price{font-size:1.8rem;font-weight:800;color:#1e3a5f}
|
|
.price-box .price-note{font-size:.78rem;color:#6b7280}
|
|
.feature-grid{display:grid;grid-template-columns:1fr 1fr;gap:.5rem;margin:.75rem 0}
|
|
.feature-item{display:flex;align-items:flex-start;gap:.4rem;font-size:.82rem;color:#374151}
|
|
.feature-item svg{width:16px;height:16px;color:#059669;flex-shrink:0;margin-top:2px}
|
|
.state-picker{display:grid;grid-template-columns:repeat(auto-fill, minmax(110px, 1fr));gap:.35rem;max-height:260px;overflow-y:auto;border:1px solid #e5e7eb;border-radius:8px;padding:.5rem}
|
|
.state-chip{display:flex;align-items:center;gap:.3rem;padding:.25rem .5rem;border-radius:6px;font-size:.78rem;cursor:pointer;border:1px solid transparent;transition:all .1s}
|
|
.state-chip:hover{background:#f0f4f8}
|
|
.state-chip.selected{background:#eff6ff;border-color:#1e3a5f;font-weight:600}
|
|
.state-chip input{accent-color:#1e3a5f;width:14px;height:14px}
|
|
.tandem-box{background:#fffbeb;border:1px solid #fbbf24;border-radius:8px;padding:.75rem;margin-top:.75rem}
|
|
.tandem-box h3{font-size:.88rem;font-weight:700;color:#92400e;margin-bottom:.3rem}
|
|
.hidden{display:none}
|
|
.err{color:#dc2626;font-size:.82rem;margin-top:.5rem;display:none}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="wrap">
|
|
<h1>NECA OCN Registration</h1>
|
|
<p class="subtitle">Obtain a unique Operating Company Number from NECA. Required for STIR/SHAKEN signing, LRN assignments, and numbering authority.</p>
|
|
|
|
<div class="price-box">
|
|
<div class="price">$2,650</div>
|
|
<div class="price-note">All-in: $650 OCN application + $2,000 sponsoring CLEC agreement</div>
|
|
</div>
|
|
|
|
<div class="info-banner">
|
|
<strong>Tax deductible</strong> — OCN registration fees are deductible as ordinary business expenses under IRC § 162.
|
|
</div>
|
|
|
|
<!-- What's included -->
|
|
<div class="card">
|
|
<h2>What's Included</h2>
|
|
<div class="feature-grid">
|
|
<div class="feature-item">
|
|
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/></svg>
|
|
<span>NECA Company Code application</span>
|
|
</div>
|
|
<div class="feature-item">
|
|
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/></svg>
|
|
<span>Sponsoring CLEC agreement</span>
|
|
</div>
|
|
<div class="feature-item">
|
|
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/></svg>
|
|
<span>STIR/SHAKEN readiness</span>
|
|
</div>
|
|
<div class="feature-item">
|
|
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/></svg>
|
|
<span>LRN / number portability</span>
|
|
</div>
|
|
<div class="feature-item">
|
|
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/></svg>
|
|
<span>10 business day processing</span>
|
|
</div>
|
|
<div class="feature-item">
|
|
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/></svg>
|
|
<span>NECA filing fee included</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Intake Form -->
|
|
<div class="card">
|
|
<h2>Carrier Information</h2>
|
|
|
|
<label class="label">Legal Entity Name *</label>
|
|
<input type="text" id="entity-name" placeholder="Acme Telecom LLC">
|
|
|
|
<label class="label">Contact Name *</label>
|
|
<input type="text" id="contact-name" placeholder="John Smith">
|
|
|
|
<label class="label">Contact Email *</label>
|
|
<input type="email" id="contact-email" placeholder="john@acmetelecom.com">
|
|
|
|
<label class="label">Contact Phone *</label>
|
|
<input type="tel" id="contact-phone" placeholder="(555) 123-4567">
|
|
|
|
<label class="label">FRN (FCC Registration Number)</label>
|
|
<input type="text" id="frn" placeholder="0012345678" maxlength="10">
|
|
|
|
<label class="label">Service Category *</label>
|
|
<select id="service-category">
|
|
<option value="IPES">IPES (Interconnected VoIP)</option>
|
|
<option value="CLEC">CLEC (Competitive Local Exchange Carrier)</option>
|
|
<option value="Non-Incumbent LEC">Non-Incumbent LEC</option>
|
|
<option value="ISP">ISP (Internet Service Provider)</option>
|
|
<option value="Reseller">Reseller</option>
|
|
<option value="Other">Other</option>
|
|
</select>
|
|
|
|
<label class="label">Operating States * <span style="font-weight:400;color:#9ca3af">(select all that apply)</span></label>
|
|
<div style="margin-bottom:.3rem">
|
|
<label style="font-size:.78rem;cursor:pointer">
|
|
<input type="checkbox" id="select-all-states" style="accent-color:#1e3a5f"> Select all states
|
|
</label>
|
|
</div>
|
|
<div class="state-picker" id="state-picker"></div>
|
|
|
|
<div class="tandem-box" id="tandem-box">
|
|
<h3>Sponsoring CLEC / Tandem Agreement</h3>
|
|
<p style="font-size:.82rem;color:#78350f;margin-bottom:.5rem">
|
|
An OCN requires a sponsoring CLEC agreement for numbering authority and interconnection. If you do not have an existing tandem/interconnection agreement, we will arrange one as part of this service.
|
|
</p>
|
|
<label style="font-size:.82rem;cursor:pointer">
|
|
<input type="checkbox" id="has-tandem"> I already have an existing tandem/interconnection agreement
|
|
</label>
|
|
</div>
|
|
|
|
<div style="margin-top:1rem;padding:.6rem;background:#f8fafc;border-radius:8px;border:1px solid #e2e8f0">
|
|
<div style="display:flex;justify-content:space-between;font-size:.88rem;padding:.15rem 0">
|
|
<span>OCN Registration</span><span style="font-weight:600">$650</span>
|
|
</div>
|
|
<div style="display:flex;justify-content:space-between;font-size:.88rem;padding:.15rem 0" id="tandem-line">
|
|
<span>Sponsoring CLEC Agreement</span><span style="font-weight:600">$2,000</span>
|
|
</div>
|
|
<div style="display:flex;justify-content:space-between;font-size:1rem;font-weight:700;padding:.4rem 0;border-top:1px solid #e2e8f0;margin-top:.3rem">
|
|
<span>Total</span><span id="total-price">$2,650</span>
|
|
</div>
|
|
</div>
|
|
|
|
<label style="display:flex;align-items:flex-start;gap:.5rem;padding:.65rem;margin-top:.75rem;border:1px solid #e5e7eb;border-radius:8px;cursor:pointer;font-size:.75rem;color:#6b7280;line-height:1.5">
|
|
<input type="checkbox" id="engage-check" required style="margin-top:2px;accent-color:#1e3a5f">
|
|
<span>I authorize Performance West Inc. to prepare and submit regulatory filings on my behalf as described above. I understand Performance West provides compliance consulting services, not legal advice or legal representation. I confirm the information I provide is accurate to the best of my knowledge. <a href="/terms" target="_blank" style="color:#1e3a5f;text-decoration:underline">Terms of Service</a></span>
|
|
</label>
|
|
|
|
<div style="margin-top:1rem;text-align:right">
|
|
<button class="btn btn-primary" id="btn-pay">Continue to Payment</button>
|
|
</div>
|
|
<p class="err" id="form-error"></p>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
(function() {
|
|
var STATES = [
|
|
['AL','Alabama'],['AK','Alaska'],['AZ','Arizona'],['AR','Arkansas'],['CA','California'],
|
|
['CO','Colorado'],['CT','Connecticut'],['DE','Delaware'],['DC','District of Columbia'],['FL','Florida'],
|
|
['GA','Georgia'],['HI','Hawaii'],['ID','Idaho'],['IL','Illinois'],['IN','Indiana'],
|
|
['IA','Iowa'],['KS','Kansas'],['KY','Kentucky'],['LA','Louisiana'],['ME','Maine'],
|
|
['MD','Maryland'],['MA','Massachusetts'],['MI','Michigan'],['MN','Minnesota'],['MS','Mississippi'],
|
|
['MO','Missouri'],['MT','Montana'],['NE','Nebraska'],['NV','Nevada'],['NH','New Hampshire'],
|
|
['NJ','New Jersey'],['NM','New Mexico'],['NY','New York'],['NC','North Carolina'],['ND','North Dakota'],
|
|
['OH','Ohio'],['OK','Oklahoma'],['OR','Oregon'],['PA','Pennsylvania'],['RI','Rhode Island'],
|
|
['SC','South Carolina'],['SD','South Dakota'],['TN','Tennessee'],['TX','Texas'],['UT','Utah'],
|
|
['VT','Vermont'],['VA','Virginia'],['WA','Washington'],['WV','West Virginia'],['WI','Wisconsin'],['WY','Wyoming']
|
|
];
|
|
|
|
var API = window.__PW_API;
|
|
var selectedStates = new Set();
|
|
var picker = document.getElementById('state-picker');
|
|
|
|
// Render state chips
|
|
STATES.forEach(function(s) {
|
|
var chip = document.createElement('label');
|
|
chip.className = 'state-chip';
|
|
chip.innerHTML = '<input type="checkbox" value="'+s[0]+'"> '+s[0]+' '+s[1];
|
|
chip.querySelector('input').addEventListener('change', function(e) {
|
|
if (e.target.checked) { selectedStates.add(s[0]); chip.classList.add('selected'); }
|
|
else { selectedStates.delete(s[0]); chip.classList.remove('selected'); }
|
|
});
|
|
picker.appendChild(chip);
|
|
});
|
|
|
|
// Select all
|
|
document.getElementById('select-all-states').addEventListener('change', function() {
|
|
var checked = this.checked;
|
|
picker.querySelectorAll('input').forEach(function(cb) {
|
|
cb.checked = checked;
|
|
var code = cb.value;
|
|
if (checked) { selectedStates.add(code); cb.closest('.state-chip').classList.add('selected'); }
|
|
else { selectedStates.delete(code); cb.closest('.state-chip').classList.remove('selected'); }
|
|
});
|
|
});
|
|
|
|
// Tandem toggle — adjust price
|
|
document.getElementById('has-tandem').addEventListener('change', function() {
|
|
var line = document.getElementById('tandem-line');
|
|
var total = document.getElementById('total-price');
|
|
if (this.checked) {
|
|
line.style.textDecoration = 'line-through';
|
|
line.style.opacity = '0.5';
|
|
total.textContent = '$650';
|
|
} else {
|
|
line.style.textDecoration = '';
|
|
line.style.opacity = '';
|
|
total.textContent = '$2,650';
|
|
}
|
|
});
|
|
|
|
// Checkout
|
|
document.getElementById('btn-pay').addEventListener('click', async function() {
|
|
var btn = this;
|
|
var errEl = document.getElementById('form-error');
|
|
errEl.style.display = 'none';
|
|
|
|
var entityName = document.getElementById('entity-name').value.trim();
|
|
var contactName = document.getElementById('contact-name').value.trim();
|
|
var contactEmail = document.getElementById('contact-email').value.trim();
|
|
var contactPhone = document.getElementById('contact-phone').value.trim();
|
|
|
|
if (!document.getElementById('engage-check').checked) {
|
|
errEl.textContent = 'Please accept the authorization terms to continue.';
|
|
errEl.style.display = 'block';
|
|
return;
|
|
}
|
|
if (!entityName || !contactName || !contactEmail || !contactPhone) {
|
|
errEl.textContent = 'Please fill in all required fields (entity name, contact name, email, phone).';
|
|
errEl.style.display = 'block';
|
|
return;
|
|
}
|
|
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(contactEmail)) {
|
|
errEl.textContent = 'Please enter a valid email address.';
|
|
errEl.style.display = 'block';
|
|
return;
|
|
}
|
|
if (selectedStates.size === 0) {
|
|
errEl.textContent = 'Please select at least one operating state.';
|
|
errEl.style.display = 'block';
|
|
return;
|
|
}
|
|
|
|
btn.disabled = true;
|
|
btn.textContent = 'Creating order...';
|
|
|
|
var hasTandem = document.getElementById('has-tandem').checked;
|
|
|
|
var orderBody = {
|
|
service_slug: 'ocn-registration',
|
|
customer_name: contactName,
|
|
customer_email: contactEmail,
|
|
customer_phone: contactPhone,
|
|
intake_data: {
|
|
entity_legal_name: entityName,
|
|
contact_name: contactName,
|
|
contact_email: contactEmail,
|
|
contact_phone: contactPhone,
|
|
frn: document.getElementById('frn').value.trim() || undefined,
|
|
service_category: document.getElementById('service-category').value,
|
|
operating_states: Array.from(selectedStates),
|
|
has_existing_tandem: hasTandem,
|
|
},
|
|
};
|
|
|
|
try {
|
|
// Step 1: Create compliance order
|
|
var orderResp = await fetch(API + '/api/v1/compliance-orders', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(orderBody),
|
|
});
|
|
var orderData = await orderResp.json();
|
|
if (!orderResp.ok) throw new Error(orderData.error || 'Order creation failed');
|
|
|
|
btn.textContent = 'Redirecting to payment...';
|
|
|
|
// Step 2: Create Stripe session
|
|
var sessionResp = await fetch(API + '/api/v1/checkout/create-session', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
order_id: orderData.id,
|
|
order_type: 'compliance',
|
|
payment_method: 'card',
|
|
}),
|
|
});
|
|
var sessionData = await sessionResp.json();
|
|
if (!sessionResp.ok) throw new Error(sessionData.error || 'Checkout failed');
|
|
|
|
if (sessionData.checkout_url) {
|
|
window.location.href = sessionData.checkout_url;
|
|
} else {
|
|
throw new Error('No checkout URL returned');
|
|
}
|
|
} catch (err) {
|
|
errEl.textContent = err.message || 'Something went wrong. Please try again.';
|
|
errEl.style.display = 'block';
|
|
btn.disabled = false;
|
|
btn.textContent = 'Continue to Payment';
|
|
}
|
|
});
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|