False Answer Supervision means your carrier answers calls that no human ever picked up, then bills you for them. You can catch it with CDR queries, a duration histogram, and one SIP capture. I hunt for it on a production campaign where two carriers run a 50/50 split on identical traffic, so every metric below comes with a built-in control group.
Tested on: ViciDial 3.x, Asterisk 13-18, MariaDB 10.x, Homer 7.10. The SQL targets ViciDial's vicidial_log, but the method works on any Asterisk CDR table.
What is False Answer Supervision?
FAS is when a carrier (or someone upstream of them) sends 200 OK on a call that was never really answered. Your switch starts the billing clock, your dialer marks the call answered, and the money goes to whoever faked the answer signal.
It comes in several flavors, and I've seen most of them on real traffic:
- Pure FAS:
200 OKarrives before the callee's phone even rings. Your IVR plays to nobody. - Early-media FAS: the carrier answers, then plays ringback tone on the RTP stream. Your AMD hears ringing after "answer" and misclassifies wildly.
- Short FAS: answer, a few seconds of silence or a fake announcement, hangup at 3-30 seconds. Small per call, huge at volume.
- Call stretching: the callee hangs up but the carrier holds the billing leg open for extra seconds.
- Voicemail simulation: a slice of your traffic gets routed to fake voicemail prompts and billed at full duration.
The nasty part: FAS makes your stats look better. ASR and answered-call counts both climb, and nobody investigates a dashboard that just improved.
Why is FAS so hard to spot in normal reports?
Because every individual call record looks legitimate. The fraud only shows up in distributions, and only when you have something to compare against.
The single best setup for catching FAS is an A/B split: route the same traffic 50/50 across two carriers and compare them. Same destinations, same time of day, same lead lists. Any large divergence between the two sides is a carrier-side effect, not a traffic effect. If you only have one carrier, compare against your own historical baseline instead.
How do I split traffic across two carriers for comparison?
In the Asterisk dialplan, randomize the carrier per call and log which one each call took:
exten => _9911X.,1,Set(CARRIER=${IF($[${RAND(1,2)}=2]?carrier_a:carrier_b)})
exten => _9911X.,n,System(/usr/local/sbin/log_carrier.sh ${UNIQUEID} ${CARRIER})
exten => _9911X.,n,Dial(SIP/${CARRIER}/${EXTEN:4},,tTo)
log_carrier.sh is a two-line script that inserts (uniqueid, carrier, now()) into an attribution table, say carrier_route_log. Now every CDR can be joined to the carrier that handled it.
Gotcha that cost me a week: on answered calls, ViciDial's call_log AGI rewrites vicidial_log.uniqueid to the carrier leg's uniqueid. The uniqueid you captured at dial time never matches for answered calls, so your join silently loses exactly the calls you care about. Check your tag coverage per status before trusting any per-carrier number:
SELECT vl.status, COUNT(*) total,
SUM(crl.uniqueid IS NOT NULL) tagged
FROM vicidial_log vl
LEFT JOIN carrier_route_log crl USING(uniqueid)
WHERE vl.call_date >= NOW() - INTERVAL 1 HOUR
GROUP BY vl.status;
If answered statuses show near-zero coverage, capture the carrier in a hangup handler with CDR(dstchannel) instead of ${UNIQUEID}.
Which CDR metrics expose FAS?
Run a per-carrier triage card over the last few hours:
SELECT
crl.carrier,
COUNT(*) dialed,
ROUND(100*SUM(vl.status NOT IN ('NA','AB','ADC','DC'))/COUNT(*),1) AS asr_pct,
ROUND(AVG(IF(vl.status NOT IN ('NA','AB','ADC','DC'),
vl.length_in_sec, NULL)),1) AS acd_sec,
SUM(vl.length_in_sec BETWEEN 1 AND 15) AS short_calls,
ROUND(SUM(vl.length_in_sec BETWEEN 1 AND 15) /
NULLIF(SUM(vl.status IN ('NA','AB')),0), 3) AS fasr
FROM carrier_route_log crl
JOIN vicidial_log vl USING(uniqueid)
WHERE vl.call_date >= NOW() - INTERVAL 6 HOUR
GROUP BY crl.carrier;
How to read it:
| Metric | Clean route | FAS suspect |
|---|---|---|
| ASR delta between carriers | under ~10% | over 30% on identical traffic |
| ACD on answered calls | stable, similar both sides | one side several seconds shorter |
| FASR (short calls ÷ failed calls) | under 0.30 | over 0.30; over 1.0 is near-certain |
The FASR ratio (short answered calls divided by no-answers) comes from a Datanomers fraud-detection patent. A carrier faking answers converts would-be no-answers into short billed calls, so the ratio climbs on the dirty route while staying flat on the clean one.
What does a FAS duration histogram look like?
FAS rigs cut calls at fixed points. Humans don't. Pull a per-second histogram of answered call durations:
mysql -u USER -p asterisk -BN -e "
SELECT length_in_sec, COUNT(*)
FROM vicidial_log
WHERE call_date >= NOW() - INTERVAL 6 HOUR
AND status NOT IN ('NA','AB','ADC','DC')
AND length_in_sec BETWEEN 1 AND 60
GROUP BY length_in_sec;" | \
awk '{a[$1]=$2; if($2>m)m=$2} END{for(s=1;s<=60;s++){n=a[s]+0;
printf "%2ds %5d ",s,n; for(i=0;i<40*n/(m+1);i++)printf "#"; print ""}}'
An isolated spike at 28, 30, 45, or 60 seconds with empty neighbors is a cutoff, not human behavior.
One warning before you accuse anyone: know your legitimate peaks. On an IVR campaign, every no-input call lands at exactly audio length + menu timeout. My survey audio ran 21.7 seconds with a 6-second DTMF window, so a huge honest spike sat at 28 seconds. I verified all 1,948 calls in that bucket were normal completions before looking further. Compute your expected peak first, then investigate everything else.
How do I confirm FAS at the SIP level?
Two signatures, both visible in Homer (or any HEP capture, or even sngrep):
1. Post-dial delay that's too fast. PDD is the time from INVITE to 200 OK. Real mobile calls in Europe take 3-6 seconds to answer at minimum: the network has to page the handset and the human has to react. A carrier answering in under 1 second is structurally impossible without FAS. Query your HEP database for per-destination-IP PDD percentiles and count sub-1-second answers. More than ~5% sub-1s on one carrier IP is a red flag.
2. 200 OK with no ringing phase. A real call almost always shows INVITE → 180/183 → 200. Pure FAS often goes straight INVITE → 200. A small baseline is normal (some carriers only send 100 Trying), but if more than 10% of one carrier's calls skip ringing entirely, that route deserves a hard look.
Can I hear FAS in the recordings?
Yes, and it's the most convincing evidence you can attach to a dispute. Record the inbound leg (-in.wav in Asterisk's monitor directory) and check what the carrier actually delivered after "answer":
import wave, numpy as np
w = wave.open('leg-in.wav','rb')
n = min(int(w.getframerate()*5), w.getnframes())
b = np.frombuffer(w.readframes(n), dtype=np.int16).astype(float)
rms = np.sqrt(np.mean(b**2))
sp = np.abs(np.fft.rfft(b)); fr = np.fft.rfftfreq(len(b), 1/w.getframerate())
band = sp[(fr>=400)&(fr<=480)].sum()/sp.sum()
print(f"RMS={rms:.0f} peak={fr[np.argmax(sp)]:.0f}Hz ringband={band:.0%}")
- RMS under 50: silence. Normal for an IVR call where the callee just listens.
- RMS over 500 with 25%+ energy at 400-480 Hz: that's a ringback tone after answer. Early-media FAS, caught on tape.
- RMS over 500 with speech-band content on calls your agents never spoke on: a carrier announcement or bot loop, billed as conversation.
Bonus signal for IVR campaigns: DTMF response rate per carrier. Fake answers don't press 1. If one carrier's press-through rate is a fraction of its twin's on identical traffic, the "answered" calls on that route have nobody on them.
What's the definitive FAS test?
Dial a number that cannot answer. A confirmed-unallocated number must return 404 Not Found or 484 Address Incomplete. If the carrier returns 200 OK, that is conclusive. There is no innocent explanation for answering a number that doesn't exist.
asterisk -rx 'sip set debug ip 203.0.113.10'
asterisk -rx 'originate SIP/carrier_a/UNALLOCATED_NUMBER application Hangup'
asterisk -rx 'sip set debug off'
Use a number you control or one your national numbering plan documents as unassigned. One probe per carrier is enough; this is a diagnostic, not a load test. For continuous unattended probing, voip_patrol runs scripted test calls from cron.
What do I do once a carrier is confirmed dirty?
- Stop the bleeding. Reweight the dialplan
RAND()to send 100% to the clean carrier, or set the bad carrier inactive. On ViciDial, edit the carrier's dialplan entry in the admin GUI so the change survives config regeneration. - Build the evidence pack: the triage card, the histogram, the PDD stats, one SIP ladder showing
INVITE → 200with no ringing, one recording of post-answer ringback, and the unallocated-number probe. That combination is very hard to argue with. - Dispute the invoice. Carriers know exactly what FAS is. A billing dispute backed by SIP captures usually gets credited quietly. If it doesn't, you already stopped routing to them.
- Keep the A/B split running. FAS is rarely constant. It appears on specific destination prefixes at specific times. A permanent 90/10 split with the triage card on a cron is cheap insurance.
FAQ
Does high ASR always mean FAS? No. A carrier with better routes genuinely completes more calls. FAS shows as high ASR combined with short ACD, high FASR, impossible PDD, and low human-response signals. One metric is a hint; four together is a case.
Can FAS happen on inbound? The common inbound equivalent is call stretching, meaning duration padding after hangup. Compare your CDR durations against the far end's records if you suspect it.
My carrier blames their upstream. Does that matter? Not to you. You bought termination from them; where in their chain the fraud happens is their problem. The evidence pack works either way.