Read the caller's number when SignalWire fetches your call document, and decline a listed number before the call is answered while everyone else is connected.
swmlwebhooksscreening
The claim
Call screening does not need a feature. SignalWire fetches your document with the inbound call webhook, and that request carries the caller’s number, so your handler is the place where the decision lives. The list is yours, kept wherever you keep things, and the platform never sees it.
Why it holds
Two facts carry the claim.
The vendored REST spec documents the inbound call webhook payload. Its call object requires from, “the number/URI that initiated this call”, and that is what the handler reads.
The bundled SWML schema’s hangup verb takes an optional reason whose values are exactly hangup, busy and decline. A document that starts with hangup and never says answer refuses the call rather than picking it up and dropping it.
Numbers are compared by digits, so +1 (555) 555-0101 on the list still catches 15555550101 on the wire. An absent caller id is not on any list and is connected.
How it works
def is_blocked(caller):
d = digits(caller)
return bool(d) and d in BLOCKED
def document(caller):
service = SWMLService(name="screen", route="/swml")
if is_blocked(caller):
service.add_verb("hangup", {"reason": REASON})
else:
service.add_verb("answer", {})
service.add_verb("connect", {"to": DESTINATION})
return json.loads(service.render_document())
decline tells the network the call was refused. busy makes the line look engaged instead, which a persistent dialler reads as a dead end. Both are in the schema; REJECT_REASON picks one.
The route sits behind the basic auth you put in the webhook URL, as every document-serving recipe here does. Nobody but SignalWire reads your routing.
Limitations
The verifier proves the documents, not what a blocked caller hears. What decline and busy sound like on the far end depends on the caller’s carrier.
call.from is what the network delivered. A caller who withholds their number arrives with none, and this recipe connects them; screening anonymous callers is a policy you add, not a default.
What to change first
Add "+14155550123" to BLOCKLIST and run the verifier. The allowed caller’s assertion fails on a hangup, which is the point: the list is the whole decision, and it is yours.