For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
Log inSign up
Support
GuidesReference
GuidesReference
    • Core
      • Overview
      • Webhook signature validation
        • make_webhook_validation_dependency
        • validate_request
        • validate_webhook_signature
    • Agents
      • Overview
      • AgentBase
      • AgentServer
      • BedrockAgent
      • CLI Tools
      • Configuration
      • ContextBuilder
      • DataMap
      • FunctionResult
      • Helper Functions
      • LiveWire
      • MCP Gateway
      • PomBuilder
      • Prefabs
      • Search
      • SkillBase
      • Skills
      • SWAIGFunction
      • SWMLBuilder
      • SWMLService
      • WebService
    • RELAY
      • Overview
      • Actions
      • Call
      • Constants
      • Events
      • Message
      • RelayClient
      • RelayError
    • REST Client
      • Overview
      • Addresses
      • Calling
      • Chat
      • Compat
      • Datasphere
      • Fabric
      • Imported Numbers
      • Logs
      • Lookup
      • MFA
      • Number Groups
      • Phone Numbers
      • Project
      • PubSub
      • Queues
      • Recordings
      • Registry
      • RestClient
      • Short Codes
      • SignalWireRestError
      • SIP Profile
      • Verified Callers
      • Video
LogoLogoSignalWire Docs
Log inSign up
Support
On this page
  • Parameters
  • Returns
  • Example
CoreWebhook signature validation

validate_webhook_signature

|View as Markdown|Open in Claude|
Was this page helpful?
Edit this page
Previous

Agents

Python API reference for AgentBase, SWMLService, SWAIG functions, skills, contexts, LiveWire, search, and more
Next
Built with

Verify that an incoming webhook was signed by SignalWire with your Signing Key. This is the primary standalone validator for custom (non-AgentBase) servers. Pass it the raw, unparsed request body so the signature matches what the platform computed.

The signature value comes from the X-SignalWire-Signature request header (or X-Twilio-Signature for Compatibility callbacks). See the security overview for the recognized header names.

Parameters

signing_key
strRequired

Your Signing Key from the Dashboard, as a UTF-8 string. A None or empty value raises ValueError — this is a programming error, not a validation failure.

signature
strRequired

The X-SignalWire-Signature header value (or X-Twilio-Signature for Compatibility callbacks). A missing or empty value returns False without raising.

url
strRequired

The full URL SignalWire POSTed to — scheme, host, optional port, path, and query. It must match what the platform saw.

raw_body
strRequired

The raw request body as a UTF-8 string, before any JSON or form parsing. Must be a str; passing a parsed dict raises TypeError.

Returns

bool — True if the signature matches, False otherwise.

Example

1from fastapi import FastAPI, Request, Response, status
2from signalwire.core.security import validate_webhook_signature
3
4app = FastAPI()
5SIGNING_KEY = "PSK_your_signing_key"
6
7@app.post("/webhook")
8async def webhook(request: Request):
9 raw_body = (await request.body()).decode("utf-8")
10 signature = request.headers.get("x-signalwire-signature", "")
11
12 if not validate_webhook_signature(
13 signing_key=SIGNING_KEY,
14 signature=signature,
15 url=str(request.url),
16 raw_body=raw_body,
17 ):
18 return Response(status_code=status.HTTP_403_FORBIDDEN)
19
20 # Signature is valid — safe to process the request.
21 return {"ok": True}

If you already have pre-parsed form parameters instead of a raw body, use validate_request, which accepts either form.