Table of Contents

Minimal inbound call

Register a line, accept the next incoming call, attach audio. Inbound calls surface through the IncomingCall event (client- or line-level) or the convenience OnIncomingCall hook.

using CalloraVoipSdk.Client;

using var client = new VoipClient(new VoipConfiguration
{
    LoggerFactory = loggerFactory,
    UserAgent     = "MySoftphone/1.0"
});

// Register the account that should receive calls.
var connect = await client.ConnectAsync(new SipAccount
{
    Username  = "1001",
    Password  = "secret",
    SipServer = "pbx.example.com"
});

if (!connect.IsSuccess)
    throw new InvalidOperationException($"Connect failed: {connect.Status}");

// Handle each inbound call. The handler runs when an INVITE arrives.
using var subscription = client.OnIncomingCall(async call =>
{
    await call.AcceptAsync();                 // send 200 OK
    await client.AttachDefaultAudioAsync(call);
});

// Keep the process alive while calls come in…

Accept, reject, redirect

Once you hold an ICall, the inbound control surface is:

await call.AcceptAsync();                            // 200 OK, answer
await call.RejectAsync(/* reason */);                // decline with a SIP status
await call.RedirectAsync(/* target */);              // 3xx redirect to another URI

AcceptAsync throws InvalidOperationException if the call is not in a state that can be accepted; RejectAsync/RedirectAsync return a CallActionResult instead of throwing for foreseeable outcomes. See the error contract.

Trunk vs. extension inbound

For SIP-trunk scenarios (calls addressed to DIDs rather than your registered AOR), set the numbers you own on the account so the SDK matches inbound requests:

new SipAccount
{
    Username       = "trunkuser",
    Password       = "secret",
    SipServer      = "trunk.provider.example",
    InboundNumbers = new[] { "4930123456" },
    AcceptTrunkInbound = true   // default
};

See NAT and SIP trunks for provider-specific setup.

Next