SIP response codes look like HTTP status codes and mostly behave like them, which is helpful right up to the point where it is not. The classes carry over, the familiar numbers mean roughly what you expect, and then one code in ordinary use means something quite different from what the standard says.
What do the classes mean?
The same six-class structure HTTP uses. RFC 3261, which defines SIP, names them in section 7.2, quoted here as it writes them:
1xx: Provisional -- request received, continuing to process the request;
2xx: Success -- the action was successfully received, understood, and accepted;
3xx: Redirection -- further action needs to be taken in order to complete the request;
4xx: Client Error -- the request contains bad syntax or cannot be fulfilled at this server;
5xx: Server Error -- the server failed to fulfill an apparently valid request;
6xx: Global Failure -- the request cannot be fulfilled at any server.
The one class with no HTTP equivalent is 6xx. The difference between a 4xx and a 6xx is scope: a client error says this server could not fulfil the request, while a global failure says no server can, so there is no point trying an alternative route. In practice you will rarely see one.
What do the common codes mean?
Four codes account for most of what you will meet, and RFC 3261 defines them in section 21 as follows.
403 Forbidden: "The server understood the request, but is refusing to fulfill it."404 Not Found: "The server has definitive information that the user does not exist at the domain specified in the Request-URI."486 Busy Here: "The callee's end system was contacted successfully, but the callee is currently not willing or able to take additional calls at this end system."503 Service Unavailable: "The server is temporarily unable to process the request due to a temporary overloading or maintenance of the server."
Two of those are worth reading as diagnoses rather than definitions. The RFC's wording on 486 is the useful part: the end system was contacted successfully, and then declined. A 404 means the number is not allocated. Both point at the number you dialed rather than at your own setup, which is the opposite of the instinct a 4xx usually triggers, and it saves a lot of time spent auditing a trunk that was working correctly.
Why did my call get a 503?
Two quite different things answer 503, and the call log is what separates them.
A 503 with a matching call record is a refusal. Bird checks the caller ID, the destination, the account's limits and the wallet balance before dialing out, and a call failing one of those checks is refused with 503. The record carries the rejection reason naming the check it failed. Retrying an identical call gets the same answer, so the fix is the setting the reason points at rather than another attempt.
The reason is deliberately not on the wire. Your phone system gets the bare 503; the specific reason lives on the authenticated call record instead. That is a security decision rather than an omission: putting the cause in the SIP response would let anyone who can send you an INVITE learn whether a destination is enabled, whether a caller ID is verified, or whether an account is out of balance.
A 503 with no call record at all is not a refusal. No check rejected the call, so there is no reason to read and nothing appears in the log. This is the case where the RFC's own definition is the better guide, and where a retry is the right move.
So the workflow is: see the 503 on your side, then look for the call in the log. If it is there, the rejection reason tells you what to change, and every reason and its fix is listed under rejected calls. If it is not there, treat it as transient and retry rather than going looking for a setting to fix. An empty log for a 503 is information, not a broken log.
Rejected, Failed, or something else?
The SIP code is only half the answer. The call's status is the other half, and reading them together is what makes either useful.
| Status | What happened |
|---|---|
answered | The destination picked up |
no_answer | It rang and was not answered before timing out |
rejected | It was refused rather than carried through |
failed | It was attempted and did not work, and the SIP response is what came back |
unknown | No final response ever arrived, so the outcome could not be determined |
Rejected covers two different refusals, and the rejection reason is what separates them. If there is a reason, Bird refused the call and the reason names the check it failed, with the 503 above as the code. If there is no reason, the far end declined it outright and the SIP response carries the far end's own code. An incoming call that the number it dialed turned away is also rejected with no reason, because it failed no check of Bird's; what the number was set to do is recorded as its inbound route.
Failed is not a refusal at all. The call was attempted and did not work. This is where a 486 or a 404 lands.
Two statuses in that list exist and never appear. busy and canceled are reserved for incoming calls delivered to your own numbers, nothing emits either today, and both outcomes are currently reported as failed. If you branch on them you will never take that branch, and if you search your records for them you will find nothing and conclude, wrongly, that neither situation occurs.
The table above is the outcomes an ended call can carry. A call still in progress reads ringing or in_progress, so filtering the call list meets those two as well. The list is open in the other direction too: match the ones you handle and treat an unrecognised value as a status you do not handle rather than as an error.
How do I see this across many calls?
One call at a time is the wrong tool for a pattern. The voice statistics endpoint aggregates response codes across your traffic, which is how you tell a systemic problem from a bad number.
The distinction to hold on to while reading it: a rise in 503 is about your account or your configuration, since those are Bird's own refusals, while a rise in 486 or 404 is about the numbers being dialed. The first is something you can fix in a setting, and the second usually means a list needs cleaning.
Voice troubleshooting works through the individual cases, and the call log covers what each record holds, including the call ID to quote when a reason turns out to be one only Bird can resolve.