A 404 with code call_id_not_found on POST /v1/realtime/calls/{call_id}/accept means your accept reached OpenAI, but the pending SIP session it named is either already gone or not visible to the identity you presented. Across three first-person reports on community.openai.com between 2 and 10 September 2026, every fix that worked was a project-scope change, not a code change, and none worked for everyone.
What a 404 call_id_not_found actually means in the call lifecycle
Your carrier sends an INVITE to sip:[email protected];transport=tls — OpenAI’s voice SIP guide tells you to point the trunk there “using the project ID for which you configured the webhook”. OpenAI creates a pending session and fires a realtime.call.incoming webhook carrying data.call_id. You POST that identifier to the accept endpoint, which per the same guide, read 14 September 2026, “returns 200 OK once the SIP leg is ringing and the realtime session is being established”. The 404 sits between those last two steps.
The accept is therefore a lookup against a short-lived pending session, and a lookup fails only two ways: the record is gone, or it is not yours to see. Every cause below collapses into one of those. This is not a call that connected and then ended, which has its own ended-reason codes for dropped AI voice calls, nor a webhook that never arrived, which is a separate triage path.
Part of why this feels undocumented is that it is. We fetched and searched four OpenAI pages on 14 September 2026 — the voice SIP guide, the webhooks guide, the accept-endpoint reference and the API error codes guide — and the string call_id_not_found appears on none of them. The error codes page carries entries for 400, 401, 403, 429, 500 and 503, and no 404 entry at all.
Our inbound calls started returning 404 call_id_not_found on accept and nothing on our side changed
Is it every call or some calls? If every inbound call fails, no retry recovers those calls and you should work the 24-hour list below as a production outage. If it is a minority, check your ringback abandonment rate first: a caller who hangs up during ringback leaves a pending session that is legitimately gone by the time your accept lands, so a 404 on an abandoned call is the correct answer rather than a defect. Intermittent 404s at roughly your abandon rate are noise, not an incident.
The nearest thing to an official answer is dated 2 September 2026. On community topic 1394315, a report of an accept that took about 5.3 seconds and returned 404 drew a reply from an OpenAI_Support account listing five checks: that the value sent is exactly event.data.call_id, not the SIP Call-ID header; that “the API key or OpenAI-Project header belongs to the same project used in the SIP destination and webhook configuration”; that only one worker attempts each accept; that no separate live.call.incoming handler is accepting the same session; and that duplicates are deduplicated on webhook-id. That case was closed on 6 September 2026 for want of a reply. Topic 1396354, opened 10 September 2026, nine posts, last reply 11 September, still had no staff reply and no accepted answer when we read it on 14 September 2026. Two participants there reported the project header fixed theirs; the person who opened it reported it did not fix his. A separate report, topic 1396412, dates its own outage from 20:51 CEST on 9 September to 10:32 CEST on 10 September 2026 and says it was resolved by recreating the webhook — a fix that is nowhere in the documentation and that did not work for everyone who tried it.
The six signatures and the one observation that confirms each
Every test below runs against logs you already have. The third column is the one that matters at 11pm: it tells you whether to keep debugging or start writing a support case.
| Observed signature | Likely owner | The one test that confirms it | Action |
|---|---|---|---|
| Every call fails from a moment in time after months of working; other endpoints still succeed on the same key | Project scope, or a provider-side change | Call GET /v1/files twice on the same key, once plain and once with OpenAI-Project set to the project ID in the webhook To: header. Different results mean your key resolves to a different project than your calls do |
Send OpenAI-Project on the accept and the WebSocket connect, with a project-scoped key from that project |
| Failures are a tail, not a total, and the failing accepts are the slow ones | You, or the network in front of you | Log a monotonic delta from webhook receipt to accept sent, plus openai-processing-ms. Plot failures against the delta; a clean threshold means timing |
Get the accept off the webhook request thread and into a worker |
Two or more accept attempts share one call_id and one returned 200 |
You | Group accept attempts by call_id. If any returned 200 the call was answered, so the 404 is on the duplicate |
Idempotency key on webhook-id, first decision wins |
Repeated webhook-id values with growing gaps; failure rate tracks concurrency, not the clock |
You | Count distinct webhook-id values against total deliveries. A retry means you did not return 2xx in time |
Return 2xx at the edge, queue the work, add capacity |
| Every call has failed since the integration was built, including the first | You | Compare the string you send with event.data.call_id. Sending the SIP Call-ID header is the classic first-day error |
Use the webhook field, not the SIP header |
| Unrelated parties report the same failure in the same hours; your deploy log is empty | The provider | The Two-Witness Rule, below | Stop debugging, assemble the evidence pack, open a case |
Two rows deserve a sentence more. On project scope, OpenAI’s API reference overview documents OpenAI-Project as the header specifying “which organization and project to use for an API request”, while the accept example on the voice SIP guide shows only Authorization and Content-Type. The same overview warns that most updates affecting a key’s authentication result propagate within 15 minutes and can take longer, so do not judge a credential change after five. On duplicates, OpenAI documents that it may in rare cases deliver duplicate copies of a webhook event and that webhook-id is the idempotency key; on the GPT-Live contract it documents that the first accept or reject decision wins and a later competing decision returns decision_already_made. No code is published for a second decision on the Realtime accept path, so a duplicate is a candidate explanation rather than a confirmed one, which is why the test groups by call_id rather than trusting a status code.
What to do in the next 24 hours
- Establish blast radius first. Failing calls over total inbound calls for the last six hours. All, or some? That ratio selects your row.
- Capture six fields from one failing call: webhook receipt time,
event.data.call_id, the project ID in theTo:header, thewebhook-id, your accept send time and the accept responsex-request-id. - Run the two-project comparison. One minute, highest yield available: the same request on the same key, with and without
OpenAI-Project. Different responses mean you have found it. - Make the accept handler idempotent. Key on
webhook-id, record the outcome, never send a second accept for a call you already accepted. Free, and it removes a row from the table permanently. - Give the 404 sane retry semantics. One immediate retry at most, then stop. Unlike a 429 or a 5xx it is not transient, and a retry loop only burns the seconds the caller is still on the line.
- Fail over rather than failing open. If the accept does not return 200 inside your budget, reroute at the carrier to a human queue or a recorded message, which is the case for building failover into an AI voice agent before you need it.
The next 7 days, and the fix that stops it recurring
Pin the identity. One project per SIP destination, a project-scoped key issued inside it, and OpenAI-Project sent explicitly on every call-control request and on the sideband WebSocket, even where it is redundant today. A header you always send cannot silently start resolving somewhere else.
Assert the project at the door. Parse the project ID out of the To: header in the webhook handler and compare it with the project your credential is configured for. A mismatch should be a loud alarm, not a 404 forty milliseconds later.
Separate acknowledgement from work. OpenAI states that an endpoint which does not return 2xx, or does not respond within a few seconds, has the delivery retried with exponential backoff for up to 72 hours. Verify the signature, enqueue, return 2xx. The accept belongs to a worker with its own concurrency limit.
Instrument the fields in the next table permanently and keep 30 days of them, as AI agent observability, traces, logs and outcomes sets out. Call control is the path teams leave uninstrumented because it usually works.
The Two-Witness Rule and the evidence pack a provider will accept
The Two-Witness Rule: do not call a failure the provider’s until two independent witnesses agree — a party outside your infrastructure reporting the same failure in the same window, and a control request of your own that succeeds on the same credential and path in the same minute. One witness is a hypothesis. Two is a bug report.
It rules out the two things that mislead in opposite directions. An outside report alone can be a different bug sharing a symptom. A green status page alone proves nothing: the public incident feed at status.openai.com returned its 25 most recent incidents when we read it on 14 September 2026, spanning 20 August to 14 September, and none named the Realtime API, SIP or calls. A change scoped to how a credential resolves to a project need not register as an incident.
The evidence pack converts a hypothesis into something a vendor can act on. That 2 September 2026 support reply asked for exactly this, for two or three failed calls: UTC timestamps, call_id, webhook ID, event ID, the SIP provider call ID, the redacted accept payload, x-request-id and openai-processing-ms, sent privately rather than posted publicly with keys or unredacted SIP headers in them.
| Field to capture | Where it comes from | What it proves |
|---|---|---|
x-request-id |
Accept response header | Lets the provider trace your exact request internally |
X-Client-Request-Id |
You set it, ASCII, 512 characters or fewer | Per OpenAI, can be used to look up whether a request arrived at all when no response header came back |
openai-processing-ms |
Accept response header | Splits provider processing time from network and queueing time |
webhook-id |
Webhook request header | Identifies duplicate and retried deliveries; OpenAI documents it as the idempotency key |
Project ID in the To: header |
SIP headers in the webhook body | Proves which project the call was actually created in |
| Monotonic webhook-to-accept delta | Your own clock | Proves whether you were late, independently of the provider |
Where teams waste the first two hours
Four checks look obvious at this point and all four are the wrong layer: packet captures on the SBC, TLS on the trunk, rewriting the webhook handler, and refreshing the status page. The two September 2026 reporters who published their own ruled-out lists had already spent effort on that kind of ground — DNS and proxy latency, client timeouts, clock skew, an expired certificate — and none of it produced a fix. The INVITE already succeeded — you received a webhook, which proves signalling, DNS, TLS and routing worked. The failure is one HTTPS request later, on a REST endpoint.
The deeper trap is that a control plane can report success while the data plane is dead. Our own documented failure, on the WordPress publishing stack behind this blog rather than any agent runtime: on 10 September 2026 the site returned HTTP 502 to every visitor for roughly forty minutes, about 14:36 to 15:15 UTC, while our command-line tooling reported success on every operation, because that tooling does not pass through the process pool the public site uses. The following run found the cause by measurement: one post save generated 86 loopback HTTP requests in 60 seconds into a four-worker pool, while a page view generated zero. Two earlier explanations had fitted the symptom perfectly and both were wrong. The tool you are watching is often not on the path that is broken.
What running this yourself actually costs
All of the above is doable in-house and none of it needs a vendor. The honest arithmetic: diagnosis is an hour, idempotency and instrumentation are one to two engineering days, failover routing is another day, and the recurring cost is an on-call rotation that understands SIP, webhooks and a REST call-control API at once — rare enough to be a hiring problem rather than a budget one. The same trade-off runs through connecting an AI agent to your SIP trunk: the question is whether you want to own the accept path at 2am.
Zian AI runs autonomous sales agents over live phone, SMS, email and WhatsApp in 30 or more languages, and supports private model deployment on customer infrastructure for teams that need the call path inside their own boundary. Zian AI is in partnership-application beta.
Frequently asked questions
Does a 404 call_id_not_found mean the caller never heard an agent?
Not always. If two accept attempts share the same call ID and one of them returned 200, the call was answered and the 404 belongs to the duplicate attempt. Group accept attempts by call ID before treating the error as a failed call.
How long do I have to accept an inbound SIP call?
The OpenAI voice SIP guide published no deadline between the incoming-call webhook and the accept as at 14 September 2026, and an OpenAI support reply of 2 September 2026 said there is no documented requirement to wait either. The real ceiling belongs to the caller side: under RFC 3261, timer T1 defaults to 500 milliseconds and the INVITE transaction timeout is 64 times T1, which is 32 seconds by default.
Is the OpenAI-Project header required on the accept request?
The accept example on the OpenAI voice SIP guide showed only the Authorization and Content-Type headers as at 14 September 2026. The OpenAI API reference overview documents OpenAI-Project as the way to specify which organisation and project a request uses, and an OpenAI support reply on 2 September 2026 listed the key or project header matching the SIP destination project as a thing to check.
Does a green provider status page mean the fault is mine?
No. A change scoped to how a credential resolves to a project need not register as a service incident. When we read the public incident feed on 14 September 2026 it returned the 25 most recent incidents, covering 20 August to 14 September 2026, and none of them named the Realtime API, SIP or calls.
Should my code retry a 404 on the accept endpoint?
At most once, immediately, then stop. Unlike a 429 or a 5xx, a 404 on a pending session is not a transient condition, and a retry loop only consumes the seconds the caller is still on the line. Route the call to a human queue or a recorded message instead.