OpenAI CAPI is not Meta with a new host
Short answer
The ads conversion POST looks familiar until you count the digits and read the field names. OpenAI Ads uses a different path, a different clock, and a different id than Meta CAPI. A shared worker that only knows event_time will 200 and still miss.
Validate this snippet Open the rulepack
Different path, different envelope
Meta CAPI posts to the Graph API events edge with an access token. The body is data[] of events, each with event_name, event_time, action_source, user_data. OpenAI Ads Conversions API posts to bzr.openai.com/v1/events. The body is events[], each with id, type, and timestamp_ms. The image pixel is yet another path: /v1/sdk/events with pid. Mixing the pixel URL and the CAPI URL is a different miss from mixing Meta and OpenAI JSON.
Pixellint pack vendor/openai-conversions-api is the server hop. vendor/openai is the image tag. They are not aliases. Treat them as two contracts, the same way Meta Pixel and Meta CAPI are two contracts.
timestamp_ms is 13 digits
OpenAI timestamp_ms is Unix milliseconds. Date.now() is already 13 digits. Meta event_time is Unix seconds, 10 digits, so the Meta helper is Math.floor(Date.now() / 1000). Sending that 10-digit value as timestamp_ms is too short. Pixellint flags vendor.openai-conversions-api.body.timestamp_ms.invalid.
The fixture in the pack is the usual miss: type present, timestamp_ms a seconds-looking integer, id omitted. A 200 from a gateway that only checks JSON parse is not an attributed conversion.
{
"events": [
{
"type": "order_created",
"timestamp_ms": 1770000000
}
]
}
id is not event_id, type is not event_name
OpenAI events[].id is required. Meta event_id is how you dedup the pixel against CAPI. Same idea, different key, different rules about when it can be absent. Do not send event_id and expect OpenAI to find it. Do not send id to Meta and expect Graph to treat it as event_id.
type is an OpenAI event type such as order_created. Meta event_name is Purchase, Lead, CompleteRegistration. Mapping tables belong in the adapter. A shared enum named Purchase will be wrong on one of the two APIs. Web events also need source_url. That is not Meta event_source_url copied blindly: the field name and when it is required differ. Pixellint checks the OpenAI shape, not a guessed alias list.
data.type has to match the event
OpenAI documents four data shapes: contents, customer_action, plan_enrollment, and custom. page_viewed, contents_viewed, items_added, checkout_started, and order_created need contents. appointment_scheduled, lead_created, and registration_completed need customer_action. subscription_created and trial_started need plan_enrollment. A custom event needs custom, plus custom_event_name. Pixellint flags a mismatch; the image tag uses the same pairing on data[type].
contents is not available on customer_action. plan_id is only on plan_enrollment and custom. custom_event_name is omitted on standard events. app_installed and app_opened are CAPI only, with action_source mobile_app. The image tag does not take those events, and it has no user object. A raw email on the image query is an error.
What to do in the worker
Store one UTC instant. Convert at the edge: floor(ms/1000) for Meta event_time, Date.now() for OpenAI timestamp_ms. Name outbound fields after the vendor. Mint events[].id once per OpenAI event and persist it for retries, the same way you persist Meta event_id, as a different column.
Paste a redacted fixture in the playground. Empty Test Events on Meta does not tell you whether OpenAI ingested. Each vendor has its own diagnostics. Schema first, then the vendor UI.
pixellint validate json @openai-event.json --rulepack vendor/openai-conversions-api
Questions
What is OpenAI CAPI?
OpenAI CAPI is the OpenAI Ads Conversions API. timestamp_ms is milliseconds. It is not a Meta CAPI body on an OpenAI host.
Does data.type have to match the event?
Yes. order_created and page_viewed need contents. lead_created needs customer_action. Mixing those shapes is a documented miss, even when JSON parses.
Should I hash IP and user-agent for OpenAI CAPI?
No. OpenAI documents IP, user-agent, geo, and obref as unhashed. Hash emails, phones, names, and external ids after normalize, as lowercase hex.
Check the artifact
Paste the pixel URL or JSON body into the
playground. Same engine as
pixellint validate. Artifacts you test may be stored;
see privacy.