---
title: "Connect an OpenAI Ads account"
method: POST
path: "/v1/connect/openai-ads/credentials"
tags: ["Connect"]
---

# Connect an OpenAI Ads account

`POST /v1/connect/openai-ads/credentials`

Connect an OpenAI Ads account using an API key from ChatGPT Ads Manager.

The key grants full campaign write access on OpenAI's side (OpenAI does
not offer a read-only key scope). Zernio uses it to read ads and
performance, and to create and manage campaigns you set up through
Zernio (create, status, budget, and cancel). Campaigns created
directly in ChatGPT Ads Manager can still be managed there.

## Request body

- object
  - `apiKey` string, required — API key from ChatGPT Ads Manager (Settings). Grants full read/write access on OpenAI's side; Zernio only ever reads with it.
  - `profileId` string, required — Your Zernio profile ID
  - `state` string — Optional state passthrough for the connect flow.
  - `redirectUri` string, uri — Optional URL to redirect to after successful connection

## Response `200`

OpenAI Ads connected successfully

- object
  - `accountId` string
  - `adAccountName` string
  - `redirectUrl` string

## Other responses

- `400` — Invalid request
- `401` — Unauthorized, or the API key could not read an OpenAI ad account (code invalid_credentials).
- `402` — Payment method or enterprise contract required. The authenticated account hit a billing gate before the connection could proceed. Three reasons: - `free_tier_exceeded`: the team has connected more accounts than the free tier allows. Add a payment method on the dashboard to continue (the user will be billed per additional connected account). - `twitter_passthrough`: connecting an X (Twitter) account requires a card on file from day one because X API calls incur real per-call pass-through costs. Applies to the 1st X account, not just the 3rd+. - `enterprise_required`: the team is on an enterprise contract with a negotiated connected-account cap and has reached it. Self-service teams have NO connection cap (the $1/account rate continues at any scale), so this reason can only fire for teams whose contract sets an explicit limit. `dashboard_url` deep-links to the enterprise contact page rather than the billing tab. The end-user already has a card on file; this gate is about contract terms, not card collection. SDK consumers should switch on `reason` to render the right prompt. For `free_tier_exceeded` and `twitter_passthrough`, redirect the end-user to `dashboard_url` to add a payment method via Zernio's hosted Stripe Setup Checkout. For `enterprise_required`, redirect to `dashboard_url` (the enterprise contact form) to adjust the contract's limit.
- `403` — Ads add-on required.

## Changes

- **2026-08-31** `bdd771244d76` — 1 info
  - added the non-success response with the status `402`

[Change history](https://skmtc.dev/zernio/apis/zernio-api/changes/v1/connect/openai-ads/credentials/post.md)

---

[API](https://skmtc.dev/zernio/apis/zernio-api.md) · [All operations](https://skmtc.dev/zernio/apis/zernio-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/zernio/zernio-api/revisions/2d81890d21d5/schema)
