Skip to main content
Use this guide to test an Apostra-powered, customer-branded app in ChatGPT before preparing its public submission. ChatGPT currently labels this developer-mode connection a Plugin.
A developer-mode connection is private test configuration. Its name, icon, and description do not publish an app, change Apostra MCP server’s identity, or automatically carry into another customer’s submission.

Before you start

You need:
  • a ChatGPT account or workspace that permits Developer mode;
  • an Apostra account with access to a buyer or seller account enrolled in the v3 preview that you will demonstrate;
  • an owner-approved app name and short description; and
  • a square PNG icon, ideally 256 x 256 pixels and no larger than the limit displayed by ChatGPT. The current form accepts at most 10 KB.
Use a review or demo account with representative data. Do not record production credentials, access tokens, private customer data, or real campaign spend.

1. Add your plugin in Developer mode

  1. In ChatGPT, open SettingsSecurity and login.
  2. Turn on Developer mode. Availability depends on the ChatGPT account and workspace policy.
  3. Open the ChatGPT Plugins page and select the plus button.
  4. Complete New Plugin with these values:
  1. Review the custom-server warning and select I understand and want to continue only if the endpoint exactly matches your private-label handoff.
  2. Select Create and complete the app’s sign-in flow with a reviewer whose home Apostra account is the account assigned to this private-label app. The hostname is account-bound and refuses a different active account.
  3. Review the tools and metadata ChatGPT discovers from the server.
If ChatGPT cannot create the connection, copy the private-label URL from the handoff again, check that OAuth is selected, and confirm that your workspace allows custom MCP servers. Do not edit the URL path or fall back to the shared Apostra endpoint. The v3 authentication guide explains which Apostra account and permissions the login grants. If Scan Tools reports Access token is not valid for this protected resource after changing the MCP Server URL, disconnect the saved authorization and reconnect before scanning again. ChatGPT discovers the OAuth configuration from the server; no advanced-field overrides are required.

2. Verify the connection

Start a new chat, enable the plugin from the tools menu, and ask:
Confirm that the result names the assigned account before demonstrating any workflow. If it does not, reconnect with the grant-bound reviewer credential for that account’s System advertiser; do not switch a private-label app into another account. Then test the exact prompts you plan to give reviewers:
  • a read that returns useful account data;
  • a representative write that shows the expected confirmation before it runs;
  • a follow-up that reuses an identifier from the prior result; and
  • an unsupported or unsafe request that produces the intended clarification, refusal, or safe fallback.
Use demo fixtures for writes and stop before creating real spend. If you change tool metadata or deploy a server update, refresh the connection and rerun the tests in a new conversation.

3. Record the review video

Record one clean end-to-end session while the developer-mode plugin is enabled. The recording should show:
  1. the app name and icon in ChatGPT;
  2. the plugin selected for a new conversation;
  3. get_status confirming the review account;
  4. at least one representative read workflow;
  5. the confirmation and result for a safe demo write, when the app supports writes; and
  6. the expected behavior for one negative test.
Keep the browser URL, app identity, prompts, confirmations, and final results legible. Hide password-manager overlays, credentials, OAuth tokens, personal data, internal admin screens, and unrelated browser tabs. Store the recording in the customer’s approved file-sharing system; do not commit video files to a source repository. The video is part of the submission handoff and a useful reproduction artifact. OpenAI’s portal requirements can change, so check the live form to determine whether to upload the recording, link it, or retain it for reviewer follow-up. For reference, watch the example review video created for Apostra app.

4. Prepare the public submission

Developer-mode branding is not a public listing. The intended handoff is one app-specific submission package rather than a request to assemble each upload by hand. An account admin prepares it on the Listing page’s ChatGPT destination (see Create a white-label ChatGPT app for the full walkthrough; the retired Account Settings “Discovery & distribution” tab, and later the retired “Branding & distribution” page, held these same controls before AI-7434 and AI-8891 moved them here):
  1. Get Public distribution — the Listing page’s fourth step — live: add the Distribution package, then point your domain at Apostra with one CNAME. (An app that already runs on its own active per-app hostname keeps its ChatGPT destination — existing reviewer grant, token, and package — without this step; requesting a new reviewer grant still needs it.) Apostra checks it for you; there is no separate tenant-specific TXT record or dedicated ChatGPT hostname to configure. Apostra first-party app uses its platform-managed hostname and skips this step entirely.
  2. Review Brand identity at the top of the page. It identifies whether the storefront resolves a self-hosted brand.json, an AAO-managed identity, a community profile, or no reusable identity. A usable resolved logo automatically generates the 256 × 256 directory PNG and 48 × 48 composer PNG, but this is optional. You can instead upload both channel-specific PNGs from the ChatGPT destination. If no identity resolves, you can use the AAO builder to self-host or request AAO-managed hosting, or skip that step and upload the app icons directly. The directory category is set to Business by Apostra for new registrations (an existing registration keeps its saved category; the value appears in the approval preview); other one-time portal choices are completed in OpenAI rather than duplicated here.
  3. In the ChatGPT destination, choose Request access once the listing is Public. (An app that already runs on its own active per-app hostname keeps an existing grant, its token, and its package without Public distribution; a new grant still requires it.) The action requires the storefront’s Listing + Distribution package to include customer-branded AdCP, customer-branded ChatGPT app, organization advertiser lifecycle, and public listing distribution entitlements. Apostra records a bounded review request owned by the current account; the destination shows its requested, provisioning, active, failed, revoked, or expired state. Operator activation creates a no-spend System advertiser in this storefront and issues one advertiser-scoped, read-only buyer credential. When the grant is active, choose Open reviewer login to view and copy its email and password. Account admins can reopen the same login while the grant remains active; Apostra does not put it in the submission ZIP or expose it to the model. The login is shared across OpenAI, Anthropic, and Microsoft remote MCP directory reviews for this listing. Choose Revoke reviewer access as soon as review ends. If status is temporarily unavailable, the destination disables both actions until a refresh can safely determine the current grant.
  4. Paste the OpenAI verification token in the same ChatGPT destination — this proves ownership of the storefront’s own public listing domain, the same one verified in Public distribution, not a second hostname. After you publish the token, the destination checks (probe_discovery_openai_challenge) only that the address returns that exact token; OpenAI performs domain verification separately.
  5. Review the values OpenAI will see, then select Prepare download. If the listing changed while the page was open, review the refreshed values and prepare it again. When the package is ready, select Download package to start the browser download directly from that second click.
The page hydrates this control from get_chatgpt_app_config. reviewerSandboxAvailable is true only when the current Public listing and complete entitlement bundle permit a new request. reviewerSandboxGrantStatus is loaded when both reviewer eligibility and the existing account-owned grant lookup succeeded. It is unavailable when either lookup cannot be read safely, so the page offers a retry instead of treating an outage as a missing entitlement. An existing grant remains visible and revocable if later configuration changes make a new request ineligible. The bundle contains:
  • chatgpt-app-submission.json with the current tool annotations, all three required annotation justifications, and test prompts for the private-label app;
  • the selected 256 x 256 directory icon and 48 x 48 composer icon, whether generated from resolved brand identity or uploaded for this app;
  • interchange-buyer-skills.zip for buyer apps as a manual fallback containing one upload-ready directory of the same account-readiness, campaign-setup, and campaign-management skills advertised by the V3 server;
  • readiness-report.json, which records a stable snapshot ID, every portal field, its source, readiness, blockers, and regeneration rules; and
  • one consolidated README.md with the complete field map, prompt and locale review, release copy, screenshot plan, and video storyboard.
The outer ZIP intentionally contains no duplicate listing, CSP, annotation, prompt, checklist, or release-note files. Those details live either in the import JSON, the readiness report, or the README. The generated chatgpt-app-submission.json uses the portal-required $schema value https://developers.openai.com/apps-sdk/schemas/chatgpt-app-submission.v1.json. The package includes justifications only for tools exposed by its MCP endpoint. Account-bound app hostnames omit switch_account; the shared Apostra endpoint includes it because account switching remains available there. After importing the file, review the portal’s imported, skipped, missing, and mismatched counts before submitting the app for review. If OpenAI rejects that value, do not hand-edit the file. Send Apostra support the exact validation error; after support confirms that an updated release is deployed, download a fresh submission package. OpenAI performs the live tool and skill scans in the submission portal. The V3 MCP server advertises OpenAI’s bounded MCP Skills extension, so Scan tools automatically imports the three canonical buyer skills when the authenticated account is a Buyer Account. Seller Account scans do not receive buyer skills. Review the imported skills immediately before submission. The imported skills are submission-time snapshots, not live runtime content. Run Scan tools again after Apostra publishes a skill update. The buyer ZIP contains interchange-buyer-skills.zip only as a same-content fallback for manual upload when the scan cannot complete; do not upload it when the scan succeeds. Starter prompts remain a portal choice because OpenAI’s submission JSON schema does not currently define them. A storefront with no logo in its resolved brand identity can still download the package after both app-specific PNGs are uploaded from the ChatGPT destination. Upload the 256 × 256 directory icon and 48 × 48 composer icon together; an incomplete pair is rejected. To use automatic icons instead, add a logo at the system that manages the identity, refresh the page, choose Use automatic icons, and regenerate the bundle. The source choice persists across later saves; switching to automatic does not copy generated PNG bytes into the manual override fields. Legacy API integrations may continue updating one existing icon at a time, while new manual selections must provide the pair. Apostra can read a self-hosted brand.json, but cannot edit it. The verification token is public at the challenge URL and visible on the admin-only Listing page, but deliberately excluded from the ZIP, logs, and reviewer handoff. Never reuse another customer’s bundle or replace its exact private-label MCP URL with the shared Apostra endpoint. The publisher still completes the requirements that cannot safely be generated:
  • select the verified business or individual identity that will publish the app;
  • confirm Apps Management write access for each submitter;
  • confirm the domain-verification challenge published from the Branding & distribution Page before pressing Verify in OpenAI;
  • confirm that the account-owned reviewer request created its dedicated, least-privileged no-spend System advertiser. Open the reusable reviewer login from the destination, paste it only into the directory’s protected test-access field, ensure it works without MFA, SMS, email confirmation, or private-network access, and revoke the grant when review ends;
  • approve country availability, policy attestations, and the generated listing and release copy; and
  • approve the final review video and its sharing location.
Follow OpenAI’s current submission guide when completing the portal. Scan the production server again immediately before submission and review every discovered tool, annotation, skill, domain, and validation result.

5. Manage review and publication

Submitting starts OpenAI’s review; it does not publish the app. Keep a release record in your approved system with the bundle’s snapshot ID, source revision, generation and submission times, OpenAI draft or version reference, publisher owner, and current review state. Keep the exact outer ZIP in approved, access-controlled release storage. Do not put reviewer credentials, OAuth tokens, domain-verification tokens, or private customer data in that record, the ZIP, or a support ticket, and do not attach the ZIP to an unrestricted ticket. While review is active, keep the storefront-owned System advertiser, its grant-bound read-only reviewer login, synthetic no-spend fixtures, production MCP endpoint, domain challenge, tool metadata, and scanned skills available. Send Apostra support any reviewer feedback verbatim with the snapshot ID. Do not regenerate or hand-edit the submitted files unless the feedback requires a new version. After approval, test the approved snapshot once more, then use the OpenAI portal’s Publish action. Verify directory discovery, installation, OAuth, get_status, and one safe workflow, and monitor the launch for 24 hours. Revoke the grant-bound reviewer credential when OpenAI no longer needs it. After rejection, preserve the exact feedback and snapshot ID. Correct the canonical configuration or Apostra source, download a fresh bundle, replace the affected files, scan tools and skills again, rerun all five positive and three negative cases, update the release notes, and submit a new version. Published metadata and imported skills are reviewed snapshots; later server-side skill changes do not update the published app automatically.

Get conversational setup help

Give an MCP-capable agent the public, versioned Publish an OpenAI App skill. Authenticated Seller Accounts also advertise it through the MCP Skills extension, so Murph and compatible clients can load the same workflow without copying this guide into a prompt. Distribution uses the existing V3 noun surface rather than adding provider-specific tools:
  • get({ kind: "distribution" }) returns the configured public hostname, CNAME target, ownership record, hostname status, MCP URL, and OpenAI challenge status. An active customer CNAME is the server-owned verification result; the agent does not claim to test an OpenAI submission.
  • The same read returns a bounded channels.chatgpt summary: whether the listing is ready to submit, how many blocking items remain, this channel’s own hostname and verification status, whether the submission bundle is current and the listing approved, and one next-step line. It never claims the app is live in ChatGPT — OpenAI’s review and publish decision happens entirely on their portal — so it reports platform-side readiness only.
  • save_seller({ distribution: { openaiChallengeToken: "..." } }) publishes the portal-provided challenge token. Replacing or removing a current token requires the corresponding confirmation field.
Both operations are Seller-account-admin only. Reviewer access, portal scans, screenshots, and video remain manual work described by the submission package. For an end-to-end conversational setup, connect the V2 Storefront MCP endpoint and follow its Distribution skill section. It exposes the same guarded operations as the Listing page: update the shared listing, configure and publish Discovery, configure ChatGPT icons and the domain-ownership challenge, request reviewer access, and obtain a fresh signed OpenAI package URL. The agent makes one mutation per turn and stops for explicit owner confirmation at each consequential boundary. OpenAI portal scans, screenshots, attestations, submission, and publication remain manual.

Use the native OpenAI plugin package

Apostra repository also contains a universal OpenAI plugin package for the shared production endpoint. It includes the approved icons, the same three canonical buyer skills, and a direct HTTPS MCP mapping to https://api.interchange.io/mcp/v3. Installation starts OAuth; API keys and provider credentials never belong in the manifest or prompts. The plugin manifest, marketplace entry, skill bytes, and release notes are versioned together. Directory screenshots and any registered OpenAI app identifier remain publication inputs controlled by Apostra publication owner; the package does not invent them. Revalidate and re-record those assets for each visible release.

Understand the white-label boundary

Apostra does not infer ChatGPT branding or publisher details from an AdCP partner registration, seller profile, or MCP connection. In particular:
  • adding a partner AdCP endpoint does not turn it into a ChatGPT MCP endpoint;
  • a customer’s logo and listing copy must be provided in that customer’s developer-mode configuration; the public submission uses the automatic or app-specific icon pair selected on the Listing page;
  • the verified publisher identity, public policies, and support details must match the organization submitting the app. When the app uses Apostra, the customer’s privacy policy must also disclose the relevant Apostra data handling; and
  • a customer-owned MCP host requires its own production endpoint, OAuth metadata, tools, annotations, UI resources, security review, and submission.
Do not use the shared https://api.interchange.io/mcp/v3 endpoint for a private-label Developer-mode connection or public submission. OpenAI verifies one exact token at the host-level /.well-known/openai-apps-challenge path; changing only the MCP URL path cannot separate multiple app challenges on the same host. A customer-owned public app therefore needs either a dedicated, customer-controlled hostname that serves its MCP, OAuth, and verification challenge, or an explicit arrangement approved by both Apostra and OpenAI. Control of an Apostra account does not grant control of the api.apostra.com domain.