Skip to content

feat(api): activate the ads public API scope - #1132

Merged
realcodesiman merged 5 commits into
mainfrom
realcodesiman/feat-ads-scope-public-api
Sep 12, 2026
Merged

feat(api): activate the ads public API scope#1132
realcodesiman merged 5 commits into
mainfrom
realcodesiman/feat-ads-scope-public-api

Conversation

@realcodesiman

Copy link
Copy Markdown
Contributor

Summary

  • The ads workspace-token scope shipped in the enum/registry/i18n from day one but had no endpoints wired to it — a token scoped to ["ads"] reached nothing.
  • Adds public API routes for ads conversion-rule CRUD, CTWA/CTM/CTID funnel and CAPI-delivery reads, conversion export, ad-account reads, and the full messaging-ad campaign lifecycle (create/retry/publish/pause/delete + video upload).
  • Every handler calls the same packages/business service method its private/UI counterpart already calls, per .agents/rules/data-access.md.

Changes

  • apps/builder/src/features/ads/api/public.ts + schema/public.ts — conversion rules, funnel, CAPI delivery, export, ad-account reads
  • apps/builder/src/features/ads-campaign/api/public.ts + schema/public.ts — messaging-ad campaign lifecycle
  • apps/builder/src/routers/public.ts — mounts ads on the public router
  • packages/business/src/ads-conversion/service.ts — adds findOrFail (single-rule read with the standard not-found contract, reused by the new GET /v1/ads/conversion-rules/{id} handler)
  • docs/developer/workspace-api-tokens.md — endpoint-to-scope table and the two invariants specific to this scope (no assertWorkspaceSuperAdmin on the token path; createdBy always null for token-created campaigns)
  • Tests: ads-public-scope.test.ts (router wiring), ads-public-api.test.ts, ads-campaign-public-api.test.ts (handler behavior, including the missing-session-user regression guard), plus ads-conversion-rule.service.test.ts coverage for findOrFail

Test plan

  • pnpm lint
  • pnpm --filter builder check-types
  • pnpm --filter @chatbotx.io/business check-types
  • pnpm --filter builder test (full suite, 3355 passed)
  • pnpm --filter @chatbotx.io/business test (full suite, 2145 passed)

@github-actions github-actions Bot added the feature New feature or request label Sep 9, 2026
realcodesiman and others added 4 commits September 12, 2026 10:54
Wire the previously-inert `ads` workspace-token scope to real endpoints:
conversion-rule CRUD, CTWA/CTM/CTID funnel and CAPI-delivery reads,
conversion export, ad-account reads, and the full messaging-ad campaign
lifecycle. Every handler calls the same business-service method its
private/UI counterpart uses.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds name/description/globs frontmatter to data-access.md, git.md, and
no-dynamic-import.md so the rules are self-describing and glob-scoped
for automatic loading; sync-agent-instructions.mjs now strips the
frontmatter block before mirroring git.md's body into generated docs.
Closes gaps left by the initial ads public API activation:

- read_only tokens can no longer force an uncached Graph refresh via
  the `refresh` param on campaign/insights/ad-account routes, and gain
  a narrow POST-for-read allowlist entry for the insights endpoint
- creative video upload accepts a lower base64 cap on the public route
  than the session-gated private one
- rule/status mutations return explicit 422s via `safeParse` instead
  of letting a raw ZodError fall through to a generic 500, and use the
  correct 201/204 success statuses
- CAPI status transitions are now guarded by an explicit
  pending -> terminal state machine in the service instead of being
  writable by any caller
- worker's send-conversion-event handler calls adsConversionService
  instead of importing the repository directly, keeping the
  action/handler -> service -> repository chain intact
- export/retarget pagination now derives `hasMore` from the
  repository's own limit+1 over-fetch instead of `rows.length ===
  limit`, fixing a false "no more pages" result when a page happens to
  fill exactly
- contact-filter CTWA retarget predicate generalizes the
  channel-omitted legacy-caller behavior from WhatsApp-only to
  Messenger/Instagram as well
@realcodesiman
realcodesiman force-pushed the realcodesiman/feat-ads-scope-public-api branch from 487109a to 4002107 Compare September 12, 2026 04:04
Delivers the remaining ads public-API surface and fixes the layering
gaps the prior activation left behind:

- facebook (workspace-wide Lead Ads) no longer falls through to the
  any-channel predicate for the `conversations` segment/count, in both
  the contact-filter query and the funnel service
- Facebook Ads Graph cached reads, channel-ad-account resolution, and
  the merged analytics (funnel + Meta spend) orchestration move from
  apps/builder into packages/business, closing the "packages/business
  cannot import the builder's copy" gap that blocked a public handler
- retarget-audience sync and messaging-ads disconnect (with token
  revoke) become business services instead of server-action-only logic
- new public endpoints on the `ads` token scope: merged analytics
  overview/timeseries, single conversion-event read, custom-audience
  listing, retarget-audience sync, and messaging-ads connection
  list/disconnect
- regression coverage for the facebook/conversations fix and the new
  services/endpoints
@realcodesiman
realcodesiman merged commit aa205e9 into main Sep 12, 2026
4 checks passed
@realcodesiman
realcodesiman deleted the realcodesiman/feat-ads-scope-public-api branch September 12, 2026 07:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant