Create a brief from an opportunity
Accept a gap opportunity: mint a content brief from it and attach the brief to the row. Requires the write:opportunities scope AND an API key linked to a user (the linked user becomes the brief's created_by); an unlinked key is refused 403 before any lookup, so it never learns whether the id exists.
Only gap_ ids are accepted. prog_ ids return 400 (programmatic opportunities use batch generation) and decay_ ids return 400 (use the update action). A gap_ id whose suffix is not a valid UUID returns 400.
Ordering is load-bearing and observable. The opportunity is fetched first, so a 404 costs nothing and never mutates the row. The monthly brief allowance is checked BEFORE the row is claimed, so an at-cap organization is refused with the row untouched rather than left stranded at in_progress. Only then is the row claimed with a conditional UPDATE to status = in_progress; that single statement is also the closed-check and the concurrency check, so a dismissed/completed row, a row that already carries a suggested_brief_id, and a row another live accept is holding all lose it and get 409. Any failure after the claim releases it and restores the prior status.
Billing and metering: one accepted call consumes one brief from the organization's monthly brief allowance (calendar-month window; imported briefs and regeneration forks do not count). When the allowance is exhausted the call returns 429 with code brief_limit_exceeded and a truthful Retry-After giving the seconds until the monthly window rolls - this is a QUOTA, not a burst limit, so retrying before that instant cannot succeed and an SDK's default backoff must not re-hammer it. When the organization's subscription is canceled, paused, past due beyond grace, or its trial has expired, the call returns 403 with code subscription_inactive instead. A topic matching one of the organization's never-write-about terms returns 422 and no quota is consumed.
Success is 201 and asynchronous: the brief row exists immediately with status pending, and outline generation plus full research run in the background. Poll GET /api/v1/briefs/{brief_id} (or /briefs/{brief_id}/status) for readiness. The brief inherits the opportunity's cluster (cluster_id) and site, and its relevance bucket rides along - anything but confident is held for review at dispatch rather than auto-published.
Request
- Base URL: https://next.frase.io/api/v1
- URL: https://next.frase.io/api/v1/opportunities/{id}/brief
- Auth: API key in header X-API-KEY
Path parameters
Gap opportunity ID (gap_UUID). Other prefixes are rejected with 400.
Response
Brief creation started
Changes
No recorded changes to this operation across all 1 revision of this API.