Document scheduled_publish_at/unpublish_at on Articles API (Preview)#540
Open
kilian-tennyson wants to merge 1 commit into
Conversation
…eview) Documents the new scheduling fields gated behind AddArticleScheduledPublishing in the Preview spec. Requests accept ISO 8601 strings; responses return Unix epoch integers. Adds 400 examples for scheduling validation conflicts on POST and PUT. Companion to intercom/intercom#515420.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why?
The monolith PR intercom/intercom#515420 added
scheduled_publish_atandscheduled_unpublish_atto the public Articles API behind theAddArticleScheduledPublishingPreview version change, but the OpenAPI spec in this repo did not describe them. Without this, SDK code generation and the developer-docs mirror have no reference for the new fields.How?
Update
descriptions/0/api.intercom.io.yamlto add the two fields to the Articles request and response schemas (with the deliberate input string vs. output integer asymmetry) and document the scheduling validation rules via field descriptions and new400response examples on POST and PUT/articles.Decisions
descriptions/0/since the feature is Preview-gated; left stable version directories untouched.string+format: date-timeand responses asinteger+format: date-timeto mirror existing Intercom conventions (macro.created_atvscreated_at/updated_at) rather than reusing the shareddatetimeoneOf schema, which is for runtime-polymorphic fields.article_list_itemso they surface on both single and list responses via the sharedArticleResponsepresenter, matching the placement pattern from PR Add audit, suggestion, audience, and Fin statistics fields to Article API (Preview) #530.readOnly: trueandnullable: true; kept request fields optional (not added torequired:).POST /articles400 block with two new named examples (scheduling-conflict, conflicting-pending-schedules) and added a new 400 block toPUT /articles/{id}with three examples, covering the most discoverable validation failures while leaving empty-string/never-published rules in field descriptions.GET /articles/{id}since it takes no input that could trigger these validations.Review Guidance
█░░░░░░░░░ 1.2Why
Single-file, purely additive YAML changes to one spec version directory.█░░░░░░░░░ 1.5Why
Diff matches the PR description and plan exactly, including the called-out string-vs-integer asymmetry.░░░░░░░░░░ 0.8Why
Documentation-only OpenAPI spec edit; no runtime, auth, billing, or migration impact.Attention: Routine review — Additive Preview-only OpenAPI documentation; CI fern check is the main gate.
🧪 This AI-generated review guidance is experimental. Share feedback
Implementation Plan
Worker Implementation Plan
Plan: Document
scheduled_publish_at/scheduled_unpublish_aton Articles API (Preview)Companion to intercom/intercom#515420 (already merged on 2026-06-05).
Context
PR
intercom/intercom#515420adds two new fields to the public Articles API behind theAddArticleScheduledPublishingversion change (gated to Preview / Unstable):scheduled_publish_atandscheduled_unpublish_at. They appear on POST/articles,PUT
/articles/{id}, and the GET/list endpoints — and since the new builder preloadsschedules in batches, they also surface in list responses.
The machine-readable OpenAPI spec in this repo (
descriptions/0/api.intercom.io.yaml)is the source of truth for SDK code-generation (Fern) and is mirrored manually into
the
developer-docsrepo. Until this spec is updated, generated SDKs and the docssite will not know about these fields, so customer-facing API isn't fully shipped.
Deliberate type asymmetry (locked in by the monolith spec):
null→type: string, format: date-timenull→type: integer, format: date-timeThis asymmetry matches existing Intercom-wide conventions: epoch integers on output
(like
created_at,updated_atat lines 22946–22959), ISO 8601 strings on input(see
macro.created_atat line 31291–31294 for the string-form pattern).Files to Modify
Only edit
descriptions/0/api.intercom.io.yaml. No other version directories(
2.7/…2.15/) — the feature is Preview-only. Do not touchdeveloper-docs(that's a separate order). Do not touch the monolith (PR #515420 already done).
Edit 1 — Response schema:
article_list_itemLocation: Insert after the existing
help_center_audienceblock, immediatelybefore the next schema (
internal_article_list_item:at line 23039).So the insertion point is after line 23038.
This is the same placement convention PR #530 used when it added
created_by_id,updated_by_id,exclude_from_article_suggestions, andhelp_center_audiencetoarticle_list_item. The shared monolith presenter (ArticleResponse) surfacesthese new fields on both single-article responses (
articleschema, allOf-composedfrom
article_list_itemat line 22676) and list responses, so this placementcaptures both.
Why integer + format: date-time: matches existing
created_at(line 22946) andupdated_at(line 22953) on the same schema. Validators accept this combination(Intercom-wide convention).
Edit 2 — Request schema:
create_article_requestLocation: Insert after the
ai_sales_agent_availabilityblock (lines 26637–26641)and before the
required:block at line 26642.The exact insertion point is after line 26641, i.e. between the closing
example: trueofai_sales_agent_availabilityand therequired:line.Do not add these to
required:— both fields are optional.Edit 3 — Request schema:
update_article_requestLocation: Insert after the
ai_sales_agent_availabilityblock (lines 33575–33579).The
update_article_requestschema ends at line 33579 (norequired:block, unlikecreate_article_request), and the next schema begins at line 33580(
update_internal_article_request:).Insertion point: after line 33579.
Use the same field definitions as Edit 2 (the validation rules are identical
for create and update — both call into the same service-layer scheduling logic).
Edit 4 — Augment
POST /articles400 responseLocation: Lines 1334–1348 (the existing 400 block on
POST /articles).Currently has a single named example
Bad Requestshowing aparameter_not_foundcase. Convert to multi-example by adding two more named examples for the new
scheduling rules. The conversion keeps the existing example verbatim and adds two
siblings under the same
examples:map.After conversion, the
examples:block looks like:Why two new examples (not three): The empty-string rule and never-published rule
are covered in field descriptions. Two named examples is enough to make the most
common conflicts discoverable in generated SDK docs without bloating the response.
Edit 5 — Add
400response toPUT /articles/{id}Location: Currently the PUT endpoint at lines 1500–1564 has only
200,404,401. Add a400block between200(ends line 1536) and404(starts line 1537).Insertion point: after line 1536, before line 1537.
Three named examples for PUT because updating is where most scheduling actions happen
(creating a schedule, switching publish↔unpublish, encountering a never-published
article). This satisfies the acceptance criterion that validation rules be described
"in field descriptions and/or in '400' response examples" for PUT.
Do not add a 400 block to GET
/articles/{id}— GET doesn't accept input thatcould fail these validations.
Field Convention Summary (recap)
string+format: date-timemacro.created_at(line 31291)integer+format: date-timecreated_at(line 22946)nullable: truenullcancels schedule on input, indicates "no schedule" on outputreadOnly: trueDo NOT use the shared
datetimeschema at line 21776. ThatoneOfschema is forfields where either shape is accepted at runtime, which is not our case — the request
side accepts only strings and the response side returns only integers.
Verification
After making the edits, verify in this order:
YAML syntax:
node -e "require('js-yaml').load(require('fs').readFileSync('descriptions/0/api.intercom.io.yaml','utf8'))"or simply rely ongit diffto catch obviously broken indentation. The repo hasyaml@2.8.3in node_modules already.Spec validation: The CLAUDE.md mentions
fern check. There is nonpm run validatescript in package.json (confirmed). Try:If the
fern-apiCLI isn't installed locally, this is fine —.github/workflows/fern_check.ymlruns it on every push, so CI catches issues. Do not install fern-api globally on the worker just for this. Just push and let CI report.Diff sanity check:
git diff --stat descriptions/0/api.intercom.io.yamlshould show ~70–80 insertions, zero deletions (we're appending fields and a 400 block; we are not replacing existing content).Read-back: After editing, re-read the four modified regions and confirm:
article_list_itemnow ends withscheduled_unpublish_atcreate_article_requesthas the two new fields above itsrequired:blockupdate_article_requesthas the two new fields at the end of itsproperties:blockPOST /articles400 has three named examplesPUT /articles/{id}has a new 400 response with three named examplesNo collateral edits:
git statusshould show only one modified file (descriptions/0/api.intercom.io.yaml). Other version directories (2.7/through2.15/) must be untouched.Commit + Submit
parthas submit.(e.g. wants the descriptions to be shorter, prefers different example
timestamps), update and resubmit.
The PR description that
parthas submitultimately creates must follow this repo'stemplate (
.github/PULL_REQUEST_TEMPLATE/pull_request_template.md):intercom/intercom#515420Critical Files Touched
descriptions/0/api.intercom.io.yaml(only file edited)Critical Files Read for Reference (not edited)
descriptions/0/api.intercom.io.yamllines 1283–1602 (Articles paths)descriptions/0/api.intercom.io.yamllines 22663–23038 (article,article_list_item)descriptions/0/api.intercom.io.yamllines 26545–26644 (create_article_request)descriptions/0/api.intercom.io.yamllines 33482–33579 (update_article_request)descriptions/0/api.intercom.io.yamlline 31291 (macro.created_atISO 8601 string pattern)descriptions/0/api.intercom.io.yamllines 22946–22959 (epoch integer pattern)a188e46(PR Add audit, suggestion, audience, and Fin statistics fields to Article API (Preview) #530) — the exact reference pattern for adding fields toarticle_list_itemOut of Scope
descriptions/2.7/…descriptions/2.15/) — Preview-only feature.developer-docsrepo — separate order.Guidance Carried Forward from the Order Prompt
descriptions/0/. Confirmed Preview-only.work/0b193391/worker(already set)./Users/kiliantennyson/.parthas/worktrees/intercom-openapi/0b193391/worker.fern check(nonpm run validate); rely on CI iffern-apiisn'tinstalled locally.
intercom/intercom#515420.parthas submit.Parthas Order (task/issue)
Document scheduled_publish_at / scheduled_unpublish_at on Articles API (companion to intercom #515420)
Problem
PR
intercom/intercom#515420addsscheduled_publish_atandscheduled_unpublish_atfields to the public Articles API (POST/PUT/GET on/articles), gated behind a newAddArticleScheduledPublishingversion change available in Preview. The machine-readable OpenAPI specification in this repo (descriptions/0/api.intercom.io.yaml) does not yet describe these fields, so SDK generation and the developer-docs spec mirror will not pick them up.Why This Matters
The monolith PR can merge independently, but the public API is not fully shipped until the OpenAPI spec and developer-docs companion PRs land. The OpenAPI spec in this repo is the source of truth for both auto-generated SDKs and the spec that
developer-docsmirrors — without it, customers writing against the new fields have no reference.Goal
Update
descriptions/0/api.intercom.io.yaml(Preview/Unstable version) so the Articles request and response schemas accurately describe the new fields, the validation behavior, and the error responses. Open a PR cross-referencing the monolith PR.Context
POST /articles,PUT /articles/{id},GET /articles/{id}(Articles tag).scheduled_publish_atandscheduled_unpublish_ataccept an ISO 8601 timestamp string ornull.null.INVALID_PARAMETER.state: "draft"combined withscheduled_publish_at→ 400 (conflict).scheduled_unpublish_aton a never-published article → 400.nullvalue cancels a pending schedule (not an error).~/src/intercom/.claude/skills/ship-public-api/SKILL.mdand~/src/intercom/.claude/skills/ship-public-api/references/documentation.mdbefore generating any spec edits — they contain the OpenAPI conventions, the "OpenAPI Best Practices" section, and the three-repo-pattern guidance.descriptions/0/. The feature is gated to Preview; stable version directories do not have it.developer-docs— that's a separate order. The developer-docs sync is a targeted edit, not a file copy.Acceptance Criteria
descriptions/0/api.intercom.io.yamldescribes both fields on the Articles request and response schemas, with the input ISO 8601 string vs output Unix epoch integer difference reflected accurately in the schema definitions.'400'response examples.npm run validateor equivalent) passes.intercom/Intercom-OpenAPIwhose description cross-referencesintercom/intercom#515420.Non-goals
descriptions/2.10/,descriptions/2.15/, etc.) — the feature is Preview-only.intercom/(the monolith) — that work is already done in PR #515420.Generated with Claude Code, zen coded with Parthas