Changelog
Changes to the Archive API and to these guides, newest first.
About this changelog
This page records partner-visible changes to the /api/v2 surface: schema additions and removals,
authentication or header changes, rate-limit behavior, and error-shape changes. Add an entry in any
pull request that changes the GraphQL schema or guide-visible behavior, dated by its merge date,
with one bullet per change.
Stability and versioning
Everything this documentation describes as generally available changes additively only. New fields, arguments, types, enum members, and MCP tools may appear at any time; existing ones are not renamed, removed, or changed in meaning. The same rule covers MCP tool names and input schemas, and the webhook delivery envelope — new keys may be added, existing keys keep their shape.
Build for that: select only the fields you use, ignore unknown keys in JSON payloads, and treat
unrecognized enum values as “other” rather than an error. A change that would break a correctly
built integration ships as a new URL version (an /api/v3), never in place on /api/v2.
Coverage began at different times: the GraphQL schema has been additive-only since launch, while MCP tools joined the contract when the tool surface went generally available on 2026-08-14. MCP-only breaking changes from before that date — such as the 2026-07-25 argument-casing migration — were part of the pre-GA shakedown and are recorded below as Breaking (MCP only) entries; none can recur now that the tools are GA.
The one exception is alpha features, which are opt-in precisely because they carry no stability contract. Everything else that is partner-visible — schema, behavior, limits, error shapes — lands as a dated entry below when it changes.
2026-11-04
- Deep Research credit-permission errors now distinguish read-only connections from denied credit-spending access and explain how to resolve each. Campaign-edit access alone does not grant permission to spend credits.
- Documentation only: the
engagementHistoryfirstargument description now states its default of 20 and its maximum of 1000. The pagination guide now listsoperationRecordsas the second connection that accepts up to 1000. Behavior is unchanged.
- A
creatorsquery that passescustomAttributeConditionsorpresetIdnow costs the same as acreatorsquery without them. A page of 20 records costs 66 points instead of 316. X-RateLimit-Costand ther=value ofRateLimitdrop for those calls. Plan limits do not change.
- Re-enabling a webhook subscription with
replayFailedSince24hnow replays its failed backlog through the paced retry path in batches. Replay normally starts on the next sweep; backlog and delivery pacing can delay the first attempt.
2026-11-03
- When Archive cannot schedule the refresh job,
refetchEngagementBulknow returns a retryable userError saying the refresh could not be scheduled. Archive holds no credits for that request. A retry with the sameitemIdsis not reported inskippedItemIds.
- A
/api/v2request that costs more than your plan allows per request now returns HTTP 200 withextensions.codeQUERY_TOO_COMPLEXand the message “This request costs 680 points; your plan allows at most 500 per request. Split it into smaller requests.” (with your request’s numbers), instead of a 429 whoseRetry-Afternever came true. Nothing is charged. Split the request; don’t retry it. - The MCP server returns the same text as an
isErrortool result for such a call, instead of “Rate limit exceeded. Retry after N seconds.”
- The
getSocialProfilesMCP tool’sincludeStatssummary now returnsengagementsImpressionsAvg.engagementsViewsAvgis still returned. - The
SocialProfileStatsdescriptions now say thatengagementsViewsandengagementsViewsAvgare rarely populated (0 for most profiles), and they point toengagementsImpressionsandengagementsImpressionsAvgfor views, plays, or reach.
2026-11-02
- An unknown
orderBy,order_by,sortBy,sort_by,sortororderargument on a field that takessortingnow suggestssortingin the validation error, for example onitems(orderBy: …). MCP tools return the same hint:searchItemswithorderByanswers “did you mean ‘sorting’?”. - The
itemsfield and itssortingargument now show how to sort by engagement or earned media value, and point tofilter.engagementfor engagement ranges.
- The MCP tools
searchItemsandgetCompetitorBrandItemsnow returncurrentEngagement.impressionsin bothconciseanddetailedresponses.viewsis still returned. - The
Engagement.impressionsandEngagementHistoryEntry.impressionsdescriptions now nameimpressionsas the field for a post’s views, plays, or reach. Theviewsdescriptions now say it is rarely populated and is null for most items.
submitFeedbackreports a problem with the Archive API to the Archive team: a bug, unclear docs, a missing capability, an unexpected result or a slow call. It returns only a receipt,{ feedback: { id, duplicate }, userErrors }.- The same report sent again within 24 hours returns the earlier receipt with
duplicate: true. A workspace sends at most 10 reports at once, then one more every 15 minutes; over the limit the call returns a userError on["input"], not a 429. - Reports are not visible to workspace users and get no reply. Leave personal data out of them.
- The matching
submitFeedbackMCP tool is listed for every authorized caller, read-only OAuth connections included. Pricing: the mutation is a write costing 50.
- The MCP server’s
initializeinstructions ask agents to callsubmitFeedbackon their own when they hit what looks like an Archive problem, continue the task, and tell the user in one line with the receipt id. - MCP tool errors “Tool execution failed” and “Invalid argument …” now end with “If this looks like
an Archive bug, report it with submitFeedback.”
submitFeedback’s own errors do not.
2026-10-31
updateCampaignposts(add and remove by item id) now also applies toBRAND_MONITORINGcampaigns, with the same limits and per-entry errors as onCONTENT_CAPTURE. Added posts sit alongside automatically captured ones, and an added post’s creator joins the roster. A removed post can be captured again by a later replay when it is in-window and from a brand-listening source.CREATOR_MONITORINGstill refusesposts.
2026-10-28
CampaignTypegainsBRAND_MONITORING. Brand Monitoring campaigns built in the app, which readcampaignType: nulluntil now, readBRAND_MONITORINGand can be changed withupdateCampaign(name,dateEnd,creators). Their tag, content and source narrowing is kept as stored. A client that switches exhaustively onCampaignTypesees a new value.createCampaigncreatesBRAND_MONITORINGcampaigns where the workspace offers Brand Monitoring.dateStartis required anddateEndis optional (omitted means open-ended); the campaign captures workspace-wide, and it takes nosettings.updateCampaignrefuses adateEndon an open-endedBRAND_MONITORINGcampaign, as a userError on["input","dateEnd"].- MCP
createCampaign,updateCampaignandgetCampaigndescribe the new type.
OperationRecord.globalCreatorId: for a creator-import record thatSUCCEEDED, the global, person-level id of the creator behind the row’s main handle. It stays the same when the same person is imported into another workspace, and it is not an input tocreator(id:)(usecreatorIdfor that). Null for other records, other operation types and rows imported before this field existed.
2026-10-23
Collection.itemCountoncollectionsandcollection, also returned by thegetCollections/getCollectionMCP tools, is now computed from the item search index with one aggregation per request instead of a per-workspace Postgres count. The field answers in well under a second on large workspaces where it took 20-60 s.- Behavior change:
itemCountno longer counts soft-deleted items and now matchesitems(filter: {collectionsIds: [id]}).totalCount, up to search-index lag (seconds) and any orphaned index documents. It is no longer refreshed by a 5-minute cache.
- The
INVALID_INPUTmessage thatsocialProfile(and thegetSocialProfileMCP tool) returns for anaccountNamethat isn’t a handle now names the platform with the right article: “is not an Instagram handle”, “a TikTok handle”, “a YouTube handle”. It used to read “is not a instagram handle”. The error code is unchanged. - The same lookup with
provider: INTERNAL,fallback: trueand an input that isn’t a handle returns thatINVALID_INPUTerror (“is not a valid handle”) instead of an internal error.
createViewGroupandupdateViewGroup(and the matching MCP tools) now also refuse a name that differs from an existing view group’s name only by its spacing: a no-break space, a narrow no-break space or an ideographic space where the other name has an ordinary space, or a run of spaces where it has one. The refusal is the usualA view group named "…" already exists in this workspace.userError on the name field. Existing names are unchanged, and sending a group’s current name back still keeps it.- The same mutations no longer treat a zero-width joiner or non-joiner as invisible where it changes what renders: an emoji sequence such as 👨👩👧 and its separate emoji 👨👩👧, or a Persian word spelled with and without a non-joiner, are now distinct names. A joiner between Latin letters, next to a space or at either end of a name is still ignored.
- MCP refuses a request id with a fractional part or an exponent (
1.5,1.0,1e3) with a-32600Invalid Request error (idnull), as it already did fornull. Send a string or an integer id. - MCP refuses a request whose
Content-Typeis missing or is notapplication/json(for exampletext/plain) with HTTP415and a-32000JSON-RPC error (idnull). - MCP refuses a request whose
Acceptheader is missing, or accepts noapplication/json, with HTTP406and a-32000JSON-RPC error (idnull). SendAccept: application/json, text/event-stream;*/*andapplication/jsonalone are still answered. - Either refusal is answered only to a request that carries a credential. Without one, the
401OAuth discovery challenge comes first, as before, and apingor a notification is still answered ({}/202). - On MCP, a
Content-Typeheader that is not a parseable media type is answered with HTTP415and a JSON-RPC-32000error instead of406. On/api/v2it keeps its406, now with a{"errors": "..."}body. AnAcceptheader that cannot be parsed keeps its406on both, with the same JSON error bodies. No response echoes the header.
- Every MCP read tool’s
outputSchemanow describes the fields of the objects and list items it returns, with their types and nullability, instead of a bareobjector an untypedarray. The payloads are unchanged. A client that validatesstructuredContentnow checks each field. No property was maderequiredand no enum values are pinned, so a field added to a payload later still validates. - MCP
getWebhookSubscriptions: the top-levelnextCursorandhasNextPageare now markeddeprecatedin the tool’soutputSchema. They were deprecated copies ofpageInfo.endCursorandpageInfo.hasNextPagealready and are still returned. ReadpageInfoinstead. - MCP
searchItems,getSocialProfilesandsearchCreators: apresetIdof the wrong view type now gets an error that says which view to pass and which tool lists its ids (for example “presetId is not a Social Profile View; pass a Social Profile View id (from getSocialProfileViews).”), instead of naming internal accessor values. The GraphQLitems,socialProfilesandcreatorserrors are unchanged. - The MCP
getOperationdescription now says that a label operation (delete_label,rename_label,merge_labels) reportssucceededCount,failedCountandpendingCountas 0. Readstatus,totalandprocessedfor its progress.
2026-10-22
- New
setCreatorCustomAttributesandclearCreatorCustomAttributemutations, with matching MCP tools, write one creator custom attribute value back from your CRM. The value is checked against the key’s schema incustomAttributeSchemas; a select takes an option id or an exact option name. - Up to 40 creators are written in the request. Up to 1,000 run as one background operation to
poll with
operation(id:). An unknown creator id refuses the whole call;labelsstays on the label mutations.
SocialProfilegains the vetting fields the Archive app shows for a profile. All are nullable and additive.biography: the profile’s biography text.accountType: aSocialProfileCategory, the app’s “Profile type”. It covers every platform, unlike the Instagram-onlySocialProfileAccountType.location: where the account holder is based, as canonical names that matchLocationCanonicalInput.stats: aSocialProfileStatsobject with item counts per platform and format. It also holds last-month engagement totals, averages and rates, and earned media value in cents. It isnullwhen Archive holds no content for the profile.
- The
getSocialProfilesMCP tool returnsbiography,accountTypeandlocationin its detailed response. The newincludeStatsinput adds a shortstatssummary per profile. It is off by default and adds 5 per profile to the call cost.
creatorsgainsfilter.accountNames, a list of social handles. A bare handle matches every platform;tiktok:handlematches one platform.creatorsalso takes an optionalsortingwith one entry:CREATED_ATorFULL_NAME,ASCorDESC. An inlinesortingwins over apresetIdview’s stored sort. The MCPsearchCreatorstool accepts the samefilter.accountNamesandsorting.- A
LocationCanonicalInputentry may name a region group withgroupinstead of country, region or city. It then matches every member country. This applies tocreatorsfilter.locationsand toitemsfilter.creatorLocationsandfilter.ugcLocations. The matching MCP tool arguments accept it too. - New query
locationGroupslists region group codes with their names and member countries (cost 1). MCP tool:getLocationGroups. - New public types:
CreatorSortKey,CreatorSortingInput,LocationGroup.
socialProfilesnow filters inline by everything the Social Profiles page filters by.SocialProfileFilterInputaddsaccountNames,creatorIds,followersCount,engagement,verified,takenAtandpostingActivity(new enumFilterPostingActivity). It also addsitemTypes,contentTypes,tagsNameswithtagsNamesOperator, andsourcesIdswithsourcesIdsOperator.socialProfilestakescustomAttributeConditionslikecreatorsdoes. A combination the search cannot honor returnsINVALID_INPUT. The MCPgetSocialProfilestool takes the samefilterkeys andcustomAttributeConditions.
importCreatorstakes an optionalcustomAttributesobject per creator. Its keys are creator custom attribute keys, and it is shaped likeCreator.customAttributes. The import sets those values on the imported creator.- An unknown key, or a value that does not fit its schema, is a
userErrorsentry. The entry’s path is["creators", "<index>", "customAttributes", "<key>"]. - The MCP
importCreatorstool accepts the same field. See Creator import.
- New query
campaignCreatorspages one campaign’s roster. EachCampaignCreatornode carries thecreator,addedAtand the campaign-specificcustomAttributes, such as gifting, shipping or contract status. Filter the roster withcustomAttributeConditionsand sort it byADDED_AT. Conditions also acceptlabels,creator_nameandposting_activity, one condition each.post_dateandcollectionsare refused withUNSUPPORTED_CUSTOM_ATTRIBUTE_CONDITION. Offset paging can skip or repeat rows that change between pages. An unknown campaign ID, or one from another workspace, returns aNOT_FOUNDerror. The newgetCampaignCreatorsMCP tool wraps it. CustomAttributeSchemaEntitygainsCAMPAIGN_CREATOR. CallcustomAttributeSchemas(entity: CAMPAIGN_CREATOR), orgetCustomAttributeSchemasin MCP, to list the campaign-specific keys.
deleteCampaigndeletes a campaign exactly as deleting it in the app does. It returns{ deletedCampaignId, userErrors }.- It reaches the same campaigns
updateCampaigndoes: those whosecampaignTypeis not null. Any other id, or a repeat delete, is anot_founduserError on["input","id"]. - The roster and posts list go with the campaign; creators and items survive. Deleting a
CREATOR_MONITORINGcampaign with emptytagNamesnarrows back the creator tracking it widened. - The matching
deleteCampaignMCP tool is listed for write-capable callers. Pricing: the mutation is a write costing 50.
- New
createCustomAttributeSchemamutation and MCP tool create a creator custom attribute field in your workspace. The key is derived from the name. Only value types and theSINGLE_SELECT_V3/MULTIPLE_SELECT_V2selects can be created; other types are a userError ontype. - New
addCustomAttributeOptionsmutation and MCP tool add options to a creator select field. Names the field already has come back inskippedNames, so a repeat call adds nothing. - Names must be unique among creator fields, ignoring case. Built-in names such as
Labelsare refused; labels keep their own mutations. A workspace holds at most 250 creator fields besides the built-in ones, and a field at most 500 options.
createCampaignnow creates Vetting Workflow campaigns withcampaignType: VETTING_WORKFLOW, a newCampaignTypevalue. It needsdateStartanddateEnd. Archive pulls each rostered creator’s posts in that window and runs AI brand safety review on them.dateEndmay not be more than 24 hours from now. The app ends the window at the end of today in the user’s timezone, because a creator’s posts are pulled once, when they are added. A workspace whose Archive app does not list Vetting Workflow campaigns gets a userError on["input","campaignType"].- New
settings.vettingWorkflowinput (VettingWorkflowSettingsInput) takes two members.maxMediaItemsPerCreatoris 1 to 1000000 and defaults to 5000.excludeCreatorsInOtherVettingCampaignsdefaults totrue. An out-of-range limit is a userError on["input","settings","vettingWorkflow","maxMediaItemsPerCreator"]. AnexternalIdreplay must repeat both values. updateCampaignrenames these campaigns and changes their roster (INSTAGRAMandTIKTOKprofiles). It also movesdateEnd, again no more than 24 hours from now.- New
CampaignfieldsmaxMediaItemsPerCreatorandexcludeCreatorsInOtherVettingCampaignsread the stored settings back. Both arenullon other types. - Existing Vetting Workflow campaigns now appear in
campaigns,campaign(id:)and the MCPgetCampaignsandgetCampaigntools. This includes campaigns built in the app. They appear in their created-at place, andtotalCountrises to count them. This holds in workspaces whose Archive app lists Vetting Workflow campaigns. Elsewhere they stay out of every read. - MCP
createCampaigntakes and returns the new members, andgetCampaignreturns them. MCPupdateCampaignaccepts Vetting Workflow campaigns, and its output is unchanged. Clients that switch overCampaignTypemust still handle values they do not know.
- New mutation
requestUsageRights(itemIds, requestType, message)and MCP write toolrequestUsageRights. They ask creators for usage rights, a Partnership Ad Code or a Spark Code. Each item joins the workspace’s UGC Repurpose campaign with statusIN_QUEUE. Up to 100 items per call. Send each request from the Manage Rights page; the API returns neither the message nor its link. - Skipped items come back in
skippedItemIds, as passed. These are items outside the workspace, items not from Instagram or TikTok, and items that already have a request. Items past the campaign item or creator limit are skipped too. - New enum
UsageRightsRequestType:USAGE_RIGHTS,WHITELISTING,USAGE_RIGHTS_AND_WHITELISTING.
- New field
CompetitorBrand.previousPeriodoncompetitorBrandsandcompetitorBrand. It returns the same six metrics for the window before the requested one, with that window’sfromandto. Use it for period-over-period change. It is null when that window lies entirely before Competitor Insights data. A window that starts earlier is cut to start on that date, so read itsfrom. - New field
CompetitorBrand.provenance: for each metric, the captured value, the reported total and the estimated amounts in it. Each estimate names its method,STORY_MEDIAN_MULTIPLIERorIGM1_POST_MULTIPLIER. Totals that include estimates can now be told apart from captured values.previousPeriod.provenancegives the same breakdown for the previous window. - New argument
postDateoncompetitorBrandsandcompetitorBrand: an explicit window in whole UTC days, at most 3 months, through the latest settled day (currently today minus 8 days). Workspace Early access does not extend this default. It replacesperiodanddate. Passing either of them with it, or a window outside the bounds, returns anINVALID_INPUTerror; windows are rejected, not shortened. Post listings retain their existing day-9 rule. - New optional argument
includeProvisionalDays: Boolean = falseon both aggregate queries, available without an alpha header. PasstruewithpostDateto acknowledge that engagement figures may still grow and use the workspace’s latest selectable day. This does not grant Early access; omitted,nullorfalseretains the settled ceiling. PassingtruewithoutpostDate, or dates beyond the workspace’s ceiling, returnsINVALID_INPUT. - The
brandIddescription ofcompetitorBrandItemsnow says that the own-brand entry has no competitor posts, so its id returns an empty connection. Useitemsfor the workspace’s own posts. - These fields add no rate-limit cost. They come from the same metrics read as the existing metric fields.
Itemgains the values the Archive app’s Content library shows, so a list render needs no second call. New fields:createdAt(when Archive ingested the item) andsourceIds(the IDsItemFilterInput.sourcesIdstakes).sentimentis anItemSentiment.usageRightsreturns a connection ofItemUsageRights, newest request first, with status and scopes. The status shares its values withFilterContractStatus.- New fields also include
products(ItemProduct) andcustomProduct(ItemCustomProduct).coAuthorslists the other profiles on a collaborative post.thumbnailUrlis the first available media-content preview. productsandusageRightsacceptfirst(default 20, maximum 100) andafter. Selectnodes,edges, andpageInfoto traverse them;totalCountis computed only when requested. Products are ordered by product ID.customProductremains a separate single-record lookup.- All are additive; see rate limits for their weights.
ItemFilterInputgainstagsNamesOperatorandsourcesIdsOperator, each aFilterOperator. Values:CONTAINS(the default),CONTAINS_ALL,DOES_NOT_CONTAIN,IS_EMPTYorIS_NOT_EMPTY. Any other value is refused withINVALID_INPUT.ItemFilterInputalso gainsexcludeCollectionsIds, which drops items in any of the given Collections.creatorIdskeeps items by any of the given creators.- They apply to
items,createContentViewandupdateContentView. A content view’s storedfiltershold them astags_names_operator,sources_ids_operator,exclude_collections_idsandcreator_ids. The MCPsearchItems,createContentViewandupdateContentViewtools take them too.
updateCampaigntakes an optionalsettingsinput of the newCampaignSettingsPatchInputtype. On aCREATOR_MONITORINGcampaign,settings.creatorMonitoringchangestagNamesandpullLogic. Only the fields you send change; an omitted field keeps its stored value.tagNames: []clears the list. Content conditions set in the Archive app are kept.CreatorMonitoringSettingsInputgainspullLogic(HAS_ANY, the default, orHAS_ALL) oncreateCampaign. AcreateCampaignretry with a differentpullLogicis auserErroron that field.Campaign.pullLogicreads the stored value back next toCampaign.tagNames. It is null for other campaign types. ThegetCampaign,createCampaignandupdateCampaignMCP tools return both fields, andupdateCampaignacceptssettings.
campaignstakes an optionalfilter: CampaignFilterInputwithcampaignTypes,externalIdsandnameContains. Members AND together, andtotalCountcounts the matches.nameContainsignores case.updateCampaigntakescreators.addCreatorIds: creators already in the workspace join the roster during the call. A refused id is reported at its own index path, and the rest still apply.- The
getCampaignsMCP tool takes the samefilter, and each node now carriescampaignTypeandexternalId. The two new fields raise agetCampaignscall’s cost by 2. It goes from 14 to 16 at limit 20, and from 18 to 20 at limit 100. - The
updateCampaignMCP tool takescreators.addCreatorIds.
- New query
webhookLimitsreturns the workspace’s webhook caps and usage (cost 1). Fields:tier,maxSubscriptions,usedSubscriptions,maxViewsPerSubscription,metadataMaxBytesandcapsSource.capsSourceisplan,workspace_overrideororg_override. - Read it before
createWebhookSubscriptionorupdateWebhookSubscriptioninstead of hitting a cap’s limituserError. MCP tool:getWebhookLimits. - New public type:
WebhookLimits.
- New field
Creator.activity(first, after): the creator’s activity history, newest first. It is the same history the creator drawer shows in the app. EachActivityLogEntrycarriesoccurredAt, anaction, theactorTypeandactorName, the changedfieldwitholdValueandnewValue, and a readablesummary. Pages hold up to 100 entries, 20 by default. The field costs 5, plus 5 fortotalCount. - The MCP
getCreatortool acceptsincludeActivityandactivityCursorand then returns the activity history, 20 entries per call. Its output is unchanged whenincludeActivityis off.
socialProfiles(and thegetSocialProfilesMCP tool) now pages by a seek cursor under the default sort, so a deep page costs about the same as the first one instead of growing with its depth.afterstays opaque: pass the previous page’sendCursoras before.endCursorvalues issued before this change are still accepted; the page they return carries a new cursor, so a walk in progress continues without restarting.- A view (
presetId) whose stored sort is not the default keeps the previous paging behavior. A cursor issued under the default sort is refused withInvalid cursor(INVALID_INPUT) when it is replayed under such a view.
- A
WORKSPACE-IDheader that isn’t a UUID, such as a numeric workspace ID, now returns HTTP404with{"errors":"WORKSPACE-ID must be the workspace UUID shown in the app's API settings; numeric workspace ids are not accepted"}instead of{"errors":"Shop not found"}. The status and body shape are unchanged. An unknown or inaccessible workspace UUID still returnsShop not found, and a missing header still returns400. See Workspaces.
rotateWebhookSubscriptionSecretno longer revokes an earlier secret when you rotate again within 24 hours: every secret retired in the last 24 hours keeps signing deliveries until its own 24-hour window ends, soX-Archive-Signaturecarries onev1=per active secret (current first, then retired secrets newest first). Up to 5 retired secrets can be live at once; a sixth rotation within that window is refused with auserErroronidthat saysRetry after <time>, and nothing is rotated.
- MCP tools now word an argument that has the wrong type or value as
Invalid argument '$.<path>': <reason>, naming the tool argument (for exampleInvalid argument '$.filter.capturedAt.from': must be an ISO-8601 date-time). They used to pass through GraphQL text such asVariable $filter of type … was provided invalid value, which named a variable the caller never sent. The call is still refused the same way; only the message text changes. - MCP argument checks report every failing argument in one response, joined with
;, instead of stopping at the first. createCampaignreturns oneuserErrorper invalidtagNamesentry instead of only the first, and the create-view mutations (for examplecreateContentView) return oneuserErrorper invalid input when several are wrong. The MCP tools return the same errors.- The
getEngagementHistoryMCP tool refuses afilter.capturedAtwindow whosefromis after itsto, with the messagesearchItemsalready uses. It used to return an empty result.engagementHistoryon/api/v2still returns an empty list for a reversed window.
- Stricter input rules: the calls below used to succeed and silently return the wrong result. They now return an error. No field was removed or renamed.
- A location filter whose entries are all blank (
[{}],[{country: ""}]) onitems(creatorLocations,ugcLocations) orcreators(locations) returnsINVALID_INPUTinstead of matching every record. A list that mixes blank and real entries keeps working and ignores the blank ones.searchItemsandsearchCreatorsbehave the same. - An inline custom-attribute condition on
itemsorcreatorswhose type contradicts the workspace’s custom attribute of that name returnsUNSUPPORTED_CUSTOM_ATTRIBUTE_CONDITIONinstead of matching nothing. A key the workspace has no custom attribute for is still searched. createCampaignandupdateCampaignrefuse adateStartordateEndoutside 2000-01-01T00:00:00Z to 2100-01-01T00:00:00Z with auserErroron that field (dateStart must be between 2000-01-01T00:00:00Z and 2100-01-01T00:00:00Z.). Nothing is created or changed.- The
updateCampaignMCP tool no longer listsINTERNALas a provider, since no campaign type accepts it. The GraphQLProviderenum is unchanged. updateWebhookSubscriptiontreats repeatedviewIdsandeventTypesas one entry, ascreateWebhookSubscriptionalready did, so duplicates no longer count against the per-subscription limits.- The
refetchEngagementBulkMCP tool counts and quotes distinctitemIds: a repeated id counts, and is charged, once, and only more than 50 distinct ids needconfirm: true. - Documented, behavior unchanged: a
superSearchwith no non-blanksearchQuery,imageUrl,similarMediaContentIdorfileName(for example{}or{ searchQuery: "" }) is no search, so results are unranked and only the other filters apply.
- MCP rejects a request whose
idisnullwith a-32600Invalid Request error (idnull) instead of answering it. Requests carry a string or number id; a message with noidis still a notification and is acknowledged with202 Accepted. - MCP now enforces the
MCP-Protocol-Versionrequest header on every message exceptinitialize: a value other than2025-03-26,2025-06-18or2026-07-28gets HTTP400with a-32000JSON-RPC error whosedata.supportedlists the accepted versions. An absent or empty header is still read as2025-03-26, andinitializekeeps negotiating from its body, so send theprotocolVersionthe handshake returned on later requests. - MCP
initializewithout aparamsobject returns a-32602Invalid params error. Without a credential it still returns the401OAuth discovery challenge. - A request body over the 2 MB limit on the MCP endpoint is still refused with HTTP
413, now with a JSON-RPC error body (-32000, idnull) instead of{"errors": "..."}./api/v2GraphQL keeps its existing413body.
Workspace.hashtagsno longer lists hashtags whose detection is turned off in the workspace, matching the app; mentions are unchanged.
mediaContentsno longer reports a live post’s media asdeleted: truejust because Archive has not stored its file.deletedis nowtrueonly when the media was removed or its stored file purged. YouTube videos readdeleted: falsewith athumbnailUrl, falling back to the platform’s own poster;fileUrlstaysnullfor YouTube, as before.- Documented, behavior unchanged:
uploadItemFromUrlis not tracked as an operation — it adds nooperationsentry and sends nooperation.completedwebhook; pollitemIdsByUrlwith the same URL. When the post belongs to an account the workspace does not track yet, the import also creates a creator and a social profile for it, as an upload in the Archive app does. The API cannot delete creators.
redeliverWebhookDeliverynow refuses a delivery whose subscription isDISABLED_BY_FAILURES, with auserErrorondeliveryIdasking you to callenableWebhookSubscriptionfirst. Previously the replay went out and, on success, resetconsecutiveFailuresand setlastSuccessAtwhile the subscription stayed disabled. The MCP tool returns the same error.- A delivery that settles
SUCCEEDEDnow hasnextAttemptAt: null. A redelivered delivery used to keep the time its replay was scheduled for.
- New field
CompetitorBrand.ownMetricsHasDataoncompetitorBrandsandcompetitorBrand, also returned by thegetCompetitorBrands/getCompetitorBrandMCP tools. For the own-brand entry it istruewhenownMetricsStatusisAVAILABLEand the window has own-brand data, andfalsewhen it isAVAILABLEbut the window has none, so every metric is null and should be read as missing, not zero. It is null for competitor brands and whenownMetricsStatusisUNAVAILABLE.ownMetricsStatusis unchanged. - New field
CompetitorBrand.displayName: the name the Archive app shows for the brand. It equalsnamefor competitors; for the own-brand entry it is the name of the brand linked as the workspace’s own brand, or"You"when none is linked.namestays"You"for the own entry. Both MCP tools return it. - Unchanged behavior to know:
CompetitorBrandConnection.totalCountcounts competitor brands only and never includes the pinned own-brand entry, so a workspace with no competitors returns one node andtotalCount: 0. The field description now says so.
- The
sortargument of the six create/update Content, Creator and Social Profile View MCP tools now declares its item shape ({ field, direction }); the values they accept are unchanged. - Documentation only: the MCP tool descriptions and the webhooks guide now state the
engagement-history lag after
refetchEngagementBulk, thetypetoitemTypesmapping, the case-sensitivelabelsfilter, thesearchCreatorsindex lag, thatgetSocialProfilefallback hits are not saved to the workspace, the four view-group member kinds, the per-workspace ping throttle, and that a webhook event’spayloadis the envelope’sdatamember.
CollectiongainscustomAttributeOptionId: the id of the option that represents the Collection in the ITEMcollectionscustom attribute (customAttributeSchemas(entity: ITEM)). It differs from the Collectionid; use it as the value of acollectionscustom-attribute condition and to match an item’scustomAttributes.collections. It is null where the workspace stores Collections in the older format. The MCPgetCollectionsandgetCollectiontools return it too.- Renaming a Collection (
updateCollection) now advances itsupdatedAt. createCampaignnow refuses anexternalIdreplay whosedateStart,dateEndorsettings.creatorMonitoring.tagNamesdiffer from the request that created the campaign, with a userError on["input","dateStart"],["input","dateEnd"]or["input","settings","creatorMonitoring","tagNames"]. Such a replay used to return the stored campaign as a success, silently dropping the new values. Onlynamemay still differ. The comparison is with that first request, not the campaign’s current values, so replaying the original input still works afterupdateCampaign; campaigns created before this change replay unchecked. The MCPcreateCampaigntool behaves the same way. This is a one-off exception to the additive-only rule above, recorded as contract exception API-801: to migrate, retry with the identical input, change dates withupdateCampaign, or use a newexternalId; the userError’sfieldnames the input that differs.- New field
Campaign.tagNames: the stored tag list of aCREATOR_MONITORINGcampaign (empty captures every post), null for other types. The MCPcreateCampaignandgetCampaigntools return it. deepResearchReportscursors are now bound to the workspace andfilterthat issued them. A hand-built cursor, or one reused under another workspace or filter, is refused withInvalid cursor(INVALID_INPUT), the message every other connection uses; it previously read “Invalidaftercursor. Pass theendCursorof the previous page.” Cursors issued before this change are refused once: restart pagination withoutafter.- TikTok post URLs now include the creator’s handle:
Item.originalUrlandCompetitorBrandItem.originalUrl(and the matching MCP tool output) readhttps://www.tiktok.com/@<handle>/video/<id>instead ofhttps://www.tiktok.com/@/video/<id>. A post with no known creator keeps the handle-less form, which TikTok redirects.itemIdsByUrlaccepts both forms. createViewGroupandupdateViewGroup(and the matching MCP tools) now refuse a name that differs from an existing view group’s name only by invisible format characters, such as a zero-width space inside the name, with the usualA view group named "…" already exists in this workspace.userError on the name field. Existing names are unchanged, and sending a group’s current name back still keeps it.
2026-10-20
- Deep Research is generally available, with no alpha header:
deepResearchTemplateslists the report templates the workspace can run,deepResearchQuotevalidates a report input and quotes its cost,createDeepResearchReportstarts a report, anddeepResearchReportsanddeepResearchReportread them back, the finished report as Markdown. The five matching MCP tools are listed for every caller;createDeepResearchReportonly for write-capable callers (an OAuth connection needs thewritescope). - Unchanged behavior to know: a workspace whose plan lacks Deep Research is refused with
DEEP_RESEARCH_NOT_AVAILABLEwhen it quotes or creates. Reports spend the workspace’s credits, which are never refunded. The MCPcreateDeepResearchReporttool starts nothing withoutconfirm: trueand returns the quoted cost instead; the GraphQL mutation has no confirm step. - Pricing: each Deep Research query costs 21 points; the mutation is a write costing 50.
- New public types:
DeepResearchTemplate,DeepResearchInputType,DeepResearchSupport,DeepResearchQuote,DeepResearchReportInput,DeepResearchReportPage,DeepResearchReportFilterInput,DeepResearchReportStatus,DeepResearchReportandCreateDeepResearchReportPayload. Nothing existing changed shape. The three Deep Research enums are now under the stability contract. - The
deep_researchalpha key is retired. Clients that still send it are unaffected: unknown keys are ignored, so they see the same surface as clients that do not, and get no error.
2026-10-19
createCampaignnow normalizessettings.creatorMonitoring.tagNamesthe way the app does: entries are trimmed, lowercased, split on whitespace, stripped of trailing commas and deduplicated. An entry that is blank or is not a#hashtag/@mentionis refused as a userError on["input","settings","creatorMonitoring","tagNames","<index>"]and nothing is created. Such values were previously stored but never matched a post. The MCPcreateCampaigntool behaves the same way.
2026-10-18
- Campaign provisioning is generally available without an alpha header: read a
campaign,createCampaignwith a stable external key, andupdateCampaignto change its name, end date, creators or explicitly held posts. BothCREATOR_MONITORINGandCONTENT_CAPTUREare public. - Matching MCP tools
getCampaign,createCampaignandupdateCampaignare available by default under existing workspace and write permissions. Valid update entries can apply alongsideuserErrors; inspect returned state before retrying. Creator additions remain asynchronous andupdateCampaigndoes not promise blind-retry safety. - The
campaign_provisioningalpha key is retired. Sending it remains harmless; the same public surface is available without it. Supplied UTC timestamps retain existing whole-second precision.
2026-10-17
renameLabelis generally available, with no alpha header, and the newmergeLabelsfolds one label into another existing label: every creator carrying the source ends up on the target, and the source is deleted. Both run in the background and return a pollableoperationId; merging is irreversible. The matchingrenameLabelandmergeLabelsMCP tools are listed for every write-capable caller. See Labels.- Both work in every workspace. The
["base"]refusal “Label management is not enabled for this workspace; contact support.” is gone. - New public types:
RenameLabelPayloadandMergeLabelsPayload. Nothing existing changed shape. - The
labelsalpha key is retired. Clients that still send it see the same surface as clients that do not, and get no error. - Pricing: each call is a write costing 50 points plus the payload fields you select, like any other mutation. Neither draws from the label-write limit.
2026-10-16
- Creator labels are generally available, with no alpha header. The
labelsquery lists the workspace’s labels;createLabels,addLabelsToCreators,removeLabelsFromCreators,bulkAddLabelsToCreators,bulkRemoveLabelsFromCreatorsanddeleteLabelchange them, and the seven matching MCP tools (getLabels,createLabels,addLabelsToCreators,removeLabelsFromCreators,bulkAddLabelsToCreators,bulkRemoveLabelsFromCreators,deleteLabel) are listed for every caller. See the new Labels guide. - Label assignment is priced per creator.
addLabelsToCreatorsandremoveLabelsFromCreatorstake at most 40 creators and cost 50 points plus 100 for each further creator; they also share a per-workspace label-write limit of 40 creators at once, then one more every 2 seconds, answered with HTTP 429 when exceeded. A call your plan can never afford is auserErrorsentry naming the largest call that fits. For more creators,bulkAddLabelsToCreatorsandbulkRemoveLabelsFromCreatorstake up to 1,000 creators, run as a background operation and cost a flat 250 points, with at most 2 in flight per workspace. The rate-limit calculator prices all four. - Renaming a label stays an alpha feature until label management is
enabled for workspaces:
renameLabeland its MCP tool need thelabelskey inX-Archive-Alpha-Features. - New public types:
Labeland the six mutation payloads (AddLabelsToCreatorsPayload,RemoveLabelsFromCreatorsPayload,BulkAddLabelsToCreatorsPayload,BulkRemoveLabelsFromCreatorsPayload,CreateLabelsPayload,DeleteLabelPayload). - Heads-up: an unfiltered
operationsquery, and the MCPgetOperationstool, now also return the workspace’s label operations (operationTypedelete_label,rename_labelandmerge_labels) and its bulk label edits (operationTypeupdate_custom_attributesorremove_custom_attributes), including ones started in the app. If your client assumed every listed operation is arefetch_engagementor a creator import, checkoperationType. - Label operations and bulk label edits send no
operation.completedwebhook; follow them withoperation(id:)or thelabelsquery. - Clients that send
labelsinX-Archive-Alpha-Featuressee the same GA surface plusrenameLabel.
2026-10-15
- Creator import is generally available. The
importCreatorsmutation and theimportCreatorsMCP tool import creators into a workspace by social handle, with no alpha header. See the new Importing creators guide. - New public fields for following an import:
Operation.failedRecordsCsvUrl,Operation.successfulRecordsCsvUrlandOperation.importSource, andOperationRecord.handles,OperationRecord.creatorId,OperationRecord.errorCodeandOperationRecord.errorMessage. They are null for every operation that is not a creator import. TheCreatorImportInput,CreatorImportHandleInput,CreatorImportHandle,CreatorImportProvider,CreatorImportSkipReason,CreatorImportSourceandImportCreatorsSkippedRowtypes are public too. - Heads-up: an unfiltered
operationsquery, and the MCPgetOperationstool, now also return the workspace’s creator imports (operationTypeoneschema_creator_import), including imports started in the app. If your client assumed every listed operation is arefetch_engagement, checkoperationType. - MCP
getOperationandgetOperationRecordsnow always return the creator-import fields (null for other operation types), so each call’s weighted rate-limit cost rises by the few points those fields add. - Clients that still send
creator_importinX-Archive-Alpha-Featuresare unaffected; the key is ignored. - Requests the server can never answer no longer report
extensions.code: "INTERNAL_SERVER_ERROR", which told clients to retry them. They now carry a client-error code:BAD_REQUEST(noquery, a batched array, an unknown or ambiguousoperationName),PERSISTED_QUERY_NOT_SUPPORTED,GRAPHQL_PARSE_FAILED(syntax errors, which previously had no code at all),GRAPHQL_VALIDATION_FAILED(query depth),INVALID_INPUT(variable values,firstout of range, invalid cursors, conflicting arguments) andNOT_FOUND.creator(id:)with an unknown id now reportsNOT_FOUND“Creator not found” instead of a non-null violation. HTTP statuses and messages of these GraphQL errors are unchanged except where noted in the Errors guide. - A string argument containing the NUL character (U+0000), whether inline, in a variable or
anywhere inside an input object, list or
JSONvalue, is now refused before execution with oneINVALID_INPUTerror naming where it sits (for example`$filter.tagsNames[0]`). Some such requests used to fail withINTERNAL_SERVER_ERROR, others ran as if nothing matched. A NUL in a field skipped with@skip/@includeis refused too, and a refused request pays only the per-request minimum. MCP tools answerInvalid argument '$.<path>': must not contain the NUL character (U+0000). - A body that is not valid UTF-8 JSON now gets
400with a JSON body instead of an empty HTML page, andGET,PUT,PATCHorDELETEon/api/v2gets405with anAllow: POSTheader and a JSON body instead of404. On/api/v2/mcp, the same body gets JSON-RPC-32700, a405carries a JSON-RPC error body, and a batch array names why it is rejected. refetchEngagementBulkreports its item-count limit onuserErrors[].field: ["itemIds"], and credit refusals with an emptyfield: [], instead of the placeholder["base"].- Webhook deliveries awaiting a scheduled retry (
status: FAILEDwithnextAttemptAtset) are now retried automatically oncenextAttemptAtpasses; previously such rows were never re-attempted. See retries. sendWebhookTestEventpings now carry the event typesubscription.ping(envelope,X-Archive-Event-Typeheader andwebhookEvents). A ping is a single attempt, never affects the subscription’s health counters or auto-disable, and is sent even while its endpoint host is paused after repeated transport failures.redeliverWebhookDeliverynow replays only a terminalFAILEDdelivery (nextAttemptAt: null) and never asubscription.pingdelivery; anything else returns anot_replayableuserError.enableWebhookSubscription’s 24-hour replay follows the same rule and keeps each replayed delivery’slastError/lastResponseStatusuntil the replay settles.createWebhookSubscriptionandupdateWebhookSubscriptionnow refuse ametadatavalue that is not a JSON object (includingfalse), and report input errors on the paths["input","name"],["input","eventTypes"]and["input","metadata"].- Webhook subscription
nameis limited to 200 characters andurlto 2048 characters. responseTimeMsis now recorded for non-2xx responses too, not only for successful deliveries.- Webhook endpoints are checked against more private and reserved address ranges: an address under
the local-use NAT64 prefix
64:ff9b:1::/48is judged by the IPv4 address it embeds, and Teredo (2001::/32) addresses are refused. - MCP
getWebhookSubscriptionsacceptscursorfor pagination (afterkeeps working as a deprecated alias), andredeliverWebhookDeliverynow advertisesidempotentHint: false. /api/v2accepts theAuthorizationscheme in any case (bearer,BEARER), as HTTP requires. A lowercasebearerpreviously returned 401. Every 401 now carries aWWW-Authenticate: Bearerheader. See authentication.uploadItemFromUrluserErrors for a rejected URL now reportfield: ["input", "url"], the path of the URL in the mutation’s arguments. They previously reported["url"]. The no-user error still reports["shop"].- The MCP
uploadItemFromUrltool now advertisesopenWorldHint: true: the import fetches the URL you pass from outside Archive. GET /oauth/authorizewithout aclient_idorredirect_urinow returns HTTP 400invalid_requestinstead of redirecting to the login page.- Corrected the docs: a mutation costs 50 plus 1 for each payload field it selects, not a flat 50;
RateLimit’stis an absolute Unix timestamp, not the IETF draft’s delta-seconds; schema introspection is disabled in production, so the reference and the Explorer are how you discover the schema. The site now publishes anllms.txtindex of its Markdown pages. See rate limits and alpha features. updateWebhookSubscriptionno longer reports success for an explicitnullit ignored:metadata: nullclears the metadata (as{}does), andnullon any other field returns a userError on that field. ThestatususerError lists the values as the enum spells them (ACTIVE, DISABLED_BY_USER).- MCP
getWebhookSubscriptionsalso returnspageInfo { hasNextPage, endCursor }andtotalCount, like the other list tools. The top-levelhasNextPageandnextCursorstay, as deprecated copies. The tool always requeststotalCount, so a default call now costs 20 credits instead of 15. - A bare
OPTIONSrequest to/api/v2or/api/v2/mcpgets405withAllow: POSTinstead of a422. CORS preflights are unchanged.
2026-08-21
- Every docs page now links the terms of service and privacy policy in a footer; previously they were reachable only from the MCP security page.
- This page now states the
/api/v2stability contract explicitly: the GA surface changes additively only, and a breaking change would ship as a new URL version. The GraphQL schema has operated under this rule since launch; MCP tools since their GA on 2026-08-14. It is now written down where partners can cite it. - New Webhooks guide: triggering model, the delivery request and signature verification, retry and auto-disable behavior, testing and monitoring, and per-plan limits. The webhook reference pages are unchanged; this adds the prose walkthrough.
2026-08-14
- MCP
searchItemswithresponseFormat: "concise"now returnscreator { id }on every node. This is the join key for creator-level comparisons, such as matching a campaign roster fromsearchCreatorsagainst that campaign’s posters; matching onaccountNameis unsafe there because a workspace can hold two creator records that share a handle. The added relation raises a concisesearchItemscall’s weighted cost by 8 (a 20-row page goes from 55 to 63) and adds one batched creator lookup (about 17 ms) per request.detailedresponses are unchanged in both respects. See conventions and rate limits.
2026-08-09
- Rate-limit capacity and refill rate now vary by plan instead of being the same for every paying
plan. Read your ceiling from the
RateLimit-Policyheader (qis the capacity,wthe seconds to refill it) rather than assuming the previous flat numbers; for some plans the capacity is now lower. See rate limits. - Rate-limit buckets are per-workspace again. A workspace owned by an organization takes its capacity and refill rate from the organization’s plan but keeps its own balance, so one workspace’s traffic no longer drains its sibling workspaces’ quota. This reverses the organization-pooled buckets introduced on 2026-08-01. See rate limits.
- New:
Item.aiFilterReasonsreturns the explanation an AI Filter produced for each AI-generated custom-attribute value on an item. Every entry pairs to a value: akeyis only returned when the item carries a value for it incustomAttributes.reasonisnullwhen the run recorded no explanation and""when the model produced an empty one. The list is empty, never null, when an item has none. - New:
CustomAttributeSchema.aiGeneratedmarks which attribute keys are generated by an AI Filter, so you can discover which keys carry reasons before requesting them.
2026-08-06
- New: the MCP section documents Archive’s Model Context Protocol server: its read tools, write tools, and the conventions that apply across every tool. Each tool wraps exactly one public root field, and every operation’s reference page now links to the tool that wraps it.
- The seven list fields that return a plain list rather than a connection now return at most 1000 rows. The cap is silent; there is no cursor to continue from. See pagination.
itemIdsByUrlaccepts any public HTTP(S) URL. It returnsINVALID_URLonly for a malformed URL, a non-HTTP scheme, or a private/reserved host. A well-formed public URL with no matching item now returnsNOT_FOUNDrather thanINVALID_URL.- Clarified that a Social Profile View’s and a workspace Creator View’s
filtersblob is stored and echoed back but not applied when reading throughsocialProfiles(presetId:)orcreators(presetId:). This is long-standing behavior, not a change; the documentation was previously wrong. See filtering.
2026-08-02
- MCP requests now charge and refund the same pooled organization bucket as
/api/v2, so routing load through/api/v2/mcpno longer multiplies an organization’s capacity. See rate limits.
2026-08-01
POST /api/v2acceptsvariablesas a JSON-encoded string as well as a JSON object, and honorsoperationName, so a document that defines several operations is usable. A stringvariablespreviously returned a non-JSON error page.- An unhandled resolver error now returns a coded GraphQL error envelope instead of a non-JSON error page. See errors.
- Workspaces owned by the same organization share one rate-limit bucket rather than one bucket each. See rate limits.
- Breaking (MCP only):
tools/listnow requires credentials and answers an unauthenticated call with the same RFC 9728 discovery challenge asinitialize. - MCP tool arguments now enforce the
minimum,maximum, andminLengthbounds thattools/listadvertises for them. - Revoking an MCP connection now revokes its whole refresh-token rotation lineage, so a superseded credential can no longer mint access tokens.
uploadItemFromUrlrejects URLs whose host is a private or reserved address, or that carry no host at all.
2026-07-31
- The weighted cost model is now enforced: a request that exhausts the bucket is rejected with HTTP
429, a
Retry-Afterheader, and aRATE_LIMIT_EXCEEDEDerror. It previously ran in shadow mode and only reported cost in headers. See rate limits.
2026-07-30
aftercursors are bound to the connection that issued them and shape-checked per entity, so a cursor borrowed from another connection fails with the codedInvalid cursorerror rather than an internal error. See pagination.- The payload-heavy MCP read tools accept
responseFormat: "concise" | "detailed".detailedis the default and its shape is unchanged.
2026-07-29
- A query canceled by the database statement timeout now returns a GraphQL error envelope with the
stable
QUERY_TIMEOUTcode instead of a non-JSON error page. See errors. competitorBrandsandcompetitorBrandkeep returning roster data when aggregate metrics are temporarily unavailable, and report the outage as aSERVICE_UNAVAILABLEerror alongside the data. Match onextensions.codeto decide whether to retry;ownMetricsStatus: UNAVAILABLEalone no longer implies a retry will help.- MCP tool responses were trimmed to the fields each tool needs for its stated purpose; 20 tools now return fewer fields.
- MCP honors the
MCP-Protocol-Versionrequest header.
2026-07-28
- A superseded MCP refresh token is now revoked when its successor is used. Superseded refresh
tokens previously stayed valid indefinitely. The OAuth discovery document also advertises the
revocation_endpoint, so clients can log out cleanly.
2026-07-27
refetchEngagementBulkis available to every API-enabled workspace. The separate engagement-refresh feature gate is gone, and itsuserErrorsno longer report “feature not enabled”. The mutation is still credit-gated.- MCP answers the
pingmethod with the protocol’s empty result instead of-32601 Method not found.
2026-07-26
competitorBrandsnow returns your own brand as one additional pinned node on the first page, namedYouand flagged by the newisOwnBrandfield, so you can compute self-vs-competitor Share of Voice.totalCountstill counts tracked competitors only, so page one returns one more edge than it reports. See pagination.CompetitorBrandgainedearnedMediaValue,engagementsTotal,impressions,influencersCount,postsCount, andreach, plusownMetricsStatus, which is set only on the own-brand entry and distinguishes “computed, no data in window” from “could not be computed”.competitorBrandsandcompetitorBrandacceptperiod(WEEK/MONTH, defaultMONTH) anddateto select the metric window.competitorBrandalso resolves the own-brand entry by its stable ID.
2026-07-25
- Malformed or foreign pagination cursors now fail with a coded
Invalid cursorerror instead of a generic internal error, across every cursor-paginated connection. - Breaking (MCP only): every MCP tool argument is now camelCase (
itemId,presetId,viewIds), matching the GraphQL field names one-to-one. Stored keys inside the opaque saved-viewfiltersblob stay snake_case; clone them verbatim. The/api/v2GraphQL surface is unchanged.
2026-07-24
- MCP responses now carry the same IETF
RateLimitandRateLimit-Policyheaders as/api/v2. See rate limits.
2026-07-23
- Recalibrated the base rate-limit plan to a capacity of 15000 with a refill of 250 per second.
- Published the Archive API documentation site: task-oriented guides plus a schema-driven reference for every query, mutation, and type.
- Documented the generally available surface: bearer-token
authentication, the
WORKSPACE-IDworkspace model, Relay-style pagination, theitemsfiltering and search guide, the rate-limit layers, and the error model.