Context

Read, edit, copy, tag, claim, follow, and suggest Context through the HTTP API.

RouteUseCLI equivalent
GET /context/objectsDiscover Context object types, their filters, and the related objects each embeds.ax context objects
GET /context/{kind}List Context objects of one type as flat rows.ax context list
GET /context/{kind}/{id}Read one Context object with its related objects embedded.ax context get
GET /context/{kind}/{id}/documentsList document attachments for a supported host.ax context documents
POST /context/mutationsEdit organization-owned Context.`ax context edit --file <PATH
POST /context/{kind}/{id}/copyCopy an eligible global root into an organization.ax context copy
POST /context/matchFind the organization's existing Context for candidate objects.ax context match
POST, GET /context/tagsCreate, assign, and look up reusable tags on Context objects.ax context tags
POST, GET, DELETE /context/linksAdd, list, and remove links between two Context objects.ax context links
POST /context/claimsRead and manage Context ownership claims.ax context claim
GET, POST, DELETE /context/followsRead, start, or stop your own follow of a shared object.ax context follow-state, ax context follow, ax context unfollow
POST /context/suggestionsRead, submit, list, or withdraw a reviewed shared Context edit or tag suggestion.`ax context suggest --file <PATH

Every route requires an API key and an organization selected through org_id when the key can access more than one organization. The feature must be enabled for that organization. Read routes accept scope=org (the default) for the selected organization's Context and scope=global for the shared catalog; global scope never grants write access. Discover object types before reading, because the registry defines the filters, ordering, and embedded relationships for each type. Relationship tables such as product-personas are not object types: requesting one returns 400 with the embed that carries its rows.

In the web app, ask the AX chat agent to research Context; see AX agents for how research works and how it updates objects you already have. Conversations are private to the member who started them. The product and company import pages are retired: old product import links permanently redirect to your organization's Products list. Previously saved Context objects, experiments and reports remain available on their own pages and through their existing APIs.

Connect RPC

Connect clients call POST /rpc/axp.v1.AxpContextService/<METHOD> with a Bearer API key, JSON request body, and Connect-Protocol-Version: 1. Request fields use lower camel case and every Context service response wraps the corresponding REST result in {result: ...}.

curl -X POST \
  -H "Authorization: Bearer $AX_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Connect-Protocol-Version: 1" \
  -d '{"orgId":"'$AX_ORG_ID'","scope":"global"}' \
  "https://app.514.ax/rpc/axp.v1.AxpContextService/ListContextObjects"
Connect methodCorresponding REST operationRequest fields
ListContextObjectsGET /context/objectsorgId, scope
ListContextGET /context/{kind}orgId, type, scope, limit, pageToken, filters, archived
GetContextGET /context/{kind}/{id}orgId, type, id, scope
ListContextDocumentsGET /context/{kind}/{id}/documentsorgId, type, id, scope, limit, pageToken
EditContextPOST /context/mutationsorgId, action, input
CopyContextPOST /context/{kind}/{id}/copyorgId, type, id, requestId
ManageContextTagsPOST /context/tagsorgId, input
CreateContextLinkPOST /context/linksorgId, link
ListContextLinksGET /context/linksorgId, source, relationship
DeleteContextLinkDELETE /context/linksorgId, linkId or link
MatchContextPOST /context/matchorgId, candidates (each type, name, website, aliases)
SuggestContextPOST /context/suggestionsorgId, input

type is the Context object type from ListContextObjects, the same value the REST path calls {kind}. scope defaults to org; use global for the shared catalog. filters is a map of the object type's filterColumns to values. archived (exclude, include, or only) selects archived organization roots as described under GET /context/{kind}. Reuse a pageToken only with the same organization, scope, type, filters, archived scope, and ordering.

Claims use the separate axp.v1.AxpContextClaimsService with its single ManageContextClaim method. Its request accepts orgId, action, kind, and id, plus the action-specific claim fields; its response is also {result: ...}. Follows use axp.v1.AxpContextFollowsService with GetContextFollowState, FollowContext, and UnfollowContext; each takes kind, id, and an optional orgId and returns {following: boolean} for the authenticated person only.

GET /api/v1/context/objects

Discover the Context object types for one scope.

curl -H "Authorization: Bearer $AX_API_KEY" \
  "https://app.514.ax/api/v1/context/objects?org_id=$AX_ORG_ID&scope=global"

The response lists each object type's category (root, subobject, document, or tag), filterColumns, sortColumns, summaryColumns, and relationships: the key, object type, cardinality, and shape of every related object that GET /context/{kind}/{id} embeds. Object types that accept tags report taggable: true and a tagFilter describing the filter.tags parameter. Roots are companies, products, use-cases, personas, and agents. The companies root holds Company Context objects: the companies, customers, vendors, and competitors a workspace tracks, shown as Companies in the platform.

GET /api/v1/context/{kind}

List Context objects of one type as flat rows. Organization reads return newest updates first; shared-catalog reads are ordered by id. Use exact filter.<COLUMN>=<VALUE> parameters only for the type's filterColumns. On taggable types, filter.tags=<TAG_UUID>,<TAG_UUID> (up to 20 ids from the same scope) returns objects carrying any of those tags. Archived organization roots are left out; archived=include adds them and archived=only lists archived roots alone (root types, organization scope, without filter.tags or filter.import). Reuse next_page_token with the same organization, scope, type, filters, archived scope, and ordering.

curl -H "Authorization: Bearer $AX_API_KEY" \
  "https://app.514.ax/api/v1/context/product-versions?org_id=$AX_ORG_ID&scope=global&filter.product_id=<PRODUCT_UUID>"

limit defaults to 50 and accepts 1 through 100. The response is {rows, next_page_token}.

GET /api/v1/context/{kind}/{id}

Read one Context object by UUID with its related objects embedded one level deep.

curl -H "Authorization: Bearer $AX_API_KEY" \
  "https://app.514.ax/api/v1/context/products/<CONTEXT_UUID>?org_id=$AX_ORG_ID&scope=org"

The response is the object's row plus one key per relationship from GET /context/objects: an array for many-valued relationships and an object or null for a parent. Items reached through a relationship table carry a link object with the link id and its metadata. Each array holds at most 100 items; truncatedRelationships names any that were cut. With scope=global the related objects come from the shared catalog, and archived shared roots stay readable with their revision, archived_at, and archived_by state. An archived organization root reads the same way, with archived_at and archived_by set and its archived relations left out of the embeds.

GET /api/v1/context/{kind}/{id}/documents

List documents attached to a supported host: companies, products, use-cases, personas, agents, persona-agents, interfaces, capabilities, user-flows, markets, product-packages, product-versions, product-competitors, agent-versions, or models.

curl -H "Authorization: Bearer $AX_API_KEY" \
  "https://app.514.ax/api/v1/context/products/<CONTEXT_UUID>/documents?org_id=$AX_ORG_ID&scope=global"

The response is {rows:[{link,document}], next_page_token}. Attachment pagination is bound to the scope, organization, host type, and host ID.

POST /api/v1/context/mutations

Edit organization-owned Context with an action/input envelope. Global Context is read-only on this route.

curl -X POST \
  -H "Authorization: Bearer $AX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"action":"mutate","input":{"kind":"products","operation":"create","values":{"name":"Product"}}}' \
  "https://app.514.ax/api/v1/context/mutations?org_id=$AX_ORG_ID"

Actions are read, options, preview-delete, mutate, mutate-many, flow-steps, and document upload actions. Objects use create, update, and delete; relationships use attach and detach. models and agent-versions are read-only through this editor. Updates require the current expectedUpdatedAt; deletion requires the token returned by preview-delete.

Use mutate with kind user-flow-steps to create a Step or update its action and expected_result. Use attach and detach on user-flow-step-memberships, user-flow-step-interfaces, and user-flow-step-capabilities to manage its links. The flow-steps input is {id,expectedUpdatedAt,steps:[{id}]}, with the Flow ID and existing Step IDs in the desired order. It changes memberships only: omitting a Step detaches it from that Flow without deleting the Step or overwriting its content.

A tests record carries its definition two ways, and a mutation may send either. definition is the whole object (name, script, description, files). Its scalar members are also accepted as the typed fields definition_name, definition_script, definition_description and definition_files_declared (whether the definition names a files list, even an empty one); definition_extra holds any other members. A typed-only update rewrites just those members and keeps the rest; the files entries stay while definition_files_declared stays true, and definition_files_declared: false removes files and its entries. The ordered files entries are written through definition.files. Typed fields get the same validation as definition. A definition_extra member a typed field supersedes (name, script or description while that field is set, files while a list is declared) is dropped by the database; a string member kept there while its typed field is null, or a files list kept there while none is declared, is refused by name. A request that sends both definition and typed fields is refused unless they agree. Reads return definition whichever way it was written.

Deleting a root (companies, products, use-cases, personas, agents) archives it rather than removing it: preview-delete returns archives: true with no effects and is always allowed, and after the delete the object leaves every list, picker, embedded relationship, and count on this API, the CLI, MCP, and the platform; it no longer counts as tag usage, and a new owned record, link, tag assignment, or experiment association that names it is refused as not found. The object itself stays readable at its own id: GET /context/{kind}/{id} and its /documents return it with archived_at and archived_by set, the platform shows its page marked as archived and read-only, and its existing owned content, links, and experiment associations are kept, so experiments that referenced it keep working. Deleting an owned record or link still removes it, and preview-delete still reports what else that touches.

An org admin can then delete the archived root permanently: preview-delete on an archived root returns archives: false, its effects (delete-owned records that go with it, restrict records that block it) and a token, and a delete mutation with that deletionToken removes it and its owned records. Restricting records, such as a product's interfaces and user flows, are deleted or detached first, which works while their root is archived. User Flows and Steps remain independently editable after a linked Product is archived. flow-steps updates ordered Step memberships using Step UUIDs; it does not write Step content. Permanent deletion still requires an org admin; other members get PermissionDenied.

POST /api/v1/context/{kind}/{id}/copy

Copy a global companies, products, user-flows, user-flow-steps, use-cases, personas, agents, agent-versions, or harness-versions object and its related Context into the selected organization. The response echoes the kind you sent.

curl -X POST \
  -H "Authorization: Bearer $AX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"request_id":"<UUID>"}' \
  "https://app.514.ax/api/v1/context/products/<CONTEXT_UUID>/copy?org_id=$AX_ORG_ID"

Reuse request_id only to retry the same copy.

The copy carries the published tags of the root and every object copied with it. Each shared tag is reused from the organization's library (matched first by the shared tag it was copied from, then by name) or created there with the shared name and color, and the copied objects receive the same assignments. Locally renamed or recolored tags keep their edits, and local tags and assignments are never removed. When a shared tag's name would collide with a different organization tag, the whole copy fails with a failed_precondition error naming both tags; rename or delete one of them and send the request again.

POST /api/v1/context/match

Find the selected organization's existing company, product, persona, market, or use case for each candidate before you research or create one. Send up to 50 candidates; each needs a type and at least one of name, website, or aliases.

curl -X POST \
  -H "Authorization: Bearer $AX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"candidates":[{"type":"companies","name":"MongoDB","website":"mongodb.com"},{"type":"products","name":"MongoDB Atlas"}]}' \
  "https://app.514.ax/api/v1/context/match?org_id=$AX_ORG_ID"
FieldWhat it does
typeRequired. companies, products, personas, markets, or use-cases.
nameThe object's name. Matching ignores case, accents, punctuation, and spacing.
websiteA website, page URL, or bare domain. A company matches on its domain; a product matches on its page URL. Ignored for other types.
aliasesOther names the object goes by. A name and an alias match each other. Companies have no aliases, so a company's aliases only find look-alikes.

The response has one entry in results per candidate, in order:

FieldWhat it holds
matchesThe existing object the candidate resolves to, first: the same object a research save of it would reuse. Any other object holding part of its identity follows. Each has matchedBy (the identity it matched on: url, domain, alias, or name), updatedAt, lastResearchedAt, and coverage counts of the live objects linked to it. pending: true marks an object a research save is writing right now (its name and coverage are null).
conflicttrue when the candidate's identity is held by more than one object. Reuse the first.
duplicatesOther live objects with the same identity that research does not reuse, such as a second object created by hand.
differentOptional list of live rows previously marked Different from this candidate, with id, type, and name. These pairs stay out of lookAlikes. Ask AX in web chat to reconsider an earlier answer; matching itself never changes a decision.
lookAlikesDifferent objects whose names only look similar, each with similarity and reason. They are never matches: ask before treating one as the same object.
archivedAn archived object that held the candidate's identity. Archived objects never match.
companyHomepageFor a product whose website is the root of an existing company's domain, that company.
keysThe candidate's identity keys (type, value), strongest first.

Matching reads only the selected organization's Context and changes nothing.

POST /api/v1/context/tags

Manage tags, the reusable labels members attach to Context objects. Send one command per request. Organization tags and their assignments are yours to edit; the shared library's tags are read-only here (they are administered by Fiveonefour, and shared assignments arrive through suggestions). Every result is JSON; the ManageContextTags Connect method wraps the same result in {result: ...}.

curl -X POST \
  -H "Authorization: Bearer $AX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"action":"create","name":"Launch ready","color":"#0ea5e9"}' \
  "https://app.514.ax/api/v1/context/tags?org_id=$AX_ORG_ID"
ActionFieldsResult
targetsscopetargets: the object types that accept tags.
listscope, search, after, limit, includeUsagetags in name order and next_page_token.
getscope, required tagId, includeUsagetag.
createrequired name, colortag and created.
updaterequired tagId, patch, expectedUpdatedAttag.
deleterequired tagId, expectedUsageCountid and removedAssignments.
assignrequired kind, targetId, tagIdkind, targetId, tagId, created.
unassignrequired kind, targetId, tagIdkind, targetId, tagId, removed.
usagerequired tagId; scope, kind, after, limititems (kind, targetId, name, assignedAt, parentKind, parentId) and next_page_token. parentKind and parentId name the object that owns a nested item, such as the product of an interface, and are null for top-level objects.
assignedrequired kind, targetId; scopekind, targetId, and the tags the object carries from that library.

scope defaults to org; global reads the shared library and is refused with 403 on create, update, delete, assign, and unassign. kind is an object type from targets, such as companies or products. Names are unique per organization ignoring case and surrounding spaces, up to 64 characters. color is #rrggbb or a palette name, and null clears it. limit defaults to 50 and accepts 1 through 100. includeUsage adds a usageCount to each tag.

The commands are safe to retry:

  • create returns the existing tag with created: false when the name is already taken, so a retried create never duplicates a tag.
  • assign and unassign return created: false or removed: false when the assignment was already in the requested state.
  • update requires the tag's current updatedAt as expectedUpdatedAt and returns 409 when the tag changed since you read it.
  • delete removes the tag from every object. Once a tag is in use, send the count from usage as expectedUsageCount; a mismatch returns 412 with the current count so you can confirm again. The count is in the message and in details as [{"type":"axp.v1.ContextTagUsageChanged","value":{"usageCount":N}}], so a client can read it without parsing text.
# Attach a tag to a Company, then list the Companies carrying it.
curl -X POST -H "Authorization: Bearer $AX_API_KEY" -H "Content-Type: application/json" \
  -d '{"action":"assign","kind":"companies","targetId":"<CONTEXT_UUID>","tagId":"<TAG_UUID>"}' \
  "https://app.514.ax/api/v1/context/tags?org_id=$AX_ORG_ID"
curl -H "Authorization: Bearer $AX_API_KEY" \
  "https://app.514.ax/api/v1/context/companies?org_id=$AX_ORG_ID&filter.tags=<TAG_UUID>"

GET /api/v1/context/tags runs the read actions from query parameters: action (targets, list, get, usage, or assigned; default list) plus scope, search, after, limit, kind, tagId, targetId, and includeUsage. Reuse next_page_token only with the same organization, scope, tag, and kind filter.

Invalid input returns 400; an unknown tag or object returns 404; another organization's tag, or a shared-library write, returns 403.

Link two existing organization Context objects, read one object's links, or remove one link. Neither object is ever created or deleted, and no other link changes. Repeating a create or a delete changes nothing.

RouteBody or query
POST /api/v1/context/linksThe link: {source, relationship, target}.
GET /api/v1/context/linkskind with one of id, name or url; optional relationship.
DELETE /api/v1/context/linkslink_id, or a {source, relationship, target} body.
GET /api/v1/context/links/schemaNone. Returns the link request's JSON Schema.

source and target each name one object as {kind, id}, {kind, name} (exact name), an AX page {url} (it carries its own kind), or a company/product website as {kind, url}. relationship is a key of the source type from the links array that GET /context/objects returns for each type. The body is the same as the MCP context_create_link input.

curl -X POST \
  -H "Authorization: Bearer $AX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"source":{"kind":"companies","name":"Acme"},"relationship":"products-offered","target":{"kind":"products","name":"Acme CLI"}}' \
  "https://app.514.ax/api/v1/context/links?org_id=$AX_ORG_ID"

A write answers with status (linked, already_linked, unlinked or not_linked), the relationship, both objects and linkIds. A list answers {status: "listed", source, relationship, links}, each link with linkId, relationship, label and target. A link ID such as company-products:<UUID> names the stored link and is the same from either end. When a name matches several objects, the answer is status: "needs_clarification" with the candidates and nothing changes. Refusals name both objects and the next command, for example ax context links list companies <ID>.

POST /api/v1/context/claims

Read a claim status, submit or verify publisher evidence, issue a DNS challenge, or withdraw a claim. Claims accept companies, products, agents, personas, use-cases, and documents for status. Ownership-changing actions are limited to companies, products, and agents and require an organization admin.

curl -X POST \
  -H "Authorization: Bearer $AX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"action":"status","kind":"products","id":"<CONTEXT_UUID>"}' \
  "https://app.514.ax/api/v1/context/claims?org_id=$AX_ORG_ID"

Context follows

GET /api/v1/context/follows, POST /api/v1/context/follows, and DELETE /api/v1/context/follows read, start, and stop your own follow of a companies, products, use-cases, personas, or agents object. Follows belong to the authenticated person, persist across organization switches, and never list other followers.

scope selects which object the id names. global (the default) is a shared catalog object, which you follow by opting in. org is an object owned by an organization you belong to; every member follows the organization's objects by default, so DELETE opts you out of that object's activity and POST opts you back in. With scope=org, org_id names the owning organization and is required when your key belongs to several; with the global scope it is optional and only selects the organization whose feature rollout applies.

curl -H "Authorization: Bearer $AX_API_KEY" \
  "https://app.514.ax/api/v1/context/follows?kind=products&id=<CONTEXT_UUID>"

curl -X POST \
  -H "Authorization: Bearer $AX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"kind":"products","id":"<CONTEXT_UUID>"}' \
  "https://app.514.ax/api/v1/context/follows"

# Stop following one of your organization's own products.
curl -X DELETE \
  -H "Authorization: Bearer $AX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"kind":"products","id":"<ORG_CONTEXT_UUID>","scope":"org"}' \
  "https://app.514.ax/api/v1/context/follows?org_id=<ORG_ID>"

GET takes kind, id, and scope as query parameters; POST and DELETE take them in the JSON body, with org_id staying in the query string. Each response is {following: boolean}.

POST /api/v1/context/suggestions

Send one suggestion workflow action.

curl -X POST \
  -H "Authorization: Bearer $AX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"action":"list","pendingOnly":true}' \
  "https://app.514.ax/api/v1/context/suggestions?org_id=$AX_ORG_ID"
ActionRequired fieldsResult
snapshotkind (a shared Context kind such as products, product-packages, or a legacy alias such as product), targetIdCurrent editable fields, relationships, revision, and opaque baselineToken.
submitSnapshot target and baseRevision, the full baseline snapshot response, proposal, reason, evidence, idempotencyKeySuggestion id, status, and version.
tags with op: "snapshot"kind (any type from targets, such as companies, products, or agent-models), targetId; optional search, optional tagIds (up to 40)The object's published shared tags, the shared library (libraryTruncated when search would narrow it), and known: the current details of the requested tagIds that still exist, so a revision can tell a retired tag from a live one.
tags with op: "submit"kind, targetId, add and/or remove (shared tag ids), reason, idempotencyKeySuggestion id, status, and version.
listNoneYour suggestions and nextPageToken. Set pendingOnly to only return pending records and requestKind (suggestion or tag_assignment) to return one kind.
withdrawSuggestion id, versionUpdated suggestion id, status, and version.

proposal may contain fields and supported relationships for the target kind. Relationship create entries use a stable clientToken; the server derives the published id. evidence is an array of up to five {url, description} values. idempotencyKey is a UUID; reuse it when retrying the same submission. To replace a pending suggestion, send both replacesRequestId and expectedVersion.

A tag suggestion proposes 1 to 40 changes across add and remove, with no tag in both; every id must exist in the shared library, and you can hold one pending tag suggestion per shared object. Staff review it and publish the result; shared objects never take direct assign calls. A 422 response means the proposal can no longer be published (for example a proposed tag was deleted); withdraw it or submit a replacement.

If the shared record changed after the snapshot, refresh it and submit a new proposal. A 409 response means the submitted version conflicts with the current review state. Invalid input returns 400; an unavailable target or feature returns 404; request limits return 429. The JSON request body is limited to 128 KiB; oversized bodies return 413.