Context
Read, edit, copy, tag, claim, follow, and suggest Context through the HTTP API.
| Route | Use | CLI equivalent |
|---|---|---|
GET /context/objects | Discover 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}/documents | List document attachments for a supported host. | ax context documents |
POST /context/mutations | Edit organization-owned Context. | `ax context edit --file <PATH |
POST /context/{kind}/{id}/copy | Copy an eligible global root into an organization. | ax context copy |
POST /context/match | Find the organization's existing Context for candidate objects. | ax context match |
POST, GET /context/tags | Create, assign, and look up reusable tags on Context objects. | ax context tags |
POST, GET, DELETE /context/links | Add, list, and remove links between two Context objects. | ax context links |
POST /context/claims | Read and manage Context ownership claims. | ax context claim |
GET, POST, DELETE /context/follows | Read, start, or stop your own follow of a shared object. | ax context follow-state, ax context follow, ax context unfollow |
POST /context/suggestions | Read, 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 method | Corresponding REST operation | Request fields |
|---|---|---|
ListContextObjects | GET /context/objects | orgId, scope |
ListContext | GET /context/{kind} | orgId, type, scope, limit, pageToken, filters, archived |
GetContext | GET /context/{kind}/{id} | orgId, type, id, scope |
ListContextDocuments | GET /context/{kind}/{id}/documents | orgId, type, id, scope, limit, pageToken |
EditContext | POST /context/mutations | orgId, action, input |
CopyContext | POST /context/{kind}/{id}/copy | orgId, type, id, requestId |
ManageContextTags | POST /context/tags | orgId, input |
CreateContextLink | POST /context/links | orgId, link |
ListContextLinks | GET /context/links | orgId, source, relationship |
DeleteContextLink | DELETE /context/links | orgId, linkId or link |
MatchContext | POST /context/match | orgId, candidates (each type, name, website, aliases) |
SuggestContext | POST /context/suggestions | orgId, 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"| Field | What it does |
|---|---|
type | Required. companies, products, personas, markets, or use-cases. |
name | The object's name. Matching ignores case, accents, punctuation, and spacing. |
website | A website, page URL, or bare domain. A company matches on its domain; a product matches on its page URL. Ignored for other types. |
aliases | Other 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:
| Field | What it holds |
|---|---|
matches | The 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). |
conflict | true when the candidate's identity is held by more than one object. Reuse the first. |
duplicates | Other live objects with the same identity that research does not reuse, such as a second object created by hand. |
different | Optional 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. |
lookAlikes | Different objects whose names only look similar, each with similarity and reason. They are never matches: ask before treating one as the same object. |
archived | An archived object that held the candidate's identity. Archived objects never match. |
companyHomepage | For a product whose website is the root of an existing company's domain, that company. |
keys | The 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"| Action | Fields | Result |
|---|---|---|
targets | scope | targets: the object types that accept tags. |
list | scope, search, after, limit, includeUsage | tags in name order and next_page_token. |
get | scope, required tagId, includeUsage | tag. |
create | required name, color | tag and created. |
update | required tagId, patch, expectedUpdatedAt | tag. |
delete | required tagId, expectedUsageCount | id and removedAssignments. |
assign | required kind, targetId, tagId | kind, targetId, tagId, created. |
unassign | required kind, targetId, tagId | kind, targetId, tagId, removed. |
usage | required tagId; scope, kind, after, limit | items (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. |
assigned | required kind, targetId; scope | kind, 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:
createreturns the existing tag withcreated: falsewhen the name is already taken, so a retried create never duplicates a tag.assignandunassignreturncreated: falseorremoved: falsewhen the assignment was already in the requested state.updaterequires the tag's currentupdatedAtasexpectedUpdatedAtand returns409when the tag changed since you read it.deleteremoves the tag from every object. Once a tag is in use, send the count fromusageasexpectedUsageCount; a mismatch returns412with the current count so you can confirm again. The count is in the message and indetailsas[{"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.
Context links
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.
| Route | Body or query |
|---|---|
POST /api/v1/context/links | The link: {source, relationship, target}. |
GET /api/v1/context/links | kind with one of id, name or url; optional relationship. |
DELETE /api/v1/context/links | link_id, or a {source, relationship, target} body. |
GET /api/v1/context/links/schema | None. 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"| Action | Required fields | Result |
|---|---|---|
snapshot | kind (a shared Context kind such as products, product-packages, or a legacy alias such as product), targetId | Current editable fields, relationships, revision, and opaque baselineToken. |
submit | Snapshot target and baseRevision, the full baseline snapshot response, proposal, reason, evidence, idempotencyKey | Suggestion 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, idempotencyKey | Suggestion id, status, and version. |
list | None | Your suggestions and nextPageToken. Set pendingOnly to only return pending records and requestKind (suggestion or tag_assignment) to return one kind. |
withdraw | Suggestion id, version | Updated 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.