Strapi joins the connectors
v2.23.0 adds a Strapi connector that discovers your collections from a URL and a token, ingests many collections through one source, and survives a collection it cannot read.
Vocion can now ingest a Strapi instance. v2.23.0 adds the connector, and — more usefully — a
discovery step: you give the dialog an instance URL and an API token, press Load collections,
and the server asks the instance what is actually there instead of making you recall plural api
ids by heart.
What's new
- The Strapi connector, pulling entries from one or more collections as retrievable
documents. Both response shapes are normalized: Strapi v4's nested
attributesand v5's flat shape withdocumentId, so a source works against either without you declaring which you run. - Collection discovery from the URL + token, with a typed fallback that verifies every name against the live instance.
- A collection that fails does not lose the ones that work.
- Edit and delete a configured source, with a saved edit stopping the running sync and starting a fresh one.
Why we built it
ensureSource keys a knowledge_source row on (orgId, connector slug), which means an org
gets exactly one strapi row — a second Strapi source would resolve straight back to the first.
So collections live in the connector's own config rather than in separate sources. They share one
instance, one token and one vault entry, and externalId is namespaced <collection>:<id> so
entries from different collections cannot collide.
The failure behavior follows from the same reasoning. A collection that errors is reported through
onProgress and the sync moves to the next one, rather than throwing and losing the collections
that succeeded. That also suppresses tombstoning for the run — a collection we could not read is
not one whose documents we can safely call deleted.
How to use it
Add source → Strapi. Enter the instance URL and an API token, then press Load collections.
Behind that button, POST /rpc/connectors/[slug]/inspect (admin-only, persists nothing) calls
inspectStrapiInstance, which tries the content-type list. Where the instance lets an API token
read that list, the dialog renders a tick-list of collections. Most instances keep the catalogue
admin-only — so the typed list stays, and every name you type is checked against the instance:
| Response | What the dialog says |
|---|---|
| 200 | The entry count |
| 404 | "no such collection" |
| 403 | A permissions hint |
| 401 | Token rejected |
There is a subtlety worth naming. A read alone cannot prove the token. A Strapi collection
that the public role can read answers 200 with no credential at all — so a successful check
re-requests the same collection with no Authorization header, and the token only counts as
proven when a private collection answered, or when the catalogue itself came back. Verified
against api-dev.veerio.app, whose events collection is public.
The resulting config is small:
// packages/core/src/libs/sources/strapi.ts
{
baseUrl: z.string().url(),
/** Plural API ids of the collections to sync, e.g. ["events", "venues"]. */
collections: z.array(z.string().min(1)).min(1),
}
The token is stored against the new source right after it is created, so this connector has no separate Connect step — the dialog you just filled in is the whole setup.
Also in this range
The sources surface picked up a batch of fixes alongside the connector: the source-type picker sorts A–Z and is searchable, the token field gets a show/hide toggle, rows carry entry counts, the dialog footer is pinned, the Edit form loads the stored token, a sync started by another tab or by the scheduler shows up where you are looking, a sync that saved nothing fails rather than reporting success, and survivable sync failures are recorded on the checkpoint.
What's next
- Coverage for the live HubSpot CRM tools that shipped in the same range — engagement timelines,
hubspot_contact_emailsandhubspot_company_activity.
Links
- GitHub release: https://github.com/vocion/vocion-core/releases/tag/v2.23.0
- Dashboard surface:
/dashboard/sources - Code:
packages/core/src/libs/sources/strapi.ts - Tests:
packages/core/src/libs/sources/strapi.test.ts