← All posts

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 Teamv2.23.0

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

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:

ResponseWhat the dialog says
200The entry count
404"no such collection"
403A permissions hint
401Token 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