Skip to content

Admin Ingestion

The admin app exposes a set of Sanctum-protected endpoints for external ingestion agents (such as n8n) to submit content payloads and for curators to manage the review workflow.

Auth

Source-management and submission endpoints require a Sanctum service token with the appropriate ability and Spatie permission. For n8n-managed sources provisioned from the admin app, that token is issued per source and injected into the cloned workflow automatically. Review endpoints also work for authenticated curator/admin browser sessions.

Base URLs

EnvironmentBase URL
Localhttps://localhost/admin/api
ProductionTBD

Authentication

Service-account tokens can be created manually by an admin and scoped to the minimum abilities needed. For n8n-managed sources, the app issues a dedicated per-source token, injects it into the cloned workflow, scopes it to that source’s source_url, and revokes it when the source is deleted.

AbilityRequired for
ingestion:viewList sources
ingestion:createSubmit payloads, create sources

Spatie permission checks (ingestion.view, ingestion.create) are enforced server-side in addition to ability checks. A token with the correct ability but belonging to a user without the matching Spatie permission is rejected with 403.

Ingestion Sources

List sources

http
GET /admin/api/ingestion-sources

Requires ingestion:view ability and ingestion.view permission.

Response 200 OK — Laravel paginator envelope with source objects.

Create a source

http
POST /admin/api/ingestion-sources

Requires ingestion:create ability and ingestion.create permission.

Request body

json
{
	"name": "Tourism Board Feed",
	"source_url": "https://example.com/tourism/events",
	"ingestion_type": "api",
	"provider": "example.com",
	"external_source_id": "tourism-board-events",
	"source_priority": 10,
	"is_active": true
}
FieldTypeRequiredNotes
namestringYesHuman-readable source label
source_urlstringYesUnique canonical URL for this feed
ingestion_typestringYesapi | scrape | manual | csv
providerstringNoRequired when external_source_id is given
external_source_idstringNoUnique within the provider
source_priorityintegerNoDefaults to 0
is_activebooleanNoDefaults to false

approval_mode is server-managed — change it through the admin UI.

Response 201 Created{ "data": { ...source } }

Submitting payloads

http
POST /admin/api/ingest/{type}

{type} is event, place, business, cultural, or local.

Requires ingestion:create ability and ingestion.create permission. For source-scoped n8n tokens, every submitted item must use the bound source_url or the request is rejected with 403.

Single item

json
{
	"item": {
		"external_id": "evt-001",
		"source_url": "https://example.com/events",
		"name": "Carnival Street Jump",
		"external_url": "https://example.com/events/evt-001"
	}
}

Batch

json
{
	"items": [
		{
			"external_id": "evt-001",
			"source_url": "https://example.com/events",
			"name": "Carnival Street Jump"
		},
		{
			"external_id": "evt-002",
			"source_url": "https://example.com/events",
			"name": "Beach Lime"
		}
	]
}

Response 202 Accepted

json
{ "data": { "queued": 2, "source_id": null } }

Items are processed asynchronously. Per-item validation, deduplication, staged record creation, and approval-mode handling happen after the response.

Local payloads

local submissions use the same envelope as the other ingestion targets. Payloads can include editorial fields such as local_subtype, dob, dod, known_for, photo_url, tags, and image/gallery URLs. When the raw payload omits local_subtype, the normalizer can infer it from source fields such as person_type, role, occupation, or type and preserve that inferred value through promotion.

Review workflow

Curators review staged items in the Filament admin panel. The same state transitions are available via API:

ActionEndpointRequired status
ApprovePOST /admin/api/ingested-items/{item}/approvepending or processing
RejectPOST /admin/api/ingested-items/{item}/rejectpending or processing
Request changesPOST /admin/api/ingested-items/{item}/request-changespending or processing
RetargetPOST /admin/api/ingested-items/{item}/retargetany non-merged status
Promote to canonPOST /admin/api/ingested-items/{item}/promoteapproved

Retargeting clears stale canonical links, recalculates hash-based duplicate markers for the new target type, and queues the embedding-based duplicate check again.

Promoting an item creates or updates the matching canonical record and marks the ingested item as merged.

Item lifecycle

submitted → processing → pending → approved → merged
                    ↘ rejected

Auto-approval sources skip the pending step:

submitted → processing → approved → merged

Promotion targets

Payload typePromotes to
eventEvent record
placePlace record
businessPlace with place_kind = business
culturalStory record
localLocal record

For cultural payloads, include culture_topic_id, culture_topic_slug, or culture_topic_name so curators can promote the item into the correct story topic.

For local payloads, gallery media is attached to the gallery collection and treated as the canonical primary media collection for import and re-import.

Error reference

StatusMeaning
422Malformed submission or invalid state transition
401Missing or invalid Sanctum token
403Token ability, permission, or source-scoped access denied
404Item not found

Built with VitePress