Create a sync job

post/v1/datasets/{datasetId}/sources/{sourceId}/sync/jobs

Enqueues a sync for the source right now, regardless of its syncPeriod. The request has no body.

The job is created as pending and picked up by a background worker shortly after. Poll Retrieve sync job for progress, or list the source's sync logs once the job reports a logId.

The source must be active. inactive sources are rejected with 409 — update the source first. The response is 200, not 201.

One job at a time

If the source already has a pending or processing job, no new job is created; the response returns that job's jobId and status with existing: true and a message. This is the same rule the scheduler follows, so a manual request never stacks up behind itself.

Job lifecycle

pending → processing → completed or failed.

  • Workers claim the highest-priority, then oldest, pending job and move it to processing, stamping worker.workerId, worker.lockedAt and worker.startedAt.
  • While processing, the worker creates a sync log (status: running), fetches the whole catalogue, then diffs it against the dataset's ingest queue: new products are queued as added, changed products as updated, products missing from the store as archived. Counts describe what was queued for processing, not items that are already searchable.
  • On success the job becomes completed with result.stats, result.completedAt and logId, and the source's sync.previous is set. On any error it becomes failed with result.error and, if a log was started, logId. A job that fails before a log exists (source or dataset gone, dataset archived) has no logId.
  • A processing job whose worker stops heart-beating for 20 minutes is returned to pending and claimed again. retries.count is informational and is not incremented by this.
  • Cancelling a pending job marks it failed with result.error: "Job cancelled by user".
  • completed and failed jobs are deleted 7 days after result.completedAt.
Private keyapi.v1.datasets.sources.syncJobs.createNo demo

Path parameters

2
datasetIdstring (uuid)required

The dataset the source belongs to.

sourceIdstring (uuid)required

The source to sync.

Response

200A job is queued — either newly created, or the one that was already in flight.
successbooleanrequired

Always true on a 2xx response.

jobIdstring (uuid)required

The job to poll.

statusstringrequired

pending for a new job. processing only when an existing in-flight job was returned.

One ofpendingprocessing
createdAtstring (date-time)

When the job was created. Only present when a new job was created.

existingboolean

true when an already queued or running job was returned instead of creating a new one. Absent otherwise.

messagestring

A sync job for this source is already queued or in progress. Only present alongside existing: true.

Errors

19

Every error is JSON with a single error string unless noted. Match on the status code; the message is for humans.

404
Data source not found: <sourceId>

No source with that sourceId belongs to the organization that owns the key, or the source belongs to a different datasetId than the path. The message ends with the id you sent.

409
Data source is not active

The source's status is inactive.

curl -X POST "https://stylor.ai/api/v1/datasets/YOUR_DATASET_ID/sources/YOUR_SOURCE_ID/sync/jobs" \
  -H "Authorization: Bearer $STYLOR_API_KEY"
Response · 200
{
  "success": true,
  "jobId": "c2e4a6b8-1d3f-4a5c-9e7b-6d8f0a2c4e6b",
  "status": "pending",
  "createdAt": "2026-09-12T09:39:58.110Z"
}