{"ok":true,"version":"agent-sync-jobs.v1","generatedAt":"2026-05-30T06:52:24.926Z","surface":{"id":"sync-jobs","artistId":"laurel","safeForAgent":true,"browserAutomationRequired":false,"executionRuntimeReady":true,"relatedIssues":[608,610,671,799,1052,1057,1083,1112,1113,1114,1128,1176,1224]},"currentStatus":{"contract":"manual-run-ready","storage":"enabled","scheduler":"manual-run-ready","firstImplementedSurface":"sync-job-stripe-catalog-app-references-0001","lastCheckpoint":{"cursor":"catalog-ref:membership-tier:studio-circle:2026-05-16T07:10:00.000Z","highWatermark":"2026-05-16T07:10:00.000Z","lastSuccessfulAt":"2026-05-16T07:15:00.000Z","recordsProcessed":3,"duplicateRecordsSkipped":1,"digest":"sync-digest-catalog-app-references-0001"},"firstAvailableFeed":"work-log","summary":"This slice defines cursor-based sync jobs, exposes a redacted catalog checkpoint sample, ships the first public cursor feed for work-log upserts, and runs the first authenticated Stripe catalog app-reference drift worker. Arbitrary hosted third-party sync workers are still not enabled."},"endpoints":{"manifest":{"href":"https://docs.fanful.net/api/agent/sync-jobs","method":"GET","auth":"guest","description":"Read this sync-job manifest.","status":"available"},"readJob":{"href":"https://docs.fanful.net/api/agent/sync-jobs?jobId={jobId}","method":"GET","auth":"artist-admin-or-approved-automation","description":"Read one sync job, latest durable run, current cursor, last checkpoint, and redacted error state.","status":"available"},"startRun":{"href":"https://docs.fanful.net/api/agent/sync-jobs","method":"POST","auth":"artist-admin-or-approved-automation","description":"Start the first-party Stripe catalog app-reference drift worker after server-side credential checks.","status":"available"},"readCheckpoint":{"href":"https://docs.fanful.net/api/agent/sync-jobs?jobId={jobId}&checkpoint=latest","method":"GET","auth":"artist-admin-or-approved-automation","description":"Read the last durable checkpoint without provider credentials or raw ids.","status":"available"},"readWorkLogFeed":{"href":"https://docs.fanful.net/api/agent/sync-feeds/work-log?cursor={cursor}","method":"GET","auth":"guest","description":"Read public work-log upsert records after an opaque cursor.","status":"available"}},"syncJobContract":{"contract":"agent-sync-job.v1","requiredFields":["id","status","source","target","cursor","checkpoint","stats","redactions","errors","idempotency"],"statuses":["idle","running","completed","failed","paused","needs-review"],"credentialPolicy":"Credentials are resolved server-side from operator configuration. Agents may request a sync or read status, but never pass provider tokens, raw payment ids, media handles, or database identifiers as prompt-visible input.","reviewPolicy":"A sync job can report drift automatically. Upserting Fanful state requires an explicit action contract, fresh current-state read, idempotency key, and human/creator review when the target is billing, entitlement, media, or creator-facing copy."},"cursorContract":{"contract":"agent-sync-cursor.v1","requiredFields":["kind","value","nextValue","terminal"],"semantics":"Cursors are opaque to clients. They represent a stable source ordering such as updatedAt plus app-reference key. Clients should store and echo only the complete cursor value returned by Fanful.","duplicatePolicy":"A resumed page may overlap the previous page. Targets must use idempotency keys and skip already-processed records instead of replaying writes."},"checkpointContract":{"contract":"agent-sync-checkpoint.v1","requiredFields":["cursor","highWatermark","lastSuccessfulAt","recordsProcessed","duplicateRecordsSkipped","digest"],"retentionPolicy":"Checkpoints should persist after failures so agents can explain what was scanned, where to resume, and which records still need review."},"firstImplementedSync":{"id":"sync-job-stripe-catalog-app-references-0001","source":"Fanful app-state catalog references mirrored by Stripe catalog readiness","status":"idle","lastCheckpoint":{"cursor":"catalog-ref:membership-tier:studio-circle:2026-05-16T07:10:00.000Z","highWatermark":"2026-05-16T07:10:00.000Z","lastSuccessfulAt":"2026-05-16T07:15:00.000Z","recordsProcessed":3,"duplicateRecordsSkipped":1,"digest":"sync-digest-catalog-app-references-0001"},"safeUse":"Use POST /api/agent/sync-jobs to run the authenticated drift worker and GET /api/agent/sync-jobs?jobId=... to read the redacted durable run. It is not authorization to create Stripe objects, remap prices, or update entitlements."},"workflowTriggers":{"catalogDriftDetected":{"type":"creator.catalog.drift.detected","version":"agent-workflow-trigger.catalog-drift.v1","status":"signed-record-ready","triggerManifest":"https://docs.fanful.net/api/agent/workflow-triggers?family=creator.catalog.drift.detected","creatorCommerceManifest":"https://docs.fanful.net/api/agent/creator-commerce","sourceIssue":1128,"linkedSyncIssue":1114,"sourceJobId":"sync-job-stripe-catalog-app-references-0001","checkpointDigest":"sync-digest-catalog-app-references-0001","driftFindings":1,"writeBackPolicy":"Catalog drift triggers are review prompts only. Any provider or Fanful write-back still requires creator approval through the creator-commerce action contract."}},"availableFeeds":[{"id":"work-log","version":"agent-sync-feed.v1","endpoint":{"href":"https://docs.fanful.net/api/agent/sync-feeds/work-log","method":"GET","auth":"guest","description":"Public work-log upsert feed ordered by updatedAt plus id.","status":"available"},"cursorKind":"updated-at-plus-id","recordTypes":["work-log.entry.upsert"],"tombstones":"not-supported-until-delete-events-exist","redactionPolicy":"The work-log table is public by design, but entries must not include secrets, private inbox bodies, raw tokens, hidden admin data, or private user identifiers."}],"checkpointSimulation":{"contract":"agent-sync-checkpoint-simulation.v1","pages":[{"id":"first-page","inputCursor":null,"outputCursor":"catalog-ref:shop-product:signed-score-download:2026-05-16T07:05:00.000Z","records":[{"key":"lesson-offering:intro-guitar-lesson","sourceKind":"lesson-offering","title":"Intro guitar lesson","updatedAt":"2026-05-16T07:00:00.000Z","active":true,"amountCents":7500,"currency":"usd","duplicateOfPreviousPage":false,"modelVisibleReference":"catalog-ref:lesson-offering:intro-guitar-lesson:2026-05-16T07:00:00.000Z","hasStripePrice":true,"redactedStripePriceId":"price_...ntro"},{"key":"shop-product:signed-score-download","sourceKind":"shop-product","title":"Signed score download","updatedAt":"2026-05-16T07:05:00.000Z","active":true,"amountCents":1800,"currency":"usd","duplicateOfPreviousPage":false,"modelVisibleReference":"catalog-ref:shop-product:signed-score-download:2026-05-16T07:05:00.000Z","hasStripePrice":false,"redactedStripePriceId":null}],"checkpointAfter":{"cursor":"catalog-ref:shop-product:signed-score-download:2026-05-16T07:05:00.000Z","highWatermark":"2026-05-16T07:05:00.000Z","recordsProcessed":2,"duplicateRecordsSkipped":0}},{"id":"resume-page-with-overlap","inputCursor":"catalog-ref:shop-product:signed-score-download:2026-05-16T07:05:00.000Z","outputCursor":"catalog-ref:membership-tier:studio-circle:2026-05-16T07:10:00.000Z","records":[{"key":"shop-product:signed-score-download","sourceKind":"shop-product","title":"Signed score download","updatedAt":"2026-05-16T07:05:00.000Z","active":true,"amountCents":1800,"currency":"usd","duplicateOfPreviousPage":true,"modelVisibleReference":"catalog-ref:shop-product:signed-score-download:2026-05-16T07:05:00.000Z","hasStripePrice":false,"redactedStripePriceId":null},{"key":"membership-tier:studio-circle","sourceKind":"membership-tier","title":"Studio Circle","updatedAt":"2026-05-16T07:10:00.000Z","active":true,"amountCents":1200,"currency":"usd","duplicateOfPreviousPage":false,"modelVisibleReference":"catalog-ref:membership-tier:studio-circle:2026-05-16T07:10:00.000Z","hasStripePrice":true,"redactedStripePriceId":"price_...rcle"}],"checkpointAfter":{"cursor":"catalog-ref:membership-tier:studio-circle:2026-05-16T07:10:00.000Z","highWatermark":"2026-05-16T07:10:00.000Z","recordsProcessed":3,"duplicateRecordsSkipped":1}}],"expectedFinalStats":{"recordsScanned":4,"uniqueRecordsProcessed":3,"duplicateRecordsSkipped":1,"driftFindings":1,"errors":0}},"sampleJobs":[{"id":"sync-job-stripe-catalog-app-references-0001","title":"Stripe catalog app-reference snapshot","status":"idle","source":{"id":"fanful-app-state-catalog-references","type":"app-state-snapshot","provider":"stripe-catalog-readiness","endpoint":{"href":"https://docs.fanful.net/api/admin/stripe-catalog","method":"GET","auth":"artist-admin-or-approved-automation","description":"Read server-side catalog readiness and app references through the existing admin endpoint.","status":"available"},"credentials":"server-side-only","modelVisibleIdentifiers":"public-app-reference-keys","records":["lesson_offerings","store_items","membership_tiers"]},"target":{"id":"creator-commerce-catalog-drift-report","resourceUri":"fanful://agent/creator-commerce/manifest","mode":"drift-report-only","writesEnabled":false,"reviewBoundary":"The first sync surface reports catalog drift and checkpoint health only. Price creation, mapping, metadata, or entitlement changes still require action-contract confirmation."},"cursor":{"kind":"opaque-compound","value":"catalog-ref:shop-product:signed-score-download:2026-05-16T07:05:00.000Z","nextValue":"catalog-ref:membership-tier:studio-circle:2026-05-16T07:10:00.000Z","terminal":false},"checkpoint":{"cursor":"catalog-ref:membership-tier:studio-circle:2026-05-16T07:10:00.000Z","highWatermark":"2026-05-16T07:10:00.000Z","lastSuccessfulAt":"2026-05-16T07:15:00.000Z","recordsProcessed":3,"duplicateRecordsSkipped":1,"digest":"sync-digest-catalog-app-references-0001"},"stats":{"recordsScanned":4,"uniqueRecordsProcessed":3,"duplicateRecordsSkipped":1,"driftFindings":1,"errors":0},"idempotency":{"keyFields":["sourceKind","key","updatedAt"],"duplicateBehavior":"Skip duplicate keys that reappear after a cursor resume and count them in duplicateRecordsSkipped."},"errors":[],"redactions":["provider credentials","raw provider ids","payment identifiers","customer identifiers","checkout session identifiers","account emails"]}],"agentClientGuidance":["Read sync status before asking a user to approve provider or catalog changes.","Treat sync output as current-state context, not permission to mutate Fanful.","Store opaque cursors exactly as returned; do not parse or invent cursor values.","Use an idempotency key for every manual run. Replaying the same key returns the existing redacted run record instead of scanning again.","For public changes that need an actual feed today, use GET /api/agent/sync-feeds/work-log and replay by idempotencyKey.","If a sync reports drift, read the target manifest and action contracts before proposing any write."]}