Skip to main content

Task Lifecycle

Every WorkFunder task follows a well-defined state machine from creation through completion (or cancellation). Understanding this lifecycle is essential for building reliable integrations.

State Machine Diagram

                         ┌──────────┐
│ pending │
│(created) │
└────┬─────┘

┌────────────┼────────────┐
│ payment │ │ payment failed
│ succeeded │ │ or cancel
▼ │ ▼
┌──────────┐ │ ┌───────────┐
│ funded │ │ │ cancelled │
│(escrowed) │ │ └─────┬─────┘
└────┬─────┘ │ │
│ │ ▼
worker │ │ ┌──────────┐
accepts │ │ │ refunded │
▼ │ └──────────┘
┌──────────┐ │
│ assigned │◄────┘
└────┬─────┘

worker │
checks in │

┌─────────────┐
│ in_progress │
└──────┬──────┘

worker │
submits proof │

┌────────────────┐
│proof_submitted │
└───────┬────────┘

┌────────┴────────┐
proof │ │ proof
approved │ rejected
│ │
▼ ▼
┌──────────┐ ┌───────────────┐
│completed │ │proof_rejected │──── retry ──▶ in_progress
│ (paid) │ └───────┬───────┘ │
└──────────┘ │ │
max attempts submit proof
exhausted │ │
▼ ▼
┌──────────┐ proof_submitted
│ refunded │
└──────────┘

─── At any point after funding ───

┌──────────┐ Either party can dispute
│ disputed │◄─── (within allowed window)
└────┬─────┘

admin resolves

┌────┴──────────────┐
│ │
▼ ▼
refunded completed
(dev wins) (worker wins)

Task States

pending

The task has been created but not yet funded. The developer needs to complete payment via Stripe.

  • Entry: POST /v1/tasks creates a task in this state
  • Duration: Until payment is confirmed or task is cancelled
  • In test mode: Tasks auto-advance to funded

funded

Payment has been confirmed. The budget is held in Stripe escrow. Workers are guaranteed payment if they complete the task correctly.

  • Entry: Stripe payment_intent.succeeded webhook received
  • What happens: Task becomes visible to nearby qualified workers
  • Funds: Held in Stripe escrow -- not yet transferred to anyone

posted

The funded task has been posted to the worker marketplace and is visible to qualified workers in the area.

  • Entry: Automatic after funding (or manual posting step)
  • Visibility: Workers matching the location and skills can see this task
  • Exit: A worker accepts, or the task expires/is cancelled

assigned

A verified worker has accepted the task. The worker is now responsible for completing it.

  • Entry: Worker accepts via the portal
  • Conditions: Worker must have kyc_status: verified and payout_enabled: true
  • Cancellation: Developer can cancel at this stage with a 50% refund (worker is compensated for their time)

in_progress

The worker has checked in at the task location. GPS coordinates confirm they are within 500 meters.

  • Entry: Worker checks in via the portal (GPS validated)
  • Cancellation: Cannot be cancelled by the developer at this stage
  • Duration: Until the worker submits proof

proof_submitted

The worker has submitted proof of completion (photo, video, or signature with GPS coordinates).

  • Entry: Worker uploads proof via the portal
  • Next: Proof enters the review queue for approval or rejection
  • Disputes: Either party can open a dispute from this state

completed

The proof has been approved and the worker payout has been initiated via Stripe Transfer.

  • Entry: Proof is approved
  • Payment: Worker receives worker_payout_cents in their Stripe Express account
  • Platform: platform_fee_cents is captured as the application fee
  • Disputes: Developer can dispute within 48 hours

proof_rejected

The submitted proof was rejected. The worker can resubmit if they have remaining attempts (max 3).

  • Entry: Proof is rejected with a reason
  • Next: Worker resubmits (back to in_progress) or attempts exhausted (to refunded)
  • Worker notification: Rejection reason is sent via email and push notification

cancelled

The task has been cancelled by the developer.

  • Entry: Developer calls POST /v1/tasks/:id/cancel
  • Refund: Depends on when cancelled (see Cancellation Refunds below)
  • Next: Moves to refunded when Stripe processes the refund

expired

The task was posted but no worker accepted it before the deadline.

  • Entry: Automatic when deadline passes without assignment
  • Next: Moves to refunded

disputed

A dispute has been opened by either the developer or the worker.

  • Entry: Either party opens a dispute within the allowed window
  • Evidence: Both parties have 48 hours to submit evidence
  • Resolution: Admin reviews and resolves (see Disputes)

refunded

The developer has been refunded. This is a terminal state.

  • Entry: After cancellation, expiration, exhausted proof attempts, or dispute resolved for developer
  • Terminal: No further transitions possible

Valid Transitions

FromToTriggerWho
pendingfundedPayment confirmedSystem (Stripe webhook)
pendingcancelledDeveloper cancelsDeveloper (API)
fundedpostedTask posted to marketplaceSystem (automatic)
fundedcancelledDeveloper cancelsDeveloper (API)
fundedrefundedDeveloper cancels + refundSystem
postedassignedWorker acceptsWorker (portal)
postedcancelledDeveloper cancelsDeveloper (API)
postedexpiredDeadline passesSystem (automatic)
assignedin_progressWorker checks in (GPS)Worker (portal)
assignedpostedWorker unassignsWorker (portal)
assignedcancelledDeveloper cancels (50% refund)Developer (API)
in_progressproof_submittedWorker submits proofWorker (portal)
in_progresscancelledDeveloper cancelsDeveloper (API)
proof_submittedcompletedProof approvedAdmin / System
proof_submittedproof_rejectedProof rejectedAdmin / System
proof_submitteddisputedDispute openedDeveloper or Worker
completeddisputedDispute opened (within 48h)Developer or Worker
proof_rejectedin_progressWorker retries (attempts remaining)Worker (portal)
proof_rejectedcancelledDeveloper cancelsDeveloper (API)
proof_rejecteddisputedDispute openedDeveloper or Worker
cancelledrefundedRefund processedSystem (Stripe)
expiredrefundedRefund processedSystem (Stripe)
disputedrefundedResolved for developerAdmin
disputedcompletedResolved for workerAdmin

Cancellation Refunds

The refund amount depends on when the task is cancelled:

Cancelled At StatusRefund to DeveloperWorker Compensation
pendingNo charge was madeNone
funded100% refundNone
posted100% refundNone
assigned50% refund50% of budget
in_progressNot cancellable--
warning

When a task in assigned status is cancelled, the worker receives 50% of the budget as compensation for their time. This is clearly communicated in the API response when a task transitions to assigned.

Webhooks for State Changes

Every state transition triggers a webhook event. Subscribe to these events to react to task progress in real time:

State ChangeWebhook Event
-> fundedtask.funded
-> postedtask.posted
-> assignedtask.assigned
-> in_progresstask.started
-> proof_submittedtask.proof_submitted
-> completedtask.completed
-> proof_rejectedtask.proof_rejected
-> cancelledtask.cancelled
-> expiredtask.expired
-> disputedtask.disputed
-> refundedtask.refunded

See Webhook Events for full payload formats.

Polling vs. Webhooks

While you can poll GET /v1/tasks/:id to check task status, webhooks are strongly recommended:

ApproachProsCons
PollingSimple to implementUses API rate limit, delayed updates
WebhooksReal-time, no rate limit impactRequires a public endpoint

For AI agent workflows where maintaining a webhook endpoint is difficult, polling every 30-60 seconds is a reasonable fallback.