Skip to main content

Quickstart

Get up and running with WorkFunder in under 5 minutes. By the end of this guide, you will have created your first task and know how to check its status.

1. Create an Account

Sign up for a free WorkFunder developer account at app.workfunder.com/signup. No credit card is required for the free tier (50 tasks/month, 10 API calls/minute).

2. Get Your API Key

After signing up, navigate to Dashboard > API Keys and generate a new key. You will see two options:

  • Live key (wf_live_...) -- Creates real tasks with real charges
  • Test key (wf_test_...) -- Sandbox mode, no real charges

For this quickstart, use a test key so you can experiment freely.

caution

Your API key is shown only once. Copy it immediately and store it securely. If you lose it, you will need to generate a new one.

3. Create Your First Task

Use curl to create a photography task in test mode:

curl -X POST https://api.workfunder.com/v1/tasks \
-H "Authorization: Bearer wf_test_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"title": "Photograph storefront at 123 Main St",
"description": "Take 3 clear photos of the storefront, including the signage, entrance, and full building facade.",
"category": "photography",
"location": {
"address": "123 Main St",
"city": "Brooklyn",
"state": "NY",
"latitude": 40.6782,
"longitude": -73.9442
},
"budget_cents": 5000,
"proof_types": ["photo"]
}'

Response:

{
"id": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
"title": "Photograph storefront at 123 Main St",
"description": "Take 3 clear photos of the storefront, including the signage, entrance, and full building facade.",
"category": "photography",
"status": "pending",
"environment": "test",
"budget_cents": 5000,
"platform_fee_cents": 800,
"worker_payout_cents": 4200,
"priority": "normal",
"location_city": "Brooklyn",
"location_state": "NY",
"location_latitude": 40.6782,
"location_longitude": -73.9442,
"proof_types": ["photo"],
"max_proof_attempts": 3,
"metadata": {},
"created_at": "2026-02-24T12:00:00.000Z",
"updated_at": "2026-02-24T12:00:00.000Z"
}

In test mode, the task is automatically moved to funded status without requiring real payment.

4. Check Task Status

Poll the task to see its current status:

curl https://api.workfunder.com/v1/tasks/a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 \
-H "Authorization: Bearer wf_test_your_api_key_here"

The status field will progress through the task lifecycle:

pending -> funded -> posted -> assigned -> in_progress -> proof_submitted -> completed

5. List Your Tasks

Retrieve all your tasks with optional filtering:

curl "https://api.workfunder.com/v1/tasks?status=funded&limit=10" \
-H "Authorization: Bearer wf_test_your_api_key_here"

Response:

{
"data": [
{
"id": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
"title": "Photograph storefront at 123 Main St",
"status": "funded",
"budget_cents": 5000,
"created_at": "2026-02-24T12:00:00.000Z"
}
],
"meta": {
"total": 1,
"limit": 10,
"offset": 0
}
}

Full Working Example

Here is a complete TypeScript example that creates a task and polls for completion:

const API_KEY = "wf_test_your_api_key_here";
const BASE_URL = "https://api.workfunder.com/v1";

async function createTask() {
const response = await fetch(`${BASE_URL}/tasks`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
title: "Photograph storefront at 123 Main St",
description:
"Take 3 clear photos of the storefront, including the signage, entrance, and full building facade.",
category: "photography",
location: {
address: "123 Main St",
city: "Brooklyn",
state: "NY",
latitude: 40.6782,
longitude: -73.9442,
},
budget_cents: 5000,
proof_types: ["photo"],
}),
});

const task = await response.json();
console.log(`Task created: ${task.id} (status: ${task.status})`);
return task;
}

async function waitForCompletion(taskId: string) {
const terminalStatuses = ["completed", "cancelled", "expired", "refunded"];

while (true) {
const response = await fetch(`${BASE_URL}/tasks/${taskId}`, {
headers: { Authorization: `Bearer ${API_KEY}` },
});

const task = await response.json();
console.log(`Task ${taskId}: ${task.status}`);

if (terminalStatuses.includes(task.status)) {
return task;
}

// Poll every 30 seconds
await new Promise((resolve) => setTimeout(resolve, 30_000));
}
}

async function getProofs(taskId: string) {
const response = await fetch(`${BASE_URL}/tasks/${taskId}/proofs`, {
headers: { Authorization: `Bearer ${API_KEY}` },
});

const proofs = await response.json();
for (const proof of proofs.data) {
console.log(`Proof: ${proof.type} | GPS valid: ${proof.geo_valid}`);
console.log(` Distance from task: ${proof.distance_from_task_meters}m`);
console.log(` URL: ${proof.file_url}`);
}
return proofs;
}

// Run the full flow
async function main() {
const task = await createTask();
const completed = await waitForCompletion(task.id);

if (completed.status === "completed") {
await getProofs(task.id);
}
}

main().catch(console.error);

Next Steps