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.
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
- Authentication -- Learn about API key types, rate limits, and error handling
- Environments -- Understand live vs. test mode
- Tasks API -- Full reference for the Tasks endpoints
- MCP Integration -- Use WorkFunder from Claude Desktop