Skip to main content

Creating Missions

This guide covers everything you need to know about creating missions on Horizon Protocol. Missions are the core unit of work coordination in the ecosystem.

Mission Anatomy​

Every mission has these core components:

ComponentDescriptionRequired
TitleBrief description (max 100 chars)Yes
DescriptionDetailed requirementsYes
RewardUSDC amount held in escrowYes
CategoryMission type (delivery, task, etc.)Yes
ExpirationWhen the mission expiresYes
LocationWhere the mission takes placeOptional
GuildAssociated guild (if any)Optional

Creating a Basic Mission​

Using the SDK​

import { MissionFactoryABI, parseUSDC, toBytes32 } from '@horizon-protocol/sdk';

// 1. Approve USDC spending
await walletClient.writeContract({
address: contracts.usdc,
abi: ERC20ABI,
functionName: 'approve',
args: [contracts.missionFactory, parseUSDC('10')],
});

// 2. Create mission
const hash = await walletClient.writeContract({
address: contracts.missionFactory,
abi: MissionFactoryABI,
functionName: 'createMission',
args: [
'Deliver package', // title
'Pick up from store, deliver to park', // description
parseUSDC('10'), // reward (10 USDC)
toBytes32('delivery'), // category
BigInt(Math.floor(Date.now() / 1000) + 86400), // expires in 24h
],
});

await publicClient.waitForTransactionReceipt({ hash });

Using the API​

const mission = await fetch('https://api.horizon.dev/missions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
title: 'Deliver package',
description: 'Pick up from store, deliver to park',
rewardAmount: '10.00',
category: 'delivery',
expiresIn: 86400, // seconds
}),
});

Mission Categories​

Use standardized categories for better discovery:

CategoryUse Case
deliveryPhysical item delivery
errandGeneral errands and tasks
surveyData collection
reviewReviews and feedback
photoPhotography tasks
socialSocial media tasks
customOther tasks

Adding Location​

For location-based missions:

const hash = await walletClient.writeContract({
address: contracts.missionFactory,
abi: MissionFactoryABI,
functionName: 'createMissionWithLocation',
args: [
'Deliver package',
'Pick up from Central Park',
parseUSDC('10'),
toBytes32('delivery'),
BigInt(Math.floor(Date.now() / 1000) + 86400),
{
latitude: 40.7829, // Central Park
longitude: -73.9654,
radius: 100, // meters
},
],
});

Guild Missions​

Create missions associated with a guild:

const hash = await walletClient.writeContract({
address: contracts.missionFactory,
abi: MissionFactoryABI,
functionName: 'createGuildMission',
args: [
'Guild task',
'Complete this task for the guild',
parseUSDC('15'),
toBytes32('task'),
BigInt(Math.floor(Date.now() / 1000) + 86400),
guildAddress, // Guild contract address
],
});

Mission Requirements​

Add eligibility requirements:

// Via API - missions can have requirements
const mission = await fetch('https://api.horizon.dev/missions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
title: 'Premium delivery',
description: 'High-value item delivery',
rewardAmount: '50.00',
category: 'delivery',
expiresIn: 86400,
requirements: {
minXP: 500, // Minimum global XP
minReputation: 80, // Minimum reputation score
guildId: 'guild-123', // Must be guild member
},
}),
});

Best Practices​

Write Clear Descriptions​

Good:

Pick up a medium-sized package from Joe's Coffee (123 Main St)
and deliver to the park entrance at Central Park South.
The package is fragile - handle with care.
Estimated time: 30 minutes.

Bad:

deliver something

Set Appropriate Rewards​

Consider:

  • Task complexity and time required
  • Distance (for location-based missions)
  • Skill requirements
  • Market rates for similar work

Use Realistic Expirations​

Task TypeRecommended Expiration
Quick errands2-4 hours
Same-day delivery8-12 hours
Flexible tasks24-48 hours
Long-term projects1-7 days

Mission Lifecycle​

After creation, your mission follows this lifecycle:

Created → Open → Accepted → Submitted → Completed
↓
Disputed (if needed)

Managing Your Mission​

// Cancel a mission (before acceptance)
await walletClient.writeContract({
address: missionEscrowAddress,
abi: MissionEscrowABI,
functionName: 'cancelMission',
args: [],
});

// Approve completion
await walletClient.writeContract({
address: missionEscrowAddress,
abi: MissionEscrowABI,
functionName: 'approveCompletion',
args: [],
});

// Raise dispute (if unsatisfied)
await walletClient.writeContract({
address: missionEscrowAddress,
abi: MissionEscrowABI,
functionName: 'raiseDispute',
args: [],
});

Monitoring Missions​

Get Mission Status​

const status = await publicClient.readContract({
address: missionEscrowAddress,
abi: MissionEscrowABI,
functionName: 'state',
});

console.log('Mission state:', status); // Open, Accepted, Submitted, etc.

Listen for Events​

import { MissionEscrowABI } from '@horizon-protocol/sdk';

// Watch for mission acceptance
const unwatch = publicClient.watchContractEvent({
address: missionEscrowAddress,
abi: MissionEscrowABI,
eventName: 'MissionAccepted',
onLogs: (logs) => {
console.log('Mission accepted by:', logs[0].args.performer);
},
});

Error Handling​

Common errors and solutions:

ErrorCauseSolution
InsufficientAllowanceUSDC not approvedApprove USDC first
InsufficientBalanceNot enough USDCAdd USDC to wallet
InvalidExpirationExpiration in pastUse future timestamp
MissionAlreadyExistsDuplicate creationCheck for existing mission

API Reference​

Create Mission​

POST /missions

Request Body:

{
"title": "string",
"description": "string",
"rewardAmount": "string",
"category": "string",
"expiresIn": "number",
"location": {
"latitude": "number",
"longitude": "number",
"radius": "number"
},
"guildId": "string",
"requirements": {
"minXP": "number",
"minReputation": "number"
}
}

Get Mission​

GET /missions/:id

Update Mission​

PATCH /missions/:id

Cancel Mission​

POST /missions/:id/cancel

Next Steps​