Developers
Connect your product: invite people, report outcomes, and hear by webhook which are verified, then paid after the deadline.
Your API key: an owner or a developer creates it in your dashboard, under Integrations. Quickstart
- You invite, or share the join link; people join themselves
POST /api/v1/invitationsinvitation.joined - Your app reports an outcome
POST /api/v1/outcomes - Your organization’s verifier decides, or auto-verify on a trial campaign
outcome.verifiedoutcome.rejected - Your organization pays the person after the deadline
outcome.paid - The person keeps a certificate, checkable once they publish itCertificates
- Read back
GET /api/v1/outcomes/{external_id}GET /api/v1/invitations/{external_id} - Show cards on your pages
POST /api/v1/embed-codes
Report an outcome
POSThttps://Report one when a person finishes. It is kept against their place with a hash of what you sent, and the same external_id twice answers the first reply again. An outcome for someone who has not joined yet is kept as a record. Reporting moves no money: your organization pays each reward from its own account.
curl https://campaign.udao.org/api/v1/outcomes \
-H "Authorization: Bearer camp_sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"campaign_id": "8f2c6a1e-4b7d-4e39-a5c0-3d9e1f6b2a74",
"email": "ada@example.com",
"reference": "course-solidity-101",
"occurred_at": "2026-09-11T14:03:22Z",
"external_id": "your-own-id-8f3a",
"kind": "completed"
}'{
"external_id": "your-own-id-8f3a",
"campaign_id": "8f2c6a1e-4b7d-4e39-a5c0-3d9e1f6b2a74",
"status": "pending",
"reason": "awaiting_review",
"received_at": "2026-09-11T14:03:25Z",
"outcome_url": "https://campaign.udao.org/api/v1/outcomes/your-own-id-8f3a?campaign_id=8f2c6a1e-4b7d-4e39-a5c0-3d9e1f6b2a74"
}Authorization
Every call carries one header, your API key, and nothing else. An owner or a developer creates it, and needs a sign-in from the last 10 minutes. It is shown once; keep it on your server, never in a browser. Your organization keeps at most 10 live.
Authorization: Bearer camp_sk_live_...
An API key for trial campaigns only begins camp_sk_trial_ and writes to trial campaigns alone. Trial campaigns are the test mode: the loop runs whole and every figure comes back with simulated true.
The base address
https://campaign.udao.org
Public reads
- GET/
api/ public/ campaigns/ {id}No API key. It answers a campaign’s public facts: its title, reward, places, dates and who funds it, up to 120 requests a minute from one address. - The certificate readsNo API key either.Certificates
These get the same 404 campaign_not_found:
- a campaign before it goes live or after it is closed or canceled
- an id nobody holds
- while Udao has not approved the organization, any reader but its signed-in members, the people it invited and the people holding a place
Versions and changes
This is version 1, in the path. We only add to it: new endpoints, new optional fields, new fields in answers and webhooks, new reasons and codes. Ignore what you do not know. Anything that would break a client comes as version 2, beside version 1, announced here at least 30 days ahead.
- 2026-10-10Revoking a verified or paid outcome, or inviting, on a real campaign answers 403 power_not_granted unless an owner gave the API key that. Reading a real campaign’s outcome or invitation with an API key for trial campaigns only answers 409 trial_only_credential.
- 2026-10-05Invitations: POST /api/v1/invitations puts one person on a campaign’s list, its read answers invited, joined or removed, and invitation.joined says when they join.
- 2026-10-04The API published as one OpenAPI 3.1 document and a Postman collection. The read no longer lists proof, which it never sent.