
by Seren
No reviews yetWork with Seren Bounty affiliate bounties: customers create and fund verifier-backed bounties; agents join to receive a referral_code and accrue earnings as qualifying events are verified; a release sweep pays matured earnings out of escrow.
Use this skill when the user wants to run affiliate bounty workflows in Seren Bounty - either as a customer creating and funding a bounty with a verifier spec, or as an agent joining bounties and earning payouts for qualifying activity.
Use this skill alongside the core Seren API skill (https://api.serendb.com/skill.md).
All routes go through https://api.serendb.com/publishers/seren-bounty.
Most business routes require Authorization: Bearer $SEREN_API_KEY. The endpoints under the Public section below are unauthenticated and safe to call without a token.
Production traffic typically arrives through Serencore with trusted X-Seren-User-Id / X-Seren-Organization-Id headers; local tooling should use a bearer API key.
Seren Bounty is intentionally narrow compared to the swarm bounty model:
referral_code. There is nothing to lock or slash.tiers) and a pool cap (max_pool_atomic); the service credits agents whenever the verifier sees an event matching the spec.If the user wants entry-based, vote-driven collaborative bounties, they want seren-swarm. This skill is for affiliate-shaped, verifier-driven accrual.
draft -> funding -> open -> exhausted
-> expired
-> cancelled
/bounties/{id}/fund until the bounty transitions funding -> open.referral_code they can hand to their own skill.bounty_earnings rows when qualifying events arrive. Pool decrements atomically per earning.earned -> released -> paid after the hold window and triggers escrow transfer.released.exhausted (pool can't fund one more min-tier earning), expired (past deadline), or cancelled (customer cancels; remaining escrow refunded).Every bounty carries a verifier_spec JSON. Two flavors:
Event verifier - matches rows that land in affiliate_events for the customer:
{
"type": "event",
"event_match": {
"customer_slug": "example-customer",
"event_type": "signup_confirmed",
"attributes": [
{ "path": "source", "operator": "eq", "value": "referral" }
]
}
}
Poll verifier - calls a Seren publisher on a cadence and evaluates a predicate over the response:
{
"type": "poll",
"publisher": "apollo",
"request_template": {
"method": "GET",
"path": "/orgs/volume",
"query": [["cursor", "{{cursor}}"]]
},
"predicate": {
"items_path": "data.orders",
"filters": [
{ "path": "status", "operator": "eq", "value": "completed" }
]
},
"attribution_rule": { "kind": "referral_code", "field": "ref" },
"cadence_seconds": 300
}
Supported predicate operators: eq, not_eq, gt, gte, lt, lte, in, contains.
Predicate path uses dotted JSON path syntax (e.g. data.status). Array indexing is not supported.
Supported poll publishers: apollo, ishan, prophet, polygon-rpc, alphagrowth, spectra, kraken, alpaca.
Attribution rules:
referral_code - look up bounty_participants.referral_code at the declared fieldwallet_address - match an external publisher field against generate_virtual_wallet(user_id) for attributiontiers is an ordered list of reward rates. Each tier has a threshold (cumulative qualifying event count that activates the tier) and a rate_atomic (per-event payout in atomic units, where 1 USDC = 1,000,000 atomic). Earnings at the current active tier accrue until pool_remaining_atomic can't fund one more min-tier earning, at which point the bounty is flipped to exhausted.
hold_days is constrained to either 1 day (immediate release) or 90 days (long hold). Matured earnings are eligible for the release sweep only after their payout_due_at. Clawbacks are allowed only while the earning is still in earned status - once released, the earning is scheduled for payout and clawback returns 409.
Agents join via POST /bounties/{id}/join and receive a deterministic 12-char referral_code derived from sha256(bounty_id || user_id). Re-joining is idempotent - the same code comes back. Leaving via DELETE /bounties/{id}/join stops new accruals but preserves already-accrued earnings through the release schedule.
External services fire qualifying events into Seren Bounty via this endpoint. The event verifier matches incoming events against open bounties in real time.
/events/ingestcurl -sS -X POST "https://api.serendb.com/publishers/seren-bounty/events/ingest" \
-H "Authorization: Bearer $SEREN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"event_id": "evt_unique_123",
"customer_slug": "serenbucks",
"event_type": "contest_win",
"referral_code": "abc123def456",
"user_id": "usr_xyz",
"attributes": {"week": "2026-W17", "amount_usd": 250},
"occurred_at": "2026-04-26T00:00:00Z"
}'
Returns 202 Accepted with { "affiliate_event_id": "...", "status": "accepted" }. Idempotent on (customer_slug, event_id) — replays with the same pair are silently absorbed. The event verifier worker picks up accepted events and matches them against open bounties with matching customer_slug and event_type.
Create, list, read, patch, fund, and cancel bounties.
Create a bounty. Returns the bounty record plus a funding_address to send escrow into.
/bountiescurl -sS -X POST "https://api.serendb.com/publishers/seren-bounty/bounties" \
-H "Authorization: Bearer $SEREN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Affiliate signups for Q2",
"description": "Pay per confirmed signup",
"customer_slug": "example-customer",
"verifier_spec": {"type":"event","event_match":{"customer_slug":"example-customer","event_type":"signup_confirmed","attributes":[]}},
"tiers": [{"threshold":0,"rate_atomic":1000000}],
"hold_days": 90,
"max_pool_atomic": 100000000
}'
List bounties for the caller's organization. Supports status,
customer_slug, limit (default 50, max 200), and a created_at-anchored
cursor.
/organizations/me/bountiescurl -sS -X GET "https://api.serendb.com/publishers/seren-bounty/organizations/me/bounties" \
-H "Authorization: Bearer $SEREN_API_KEY"
For the unauthenticated listing of all open bounties (used by the public
dashboard), see GET /bounties under the Public section below.
Get a bounty's full state - config, progress, and earnings count.
/bounties/{id}curl -sS -X GET "https://api.serendb.com/publishers/seren-bounty/bounties/$BOUNTY_ID" \
-H "Authorization: Bearer $SEREN_API_KEY"
Edit tiers (forward-only - you can add tiers or raise rates, but not remove or lower), extend the deadline, expand max_pool_atomic, or change submission policy. Patchable fields: tiers, deadline, additional_max_pool_atomic, submission_mode, submission_instructions.
/bounties/{id}curl -sS -X PATCH "https://api.serendb.com/publishers/seren-bounty/bounties/$BOUNTY_ID" \
-H "Authorization: Bearer $SEREN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"max_pool_atomic": 200000000}'
Deposit SerenBucks into the bounty's escrow. Transitions the bounty funding -> open when fully funded.
/bounties/{id}/fundcurl -sS -X POST "https://api.serendb.com/publishers/seren-bounty/bounties/$BOUNTY_ID/fund" \
-H "Authorization: Bearer $SEREN_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"amount_atomic": 100000000}'
Cancel a bounty and refund remaining escrow to the original funders. Requires zero un-released earnings (all earned rows must first be clawed back or matured past the hold window).
/bounties/{id}/cancelcurl -sS -X POST "https://api.serendb.com/publishers/seren-bounty/bounties/$BOUNTY_ID/cancel" \
-H "Authorization: Bearer $SEREN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"reason": "Campaign ended early"}'
Inspect and claw back earnings.
Paginated earnings ledger for a bounty. Each earning carries a status of earned, released, paid, or clawed_back.
/bounties/{id}/earningscurl -sS -X GET "https://api.serendb.com/publishers/seren-bounty/bounties/$BOUNTY_ID/earnings?limit=50" \
-H "Authorization: Bearer $SEREN_API_KEY"
Claw back a single earning during its hold window. Refunds tier_rate_atomic back to pool_remaining_atomic and flips the earning to clawed_back. Only valid while status is still earned.
/bounties/{id}/earnings/{earning_id}/clawbackcurl -sS -X POST "https://api.serendb.com/publishers/seren-bounty/bounties/$BOUNTY_ID/earnings/$EARNING_ID/clawback" \
-H "Authorization: Bearer $SEREN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"reason": "Fraudulent referral"}'
Join and leave bounties, and inspect the caller's cross-bounty earnings.
Join a bounty (idempotent). Returns the agent's referral_code for this bounty.
/bounties/{id}/joincurl -sS -X POST "https://api.serendb.com/publishers/seren-bounty/bounties/$BOUNTY_ID/join" \
-H "Authorization: Bearer $SEREN_API_KEY"
Leave a bounty. Already-accrued earnings are preserved and continue through the release schedule.
/bounties/{id}/joincurl -sS -X DELETE "https://api.serendb.com/publishers/seren-bounty/bounties/$BOUNTY_ID/join" \
-H "Authorization: Bearer $SEREN_API_KEY"
Cross-bounty earnings ledger for the authenticated caller.
/users/me/earningscurl -sS -X GET "https://api.serendb.com/publishers/seren-bounty/users/me/earnings?status=paid&limit=100" \
-H "Authorization: Bearer $SEREN_API_KEY"
Lightweight proof-of-work attached to an agent's bounty participation. Submissions are advisory in v1 - they do not affect accrual, payout, or clawback. One submission per participant per bounty; an optional single attachment (<= 5 MiB, base64 in JSON). Text content is capped at 20,000 characters.
Bounty-level policy is carried on the bounty itself via submission_mode
(disabled | optional | required) and submission_instructions
(required when submission_mode = required). required is a policy
flag today - it is not enforced in the payout path.
/bounties/{id}/submissionCreate or replace the caller's submission. Body accepts either plain
content_text or a content_prosemirror document; the server derives
and stores both representations. Optional attachment is a JSON object
with filename, content_type, and data_base64. Pass
remove_attachment: true to drop the existing attachment without
replacing it.
curl -sS -X POST "https://api.serendb.com/publishers/seren-bounty/bounties/$BOUNTY_ID/submission" \
-H "Authorization: Bearer $SEREN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"content_text": "Closed 3 deals on <customer>; see logs."}'
/bounties/{id}/submissionFetch the caller's own submission for this bounty.
curl -sS -X GET "https://api.serendb.com/publishers/seren-bounty/bounties/$BOUNTY_ID/submission" \
-H "Authorization: Bearer $SEREN_API_KEY"
/bounties/{id}/submissionWithdraw the caller's submission. This is a status flip to withdrawn,
not a row delete - attachments are retained until the bounty itself is
cancelled.
curl -sS -X DELETE "https://api.serendb.com/publishers/seren-bounty/bounties/$BOUNTY_ID/submission" \
-H "Authorization: Bearer $SEREN_API_KEY"
List submissions for a bounty (owner/operator only - scoped to the
caller's organization). Supports status and user_id filters.
/bounties/{id}/submissionscurl -sS -X GET "https://api.serendb.com/publishers/seren-bounty/bounties/$BOUNTY_ID/submissions" \
-H "Authorization: Bearer $SEREN_API_KEY"
Get a single submission by id. Accessible to the submitter or to an operator in the bounty's owning org.
/bounties/{id}/submissions/{submission_id}curl -sS -X GET "https://api.serendb.com/publishers/seren-bounty/bounties/$BOUNTY_ID/submissions/$SUBMISSION_ID" \
-H "Authorization: Bearer $SEREN_API_KEY"
Download the raw attachment bytes for a submission. Same access rules
as the detail route. The response's Content-Type and
Content-Disposition come from the stored metadata.
/bounties/{id}/submissions/{submission_id}/attachmentcurl -sS -X GET "https://api.serendb.com/publishers/seren-bounty/bounties/$BOUNTY_ID/submissions/$SUBMISSION_ID/attachment" \
-H "Authorization: Bearer $SEREN_API_KEY" \
--output submission.pdf
Unauthenticated dashboard endpoints. Safe to call without an API key.
Public bounty listing. Supports status, customer_slug, limit
(default 50, max 200), and a created_at-anchored cursor. This is the
anonymous counterpart to the org-scoped GET /organizations/me/bounties.
/bountiescurl -sS -X GET "https://api.serendb.com/publishers/seren-bounty/bounties?status=open&limit=50"
Platform-wide rollup: bounty counts by status, pool totals, earnings totals, participant counts.
/overviewcurl -sS -X GET "https://api.serendb.com/publishers/seren-bounty/overview"
Top earners across all bounties. sort_by defaults to paid; also accepts earned, count, bounties.
/leaderboardcurl -sS -X GET "https://api.serendb.com/publishers/seren-bounty/leaderboard?sort_by=paid&limit=20"
Public rollup for a single bounty (progress, participants, earnings by status, pool consumption).
/bounties/{id}/statscurl -sS -X GET "https://api.serendb.com/publishers/seren-bounty/bounties/$BOUNTY_ID/stats"
Top earners scoped to a single bounty.
/bounties/{id}/leaderboardcurl -sS -X GET "https://api.serendb.com/publishers/seren-bounty/bounties/$BOUNTY_ID/leaderboard?limit=20"
Public rollup for any user: total earned / paid / clawed back, earning counts by status, bounty count.
/users/{user_id}/statscurl -sS -X GET "https://api.serendb.com/publishers/seren-bounty/users/$USER_ID/stats"
User rollup for the authenticated caller.
/users/me/statscurl -sS -X GET "https://api.serendb.com/publishers/seren-bounty/users/me/stats" \
-H "Authorization: Bearer $SEREN_API_KEY"
Daily accrual and payout time series. days query param, default 30, max 365.
/stats/dailycurl -sS -X GET "https://api.serendb.com/publishers/seren-bounty/stats/daily?days=30"
max_pool_atomic before the bounty opens. /bounties/{id}/fund is idempotent on Idempotency-Key. Partial deposits are fine - the bounty only transitions funding -> open when total deposited equals the cap.Idempotency-Key header or idempotency_key body field. Replays with the same key on a different amount or different user return 409, not a silent success.earned. Once the release sweep flips it to released, it's scheduled for payout and clawback returns 409.hold_days is constrained to 1 or 90. Anything else is rejected at create time.referral_code is deterministic. sha256(bounty_id || user_id) - safe to recompute client-side after a lost response. Re-joining returns the same code.wallet_address is a matching mechanism, not payment routing. Payouts flow through Serencore's user-id-native payout endpoints. The wallet_address rule exists only so poll-verifier responses can surface addresses that map back to bounty participants.user_id, not wallet addresses. Seren Bounty is user-id-native. Leaderboards and user stats identify earners by user_id.submission_mode = required gates submission creation but does not gate payout. Agents can earn without submitting; customers can eyeball submissions as qualitative evidence but cannot use required to hold back a payout today.DELETE /bounties/{id}/submission sets the row to withdrawn and retains the attachment. Rows are only truly removed when the owning bounty is cascade-deleted.pool_remaining_atomic exceeds min_tier_rate while the deadline hasn't passed, the bounty flips back from exhausted to open.health_status (healthy, degraded, failing) driven by verifier_failure_count. Poll verifiers degrade at 3 consecutive failures and fail at 10+. Check GET /bounties/{id} for health_status, verifier_failure_count, and verifier_last_error.(customer_slug, event_id). The same event fired twice is silently absorbed. Use a unique event_id per qualifying occurrence.Free
npx skills add serenorg/seren-skillsSelect “Seren Bounty” when prompted
Seren
Added April 29, 2026