@officexapp/vidfarm-devcli 0.21.62 → 0.21.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/dollarplatoon-skill/SKILL.md +163 -1174
- package/.agents/skills/dollarplatoon-skill/SOURCE.md +62 -0
- package/.agents/skills/dollarplatoon-skill/skill/clients.md +234 -0
- package/.agents/skills/dollarplatoon-skill/skill/feeds.md +326 -0
- package/.agents/skills/dollarplatoon-skill/skill/gigs.md +395 -0
- package/.agents/skills/dollarplatoon-skill/skill/gigworkers.md +324 -0
- package/.agents/skills/dollarplatoon-skill/skill/orders.md +573 -0
- package/.agents/skills/dollarplatoon-skill/skill/payouts.md +234 -0
- package/.agents/skills/dollarplatoon-skill/skill/platform.md +174 -0
- package/.agents/skills/dollarplatoon-skill/skill/prices.md +75 -0
- package/.agents/skills/dollarplatoon-skill/skill/pricing-and-tags.md +255 -0
- package/.agents/skills/dollarplatoon-skill/skill/proofs.md +555 -0
- package/.agents/skills/dollarplatoon-skill/skill/queue.md +404 -0
- package/.agents/skills/dollarplatoon-skill/skill/quickstart.md +191 -0
- package/.agents/skills/dollarplatoon-skill/skill/staging.md +178 -0
- package/.agents/skills/dollarplatoon-skill/skill/tasks.md +588 -0
- package/.agents/skills/dollarplatoon-skill/skill/web-pages.md +586 -0
- package/.agents/skills/vidfarm/SKILL.md +3 -3
- package/.agents/skills/vidfarm/references/core-workflows.md +107 -3
- package/SKILL.director.md +109 -5
- package/SKILL.md +3 -1
- package/clipper.md +20 -0
- package/dist/src/cli.js +50 -6
- package/dist/src/devcli/delivery-seal.js +119 -0
- package/dist/src/devcli/marketplace-console.js +1418 -0
- package/dist/src/devcli/marketplace-gigs.js +162 -16
- package/marketplace.md +299 -1
- package/package.json +24 -3
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
# Gigs, invites, and mailboxes
|
|
2
|
+
|
|
3
|
+
The gig (vending machine) itself, the invite links that gate it, and the mailboxes that are a
|
|
4
|
+
worker's place inside it.
|
|
5
|
+
|
|
6
|
+
## Contents
|
|
7
|
+
|
|
8
|
+
- Gig routes
|
|
9
|
+
- Create a gig
|
|
10
|
+
- Read and update a gig
|
|
11
|
+
- Invite links
|
|
12
|
+
- Security token
|
|
13
|
+
- Worker rate limits
|
|
14
|
+
- Task expiry
|
|
15
|
+
- Funding
|
|
16
|
+
- The dashboard
|
|
17
|
+
- Mailbox routes
|
|
18
|
+
- Join a gig
|
|
19
|
+
- Update a mailbox
|
|
20
|
+
- List your mailboxes
|
|
21
|
+
- Reading a mailbox's tasks
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Gig routes
|
|
26
|
+
|
|
27
|
+
| Method | Path | Auth | Description |
|
|
28
|
+
|--------|------|------|-------------|
|
|
29
|
+
| POST | `/gigs` | Yes | Create a gig |
|
|
30
|
+
| GET | `/gigs/mine` | Yes | Your owned gigs (`?tag=` substring filter) |
|
|
31
|
+
| GET | `/gigs/:id` | Optional | Gig detail |
|
|
32
|
+
| PATCH | `/gigs/:id` | Owner | Update |
|
|
33
|
+
| POST | `/gigs/:id/invites` | Owner | Mint an invite link |
|
|
34
|
+
| GET | `/gigs/:id/invites` | Owner | List invite links |
|
|
35
|
+
| DELETE | `/gigs/:id/invites/:token` | Owner | Revoke an invite link |
|
|
36
|
+
| POST | `/gigs/:id/rotate-token` | Owner | Rotate the security token |
|
|
37
|
+
| POST | `/gigs/:id/deposit` | Yes | Deposit USDC into the gig |
|
|
38
|
+
| GET | `/gigs/:id/dashboard` | Owner | Everything about the gig in one call |
|
|
39
|
+
| GET | `/gigs/:id/feeds` | Owner | Which feeds list this gig |
|
|
40
|
+
| POST | `/gigs/:id/tasks/:msgId/extend` | Owner | Reset a task's expiry clock |
|
|
41
|
+
| POST | `/gigs/:id/tasks/:msgId/recycle` | Owner | Take a task back and redistribute it |
|
|
42
|
+
|
|
43
|
+
`GET /gigs` returns `410 Gone`. There is no public marketplace — every gig is a private network
|
|
44
|
+
reached by invite.
|
|
45
|
+
|
|
46
|
+
## Create a gig
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
POST /gigs
|
|
50
|
+
{
|
|
51
|
+
"title": "Reddit Comments for Product Launch",
|
|
52
|
+
"price": 0.50,
|
|
53
|
+
"terms": "Comment genuinely on the linked threads. Tags in use: reddit, urgent.",
|
|
54
|
+
"notes": "Internal notes, owner only",
|
|
55
|
+
"owner_wallet": "wallet_alias_id", // optional — auto-provisions a hot wallet if omitted
|
|
56
|
+
"join_policy": "invite", // "invite" (default) | "open"
|
|
57
|
+
"tags": ["reddit", "q3-launch"], // free-form, max 25 tags of 256 chars
|
|
58
|
+
"requires_approval": false,
|
|
59
|
+
"review_timeout": 172800, // seconds before an unreviewed proof auto-approves
|
|
60
|
+
"task_timeout": 86400, // seconds a worker may hold a task; null = never expires
|
|
61
|
+
"distribution": "queue", // see tasks.md for all eight modes
|
|
62
|
+
"queue_order": "fifo", // queue modes only: fifo | lifo | priority | random
|
|
63
|
+
"max_claims_per_task": 3, // queue_solo only; null = unlimited
|
|
64
|
+
"default_task_tags": ["shortform"], // stamped on tasks that arrive untagged
|
|
65
|
+
"default_rate_limit_count": 5, // worker throttle; both fields or neither
|
|
66
|
+
"default_rate_limit_minutes": 60,
|
|
67
|
+
"default_max_open_tasks": 3, // tasks one worker may hold unproven; null = unlimited
|
|
68
|
+
"allow_price_offers": false, // let workers quote their own price per proof
|
|
69
|
+
"task_escrow": false, // fund each task on chain as it is created — see tasks.md
|
|
70
|
+
"min_payout": 0,
|
|
71
|
+
"location": { "country": "US", "label": "United States" },
|
|
72
|
+
"icon_url": "https://...",
|
|
73
|
+
"proof_webhook_url": "https://...", // POSTed each proof submission
|
|
74
|
+
"join_webhook_url": "https://...", // POSTed a mailbox.joined event
|
|
75
|
+
"contract_address": "0x..."
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
```json
|
|
80
|
+
→ {
|
|
81
|
+
"gig": {
|
|
82
|
+
"id": "GIG_01HX...",
|
|
83
|
+
"email": "GIG_01HX..._abc123.dollar-platoon@fwd.zoomgtm.com",
|
|
84
|
+
"webhook": "https://dollarplatoon.com/api/inbound/webhook/GIG_01HX...?token=abc123",
|
|
85
|
+
"invite_url": "https://dollarplatoon.com/gig/GIG_01HX.../join?invite=a1b2c3d4e5f6",
|
|
86
|
+
"join_policy": "invite", "price": 0.50, "status": "active"
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Creation runs a compliance check that blocks illegal content and warns on borderline content.
|
|
92
|
+
|
|
93
|
+
**`distribution: "inbound_order"` takes a different body.** Omit `price` — it is pinned to 0 —
|
|
94
|
+
and send `list_price` instead (minimum $0.02). `review_timeout` must be a positive number of at
|
|
95
|
+
least 3600 seconds; `-1` is refused. `price_tbd`, `allow_price_offers`, a non-null `task_timeout`
|
|
96
|
+
and a non-zero `min_payout` are all rejected at the door rather than quietly ignored. The response
|
|
97
|
+
adds `vendor_mailbox_id` — your own mailbox in your own shop, because there you are the worker
|
|
98
|
+
too. See [orders.md](https://dollarplatoon.com/skill/orders.md).
|
|
99
|
+
|
|
100
|
+
Tags are arbitrary — there is no whitelist. Use them to group gigs by campaign, client, or batch,
|
|
101
|
+
then filter with `GET /gigs/mine?tag=q3` (case-insensitive substring, comma-separated values
|
|
102
|
+
OR'd).
|
|
103
|
+
|
|
104
|
+
## Read and update a gig
|
|
105
|
+
|
|
106
|
+
`GET /gigs/:id` returns the gig. An owner or member also sees `notes` and enriched fields. It
|
|
107
|
+
always shows `available_funds` and `reserved_funds`, which is how a worker judges whether the gig
|
|
108
|
+
can actually pay.
|
|
109
|
+
|
|
110
|
+
`PATCH /gigs/:id` accepts any subset of: `title`, `price`, `terms`, `status`, `review_timeout`,
|
|
111
|
+
`task_timeout`, `tags`, `default_task_tags`, `join_policy`, `distribution`, `requires_approval`,
|
|
112
|
+
`min_payout`, `location`, `notes`, `proof_webhook_url`, `join_webhook_url`, `contract_address`,
|
|
113
|
+
`default_rate_limit_count`, `default_rate_limit_minutes`, `default_max_open_tasks`,
|
|
114
|
+
`allow_price_offers`. `tags` replaces the whole list.
|
|
115
|
+
|
|
116
|
+
`allow_price_offers` lets a worker send `asking_price` with a proof. The ask is a quote: it never
|
|
117
|
+
becomes the payout unless you approve at that amount, and a review that times out still pays the
|
|
118
|
+
gig price. See [proofs.md](https://dollarplatoon.com/skill/proofs.md).
|
|
119
|
+
|
|
120
|
+
**An order machine adds three fields to `GET /gigs/:id` and moves one on PATCH.**
|
|
121
|
+
`list_price` is public — a buyer is entitled to see the sticker before joining. `fee_bps` is the
|
|
122
|
+
live Treasury rate, present even when its value is `null`, which means *"could not be read"* and
|
|
123
|
+
must never be replaced with a constant. `escrowed_funds` goes to the owner and members only, and
|
|
124
|
+
is how much of `available_funds` is customers' escrow rather than the vendor's takings; `null`
|
|
125
|
+
there means "not synced", not "zero". On PATCH, `list_price` moves and `price` answers `409` —
|
|
126
|
+
along with `distribution`, `contract_address`, `min_payout`, `task_timeout` and a `review_timeout`
|
|
127
|
+
of `-1`.
|
|
128
|
+
|
|
129
|
+
## Invite links
|
|
130
|
+
|
|
131
|
+
Invite links gate who joins the private network. Two fields give you every mode:
|
|
132
|
+
|
|
133
|
+
- `max_uses` — `1` for one person, `N` for a cohort, `null` for unlimited.
|
|
134
|
+
- `email` — bind to one exact address, or `null` for anyone with the link.
|
|
135
|
+
|
|
136
|
+
```json
|
|
137
|
+
POST /gigs/:id/invites { "max_uses": 1, "email": "worker@example.com", "label": "for Alice" }
|
|
138
|
+
→ { "invite": { "token": "a1b2c3d4e5f6", "max_uses": 1, "uses": 0,
|
|
139
|
+
"invite_url": "https://dollarplatoon.com/gig/GIG_01HX.../join?invite=a1b2c3d4e5f6" } }
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
An **email-bound invite is a pre-approval**: that worker skips `pending_approval` even when the
|
|
143
|
+
gig sets `requires_approval`. You named them, so the gate does not apply.
|
|
144
|
+
|
|
145
|
+
`GET /gigs/:id/invites` lists every invite with `uses`, `revoked`, and `exhausted`.
|
|
146
|
+
`DELETE /gigs/:id/invites/:token` revokes one. Use consumption is atomic, so concurrent joins
|
|
147
|
+
cannot race past `max_uses`.
|
|
148
|
+
|
|
149
|
+
## Security token
|
|
150
|
+
|
|
151
|
+
Every gig has a 6-character token embedded in its inbound email address and webhook URL. It stops
|
|
152
|
+
anyone who guesses a gig id from injecting tasks.
|
|
153
|
+
|
|
154
|
+
- Email: `{gig_id}_{token}.dollar-platoon@fwd.zoomgtm.com`
|
|
155
|
+
- Webhook: `/inbound/webhook/{gig_id}?token={token}`
|
|
156
|
+
- Requests without a valid token get `403`.
|
|
157
|
+
|
|
158
|
+
### Who can read it
|
|
159
|
+
|
|
160
|
+
The token is a **write credential** — whoever holds it can post tasks into the gig — so
|
|
161
|
+
`GET /gigs/:id` only puts it on the `webhook` URL for callers entitled to use that door:
|
|
162
|
+
|
|
163
|
+
| Caller | Gets `?token=` on `webhook` |
|
|
164
|
+
|---|---|
|
|
165
|
+
| The gig owner | Yes, on every gig |
|
|
166
|
+
| A member of an `inbound_order` gig | Yes — placing an order **is** posting to this webhook |
|
|
167
|
+
| A member of any other gig | **No.** A worker is not a publisher |
|
|
168
|
+
| Anyone else, signed in or not | No |
|
|
169
|
+
|
|
170
|
+
The `webhook` field itself always comes back, minus the token, so the shape of the response does
|
|
171
|
+
not change for a reader who is not entitled to the secret. Read it once as the owner and store
|
|
172
|
+
it; a publisher app is not expected to re-fetch it per request.
|
|
173
|
+
|
|
174
|
+
On a **`task_escrow`** gig the token is stronger than a write credential — creating a task
|
|
175
|
+
deposits the owner's USDC on chain — which is why a worker never sees it there.
|
|
176
|
+
|
|
177
|
+
```json
|
|
178
|
+
POST /gigs/:id/rotate-token
|
|
179
|
+
→ { "email": "GIG_01HX..._newtoken...", "webhook": "https://.../webhook/GIG_01HX...?token=newtoken" }
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**Rotation invalidates the old email address, the old webhook URL, and every Insert Task link at
|
|
183
|
+
once.** Update your publisher integrations immediately after.
|
|
184
|
+
|
|
185
|
+
Gigs created before tokens existed accept all inbound requests. Generate one from the dashboard
|
|
186
|
+
to turn protection on.
|
|
187
|
+
|
|
188
|
+
## Worker rate limits
|
|
189
|
+
|
|
190
|
+
An optional throttle: each gigworker may take at most **N per M minutes**. "Take" counts proofs
|
|
191
|
+
submitted *and* queue tasks claimed but not yet proven, so a worker cannot hoard the queue by
|
|
192
|
+
claiming ahead.
|
|
193
|
+
|
|
194
|
+
- Gig-wide default: `default_rate_limit_count` + `default_rate_limit_minutes` (both positive
|
|
195
|
+
integers, or both `null` to disable).
|
|
196
|
+
- Per worker: `PATCH /gigs/:id/mailboxes/:mbx_id` with `rate_limit_count` + `rate_limit_minutes`
|
|
197
|
+
(owner only; both `null` reverts to the gig default).
|
|
198
|
+
- At the limit, `/queue/poll` and `POST /gigs/:id/proofs` return `429` with a readable `error` and
|
|
199
|
+
a `rate_limit` object: `{ count, minutes, source: "gig"|"mailbox", used, remaining, retry_at }`.
|
|
200
|
+
- Submitting a proof for a task you already claimed is **never** blocked — the claim was counted
|
|
201
|
+
at poll time, so the loop never double-charges.
|
|
202
|
+
|
|
203
|
+
## Open task cap
|
|
204
|
+
|
|
205
|
+
The rate limit above is a rolling window, so a task a worker holds stops counting against it once
|
|
206
|
+
the claim ages out. "5 per hour" therefore lets one worker take 5 more tasks every hour and prove
|
|
207
|
+
none of them. The open task cap is the standing ceiling the window cannot express: **how many
|
|
208
|
+
tasks one worker may hold with no proof submitted, at any moment**.
|
|
209
|
+
|
|
210
|
+
- Gig-wide default: `default_max_open_tasks` (positive integer, or `null` for unlimited).
|
|
211
|
+
- Per worker: `PATCH /gigs/:id/mailboxes/:mbx_id` with `max_open_tasks` (owner only; `null`
|
|
212
|
+
reverts to the gig default).
|
|
213
|
+
- At the cap, `/queue/poll` returns `429` with an `open_tasks` object:
|
|
214
|
+
`{ max_open_tasks, source: "gig"|"mailbox", open, remaining }`. Under the cap, a poll is
|
|
215
|
+
trimmed to the slots left, and the same object rides on the response.
|
|
216
|
+
- A task with a proof against it is not open — the worker is waiting on review, not hoarding.
|
|
217
|
+
Assigned tasks and `queue_solo` copies do count.
|
|
218
|
+
- The only ways to free a slot: submit a proof, skip the task, report it, or let it expire.
|
|
219
|
+
|
|
220
|
+
Pair it with `task_timeout`. The cap stops a worker taking more; the timeout takes back what
|
|
221
|
+
they already hold.
|
|
222
|
+
|
|
223
|
+
## Task expiry
|
|
224
|
+
|
|
225
|
+
Set `task_timeout` (seconds) to give workers a deadline. The clock starts when a task is claimed
|
|
226
|
+
(queue gigs) or delivered (push gigs). Default `null` — tasks never expire.
|
|
227
|
+
|
|
228
|
+
- After expiry, proof submission, skip, and report all return `410 Gone`.
|
|
229
|
+
- Unclaimed queue items never expire.
|
|
230
|
+
- Task listings carry `expires_at` and `expired`.
|
|
231
|
+
- **An expired task returns to the pool by itself.** The sweep runs on ordinary gig traffic (at
|
|
232
|
+
most once a minute), and the daily cron catches a gig nobody polled. It recycles the task
|
|
233
|
+
exactly as the route below does, so an expired hold is released even if you never look.
|
|
234
|
+
`tasks_received` is **not** given back on an expiry — running out of time is what
|
|
235
|
+
`response_rate` measures. An owner recycling by hand still discounts it, as before.
|
|
236
|
+
|
|
237
|
+
```json
|
|
238
|
+
POST /gigs/:id/tasks/:msgId/extend
|
|
239
|
+
→ { "success": true, "expires_at": "...", "expired": false }
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
```json
|
|
243
|
+
POST /gigs/:id/tasks/:msgId/recycle
|
|
244
|
+
→ { "success": true, "requeued": true } // queue gig
|
|
245
|
+
→ { "success": true, "reassigned_to": "MBX_...", "reassigned_to_name": "..." } // push gig
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Recycle takes the task back and redistributes it. On a `queue` gig it returns to the queue and the
|
|
249
|
+
previous holder will not receive it again. On `queue_solo` it discards that one worker's copy and
|
|
250
|
+
returns its claim slot, leaving everyone else untouched. On a push gig it reassigns per the gig's
|
|
251
|
+
distribution mode. Both routes reject an `UNASSIGNED` task — there is no holder and no clock.
|
|
252
|
+
|
|
253
|
+
## Funding
|
|
254
|
+
|
|
255
|
+
```json
|
|
256
|
+
POST /gigs/:id/deposit { "wallet_alias_id": "...", "amount": 100 }
|
|
257
|
+
→ { "tx_hash": "0x...", "available_funds": 100 }
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Moves USDC from your hot wallet into the gig's on-chain balance. Budget **110%** of expected
|
|
261
|
+
payouts — the fee is charged on top. Funds are locked once deposited; there is no withdrawal.
|
|
262
|
+
|
|
263
|
+
**On an order machine this route answers `409`, and correctly.** An order machine is not funded
|
|
264
|
+
by its owner: each order is funded by the participant who places it, against a deposit that names
|
|
265
|
+
it. Money in the shared pot there would be unreachable — the deposit-naming payout can only spend
|
|
266
|
+
deposits it names, and the Treasury's reserved-balance guard refuses the legacy payout the float
|
|
267
|
+
would need. It would be money the vendor could never get out.
|
|
268
|
+
|
|
269
|
+
## The dashboard
|
|
270
|
+
|
|
271
|
+
```json
|
|
272
|
+
GET /gigs/:id/dashboard
|
|
273
|
+
→ { "gig": {...}, "mailboxes": [...], "proofs": [...], "rollups": [...], "inbound_messages": [...] }
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Syncs the on-chain balance on every load and signs every S3 URL for proof attachments. Proofs and
|
|
277
|
+
inbound messages are cursor-paginated — follow `proofs_next_cursor` and `inbound_next_cursor` via
|
|
278
|
+
`GET /gigs/:id/dashboard/proofs?cursor=` and `GET /gigs/:id/dashboard/inbound?cursor=`. The
|
|
279
|
+
inbound page also accepts `?tag=`, `?tag_match=`, and `?tag_mode=`.
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## Mailbox routes
|
|
284
|
+
|
|
285
|
+
A mailbox is one worker's place in one gig. It is created by joining and it is where tasks land.
|
|
286
|
+
|
|
287
|
+
| Method | Path | Auth | Description |
|
|
288
|
+
|--------|------|------|-------------|
|
|
289
|
+
| POST | `/gigs/:id/mailboxes` | Yes | Join the gig |
|
|
290
|
+
| GET | `/gigs/:id/mailboxes` | Owner | List mailboxes in the gig |
|
|
291
|
+
| PATCH | `/gigs/:id/mailboxes/:mbx_id` | Yes | Update (owner and worker set different fields) |
|
|
292
|
+
| DELETE | `/gigs/:id/mailboxes/:mbx_id` | Yes | Leave the gig |
|
|
293
|
+
| GET | `/mailboxes/mine` | Yes | Your mailboxes across every gig |
|
|
294
|
+
| GET | `/work/available` | Yes | Where work is waiting — see gigworkers.md |
|
|
295
|
+
| GET | `/mailboxes/:mbxId/inbound` | Yes | Tasks in one mailbox |
|
|
296
|
+
| POST | `/gigs/:id/mailboxes/:mbxId/regenerate-token` | Yes | New share token |
|
|
297
|
+
|
|
298
|
+
## Join a gig
|
|
299
|
+
|
|
300
|
+
```json
|
|
301
|
+
POST /gigs/:id/mailboxes
|
|
302
|
+
{
|
|
303
|
+
"name": "John's Mailbox",
|
|
304
|
+
"email": "john@example.com", // contact address for forwarded tasks
|
|
305
|
+
"invite": "a1b2c3d4e5f6", // required when join_policy is "invite"
|
|
306
|
+
"wallet_address": "0x...", // optional — hot wallet auto-provisioned if omitted
|
|
307
|
+
"webhook": "https://...", // optional — pushed tasks POST here
|
|
308
|
+
"notes": "I have experience with Reddit marketing",
|
|
309
|
+
"tags": ["urgent", "linkedin-batch"] // private to the worker
|
|
310
|
+
}
|
|
311
|
+
→ { "mailbox": { "id": "MBX_01HX...", "status": "active" } } // or "pending_approval"
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
The invite is the gate. An invite gig rejects a join without a valid token (`403`); an
|
|
315
|
+
email-bound invite must match your account email and skips owner approval. There are no
|
|
316
|
+
reputation thresholds — `min_rep_volume`, `min_rep_quality` and `min_rep_recency` were removed,
|
|
317
|
+
and a gig that still carries them is not gated by them.
|
|
318
|
+
|
|
319
|
+
If the gig sets `join_webhook_url`, each successful join fires a fire-and-forget POST:
|
|
320
|
+
|
|
321
|
+
```json
|
|
322
|
+
{ "event": "mailbox.joined", "gig_id": "GIG_01HX...", "mailbox_id": "MBX_01HX...",
|
|
323
|
+
"name": "John's Mailbox", "status": "active", "email": "john@example.com",
|
|
324
|
+
"wallet_address": "0x...", "invite_token": "a1b2c3d4e5f6", "joined_at": "..." }
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
Useful for auto-provisioning a workspace or syncing a roster the moment somebody joins.
|
|
328
|
+
|
|
329
|
+
## Update a mailbox
|
|
330
|
+
|
|
331
|
+
**The owner** sets `priority` (1–10, used by `priority_weighted`), `status` (`"active"` approves a
|
|
332
|
+
pending mailbox, `"inactive"` disables it), and the rate-limit override.
|
|
333
|
+
|
|
334
|
+
**The worker** sets `tags`, the standing `filter_*` preferences (see
|
|
335
|
+
[pricing-and-tags.md](https://dollarplatoon.com/skill/pricing-and-tags.md)), and
|
|
336
|
+
`wallet_address`.
|
|
337
|
+
|
|
338
|
+
Worker `tags` are **never returned to the gig owner**. They are for organising your own inbox.
|
|
339
|
+
|
|
340
|
+
Changing `wallet_address`:
|
|
341
|
+
|
|
342
|
+
- Must be a valid EVM address. It is registered to your account automatically; an address already
|
|
343
|
+
registered to a **different** account is rejected with `409`, because wallets stay 1:1 with
|
|
344
|
+
users so nobody can claim somebody else's settlement history.
|
|
345
|
+
- Takes effect for **future rollups only**. A rollup that already exists — including one still
|
|
346
|
+
retrying after a failure — pays to the address snapshotted when it was created.
|
|
347
|
+
- Your history survives, but it does not follow you automatically. Events accrue **per wallet**,
|
|
348
|
+
and `GET /reputation/:wallet/events` reads one address at a time — so after rotating a payout
|
|
349
|
+
address, anyone reading your record has to read both. Nothing is lost; it is simply in two
|
|
350
|
+
places. See [payouts.md](https://dollarplatoon.com/skill/payouts.md).
|
|
351
|
+
|
|
352
|
+
## List your mailboxes
|
|
353
|
+
|
|
354
|
+
```json
|
|
355
|
+
GET /mailboxes/mine
|
|
356
|
+
→ { "mailboxes": [ { "id": "MBX_...", "gig_id": "GIG_...", "status": "active",
|
|
357
|
+
"gig_title": "...", "owner_display_name": "...", "share_token": "SHARE_...",
|
|
358
|
+
"tasks_received": 12, "proofs_submitted": 10, "response_rate": 0.83,
|
|
359
|
+
"tags": ["urgent"] } ], "next_cursor": null }
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
Returns everything by default. Send `?limit=` (max 200) or `?cursor=` to page instead. Supports
|
|
363
|
+
`?tag=` and `?tag_match=` with the same semantics as `/work/available`.
|
|
364
|
+
|
|
365
|
+
This is also where an agent gets its own `share_token` to build a `/submit/:token` link. The
|
|
366
|
+
owner-facing list at `GET /gigs/:id/mailboxes` strips that field.
|
|
367
|
+
|
|
368
|
+
## Reading a mailbox's tasks
|
|
369
|
+
|
|
370
|
+
```json
|
|
371
|
+
GET /mailboxes/:mbxId/inbound
|
|
372
|
+
→ { "inbound_messages": [ { "id": "TASK_...", "type": "email", "subject": "...",
|
|
373
|
+
"payload": "...", "payload_truncated": false, "payload_bytes": 4211,
|
|
374
|
+
"price": 2.5, "price_tbd": false, "tags": ["shortform"],
|
|
375
|
+
"expires_at": null, "expired": false, "alias": null,
|
|
376
|
+
"attachments": [ { "filename": "...", "url": "https://..." } ] } ],
|
|
377
|
+
"next_cursor": null }
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
Newest first, 100 per page (`?limit=` up to 300). `?summary=1` returns every message with no body
|
|
381
|
+
at all — the cheap call for counts and unread badges.
|
|
382
|
+
|
|
383
|
+
**`payload` may be a preview.** Bodies over 6,000 characters are stored off-row, and a list
|
|
384
|
+
returns only the first 1,000 characters with `payload_truncated: true` and the true length in
|
|
385
|
+
`payload_bytes`. Fetch the whole body before acting on it:
|
|
386
|
+
|
|
387
|
+
```json
|
|
388
|
+
GET /gigs/:id/tasks/:msgId
|
|
389
|
+
→ { "task": { "id": "TASK_...", "payload": "<complete, never truncated>",
|
|
390
|
+
"payload_truncated": false, "payload_bytes": 31674, ... } }
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
Readable by the gig owner, by the worker holding the task, and — for tasks still queued — by any
|
|
394
|
+
member of that gig. Tasks returned by `/queue/poll` always arrive complete, so a polling worker
|
|
395
|
+
never needs this route.
|