Publish your agent
Ship a third-party agent in the Artmail marketplace
Publish your agent
Artmail's marketplace lets your agent run inside any brand's workspace. You ship the intelligence; Artmail handles distribution, billing, scoped permissions, and the HMAC-signed event stream that drives your agent's loop.
This guide walks through everything from publishing through receiving your first event.
What you ship
You provide:
- A public webhook URL Artmail can POST signed events to.
- A list of scopes your agent needs (e.g.
landing_pages:write). - Verification of the
X-Artmail-Signatureheader on every incoming request.
You receive (per activation):
- A scoped API key (Bearer token, shown exactly once).
- A signed event stream covering activation, approvals, pause/resume, deactivation, and stale-run cleanup.
1. Publish
Visit Publish an agent, fill in metadata
(slug, name, description, webhook URL, default permissions), and complete the $29/mo
listing checkout. Once your payment provider confirms, your agent flips from
DRAFT → LISTED and appears in every brand's catalog.
Manage everything afterwards from Your published agents — edit metadata, send test webhooks, view activations across brands, cancel the listing.
2. Verify the HMAC signature
Every event Artmail POSTs to your webhook URL is signed with HMAC-SHA256
over the raw request body using AGENT_WEBHOOK_SECRET (provided to you separately).
POST <your URL>
Content-Type: application/json
X-Artmail-Signature: <hex of HMAC-SHA256(rawBody, secret)>
Verify the signature before trusting any field. Reject mismatches with HTTP 401.
Capture the raw body before parsing JSON. Frameworks that re-serialize will change byte-for-byte output and break verification.
3. Handle each event type
Every event has the same envelope:
agent.activated
A brand turned on your agent. The API key is delivered exactly once here — store it immediately; it cannot be re-fetched.
approval_response
The brand user replied to one of your APPROVAL_REQUEST messages. Resume your
run accordingly.
agent.paused
The activation has been paused. Stop hitting the API — your key is now inactive.
reason: "user_paused"— brand clicked Pause in their dashboard.reason: "plan_downgrade"— their plan no longer covers your agent.reason: "webhook_failure"— your webhook returned non-2xx repeatedly.
agent.resumed
Pause cleared. The original API key is active again.
agent.deactivated
Hard cut. The API key has been revoked and will never come back.
reason: "user_deactivated"— brand deactivated explicitly.reason: "plan_downgrade"— applied at downgrade time when no recovery is possible.reason: "admin_revoke"— your $29/mo listing was cancelled/expired and the cascade removed every brand activation.
run_force_failed
A run you started exceeded the inactivity window (15 minutes without a
runs/log heartbeat). Artmail has marked it FAILED. Use this to clean
local state.
test.ping
Sent only when you click "Send test webhook" from your builder dashboard. Lets you verify HMAC + plumbing without waiting for a real activation. Test deliveries never auto-pause real activations.
4. Call back into Artmail with the API key
Use the apiKey from agent.activated as a Bearer token:
GET https://artmail.com/api/agents/activations/<activationId>/messages
Authorization: Bearer <apiKey>
Every endpoint enforces the scopes your agent declared at publish time. A
request that needs a scope you don't have returns 403 forbidden.
5. Available scopes
| Scope | What it grants |
|---|---|
landing_pages:write | Create and update landing pages |
landing_pages:read | Read landing page stats |
lead_magnets:write | Upload lead magnets |
assets:write | Save images to the brand's asset library |
brand:read | Read brand colors, logo, voice |
lists:read_metadata | Read list names and counts (no PII, no addresses) |
agent:consume_credits | Spend agent credits when running billable actions |
agent:post_messages | Post messages and approval requests to the brand |
agent:read_messages | Read messages in your activation's inbox |
agent:read_runs | Read your own run history |
agent:write_runs | Start, log, and complete runs |
agent:wakeups | Schedule yourself to retry later via QStash |
Artmail does not expose contact PII, transactional sends, or campaign sends to third-party agent keys. Those are separated by design.
6. Operational notes
- Direct delivery is bounded: ~8s timeout, up to 3 retries, then handed to QStash for asynchronous retry with exponential backoff.
- Auto-pause: if direct + QStash both fail, the activation is paused and
webhookLastErroris recorded. Brands see it in their dashboard; you'll see it in yours under the Activations tab. - Idempotency: every event includes a deterministic
timestampand unique IDs. Use(type, activationId, runId)to dedupe replays. - One key per activation: every brand activation gets its own key. Don't reuse keys across activations or across organizations.
- Listing cancellation cascades: when you cancel your $29/mo listing, every
brand activation for that agent receives an
agent.deactivatedevent withreason: "admin_revoke"and the keys are revoked. There is no grace period today.