@taskmagic/apps-simplero
v0.0.2
Published
Contacts, tags, mailing lists, course access and orders in [Simplero](https://simplero.com) — the all-in-one courses, membership, email marketing and e-commerce platform.
Readme
Simplero
Contacts, tags, mailing lists, course access and orders in Simplero — the all-in-one courses, membership, email marketing and e-commerce platform.
API docs: the product serves its own OpenAPI 3.1 document at https://simplero.com/api/v2/docs/openapi.json — 614 paths and 151 schemas, and the authoritative reference for this piece. (The human-facing docs page is a JavaScript shell that renders that same document.)
The API is REST under https://simplero.com, every path versioned as /api/v2/..., and
authenticated with an X-API-Key header. /api/v1 is deprecated and is not used here.
- Actions: List Contacts, Create Contact, Update Contact, Add Tag To Contact, Remove Tag From Contact, Subscribe Contact To List, Unsubscribe Contact From List, Grant Course Access, Revoke Course Access, List Purchases, List Products, List Tags, List Lists.
- Triggers: New Contact (polling), New Purchase (polling), New List Subscription (polling).
Connection: in Simplero go to Settings → Integrations → Create New API Key, then use the copy button next to the new key and paste it into the connection. A Simplero API key carries full admin rights over the account, so create a separate key for TaskMagic rather than reusing an existing one — that way it can be revoked on its own. The Simplero admin is account-scoped and behind a login, so there is no stable public URL to link to; use the menu path above.
Notes
- The
User-Agentheader is enforced, and it is checked before authentication. Simplero requires a User-Agent containing an app name and a contact email. A missing or empty one comes back asHTTP 400 {"error":"Incorrect User-Agent"}— verified live — which looks nothing like the real cause, and it fires before the API key is even examined. The piece hardcodesTaskMagic ([email protected])in its shared request helper so no call site can omit it. - Identifiers are ambiguous, and this needs confirming against a live account. Every
{id}path parameter in the spec is typedinteger, yet of the 151 schemas onlyBuilderDocNodedeclares anidproperty at all —Customer,Purchase,Subscription,TagandListexpose a stringtokeninstead, andProductandCoursedeclare neither. Because the spec contradicts itself, the Contact ID inputs are free text and pass through whatever you give them verbatim: try the numeric ID from the contact's admin URL first, and thetokenfrom List Contacts if that 404s. The Tag / List / Course / Product dropdowns useidwhen the live response actually returns one and fall back totoken; a record that carries neither is left out of the dropdown rather than offered with an empty value, so if the Course or Product dropdown comes up empty against a live account that is this same ambiguity and is worth reporting. - Polling triggers only — there is no webhook API. Simplero v2 defines no
/webhookspaths and no outgoing-webhook schema.POST /api/v2/customers/{id}/actions/webhookonly fires a webhook record that already exists, identified by anoutgoing_webhook_idthat nothing in the API creates or lists, so there is nothing for a trigger to auto-register or to tear down. If you want push delivery, configure a Simplero Trigger by hand in the Simplero admin to POST to a TaskMagic Catch Hook URL; that is a manual setup on both sides, not something this piece can wire up for you. - Nothing can be sorted. Not one of the 614 documented paths accepts
sort,order,directionorsort_by, so a poll cannot ask for newest-first. Each trigger instead re-reads a timestamp window on every poll (created_atfor New Contact and New List Subscription,purchased_atfor New Purchase) and lets the timestamp comparison decide what is new. Rows are also collapsed ontokenwithin a poll, because paging an unsorted list that is being written to can hand back the same row on two different pages. Each poll reads at most 5 pages of 100, and looks back at most 30 days — without that clamp a trigger that found nothing would widen its window by a day every day and drift permanently past the page cap. A trigger's dedupe timestamp is always the same field its window filters on; keying the two on different fields makes a row fire twice as soon as the second field catches up. - Date filters have day granularity, in the account's timezone.
DateFilter.from/.toareformat: date, and the API does not report which timezone the account interprets them in. The triggers therefore widen their window by a day at each end — enough to cover every offset from UTC-12 to UTC+14 — and rely on the exact timestamp comparison to narrow it back down. - New Purchase watches
purchased_at, New List Subscription watchescreated_at. Simplero writes a purchase row while the order is still being taken, socreated_atwould also fire on carts that were never paid for. Conversely a double-opt-in list creates the subscription row at signup but leavesfirst_activated_atnull until the confirmation link is clicked, so filtering on that field would silently never fire for those lists. - Filters are
deepObject, not JSON. They go on the wire as?created_at[preset]=custom&created_at[from]=2026-07-01and?email[op]=equals&email[value]=…; the request helper flattens nested objects into those bracketed names.List Contactsexposes the useful subset of roughly eighty available filters — email, first names, last name, status, tag, list, product, created and updated — rather than burying them among UTM attribution, funnel steps, countdown timers and deal pipelines. - Pagination is 1-indexed (
page,per_page, 1–100, default 20) — v1 was 0-indexed, so a ported flow that starts at page 0 will silently misbehave. List responses come back as{ "data": [...], "pagination": { page, per_page, total, total_pages } }; the actions return the rows and the paginator separately. - Error shapes are inconsistent. Most failures answer
{"error":"..."}(a string), while validation failures answer{"errors":["...","..."]}(an array, plural key). The error parser reads both; a 422 would otherwise surface with an empty message. Only 200, 401, 404 and 422 are documented as responses, plus the undocumented 400 for the User-Agent check. - Rate limits are not documented. No
RateLimit-*and noRetry-Afterheader was observed on any response, so there is no published budget to respect and no server-supplied delay to honour. The request helper retries 408/429/5xx and network failures up to three times with exponential backoff (500 ms, 1 s), and every request has a 30 second timeout. OnlyGETis retried on all of those: a lost response is indistinguishable from a write the server accepted, so the write verbs are replayed only on 429, the one status that means the request was never processed. - Action verbs are checked, not trusted. Simplero's
/actions/...endpoints answer HTTP 200 with{"data":{"success":false,"message":"..."}}when they decline to do the work. The tag, list-subscription and course actions fail the step in that case rather than reporting success. - No custom API call action. A passthrough would hand this connection's key — which has full admin rights over the Simplero account — to any URL a flow supplied.
- Deliberately not built: Simplero exposes 100+ further
/customers/{id}/actions/...verbs (automations, countdown timers, deals, events, credits, badges, SMS, Mailchimp and Meta audience sync, and more) plus create/update endpoints for most of its 68 top-level resources. Only the contact, tag, list, course and commerce surface people actually automate is shipped here.
