Agent skill
loops
Loops email platform for SaaS. Use when user mentions "Loops", "Loops.so", "email marketing", "onboarding emails", "transactional email", or asks about SaaS lifecycle emails.
Install this agent skill to your Project
npx add-skill https://github.com/vm0-ai/vm0-skills/tree/main/loops
SKILL.md
Loops API
Send onboarding, marketing, and transactional emails to SaaS users via Loops.
Official docs:
https://loops.so/docs/api-reference
When to Use
- Add or update contacts synced from Clerk or another auth provider
- Trigger automated email sequences via events (e.g., user signed up, upgraded plan)
- Send one-off transactional emails (password reset, invoice, etc.)
- List or manage mailing lists and contact properties
Prerequisites
Alternatively, generate an API key from your Loops dashboard under Settings > API, then export it:
export LOOPS_TOKEN=your_api_key_here
Important: When using
$LOOPS_TOKENin commands that contain a pipe (|), always wrap the curl command inbash -c '...'to avoid silent variable clearing — a known Claude Code issue.
Core APIs
Test API Key
Verify your API key is valid:
bash -c 'curl -s "https://app.loops.so/api/v1/api-key" --header "Authorization: Bearer $LOOPS_TOKEN"'
Create Contact
Write to /tmp/loops_request.json:
{
"email": "user@example.com",
"firstName": "Jane",
"lastName": "Doe",
"userId": "clerk_user_abc123",
"subscribed": true,
"userGroup": "free"
}
bash -c 'curl -s -X POST "https://app.loops.so/api/v1/contacts/create" --header "Authorization: Bearer $LOOPS_TOKEN" --header "Content-Type: application/json" -d @/tmp/loops_request.json'
Docs: https://loops.so/docs/api-reference/create-contact
Update Contact
Write to /tmp/loops_request.json:
{
"email": "user@example.com",
"userGroup": "pro",
"planUpgradedAt": "2024-01-15"
}
bash -c 'curl -s -X PUT "https://app.loops.so/api/v1/contacts/update" --header "Authorization: Bearer $LOOPS_TOKEN" --header "Content-Type: application/json" -d @/tmp/loops_request.json'
Find Contact
Find a contact by email address. Replace <email> with the actual email:
bash -c 'curl -s "https://app.loops.so/api/v1/contacts/find?email=<email>" --header "Authorization: Bearer $LOOPS_TOKEN"'
Delete Contact
Write to /tmp/loops_request.json:
{
"email": "user@example.com"
}
bash -c 'curl -s -X DELETE "https://app.loops.so/api/v1/contacts/delete" --header "Authorization: Bearer $LOOPS_TOKEN" --header "Content-Type: application/json" -d @/tmp/loops_request.json'
Send Event
Trigger an automated email loop by sending an event. Events map to loops configured in your Loops dashboard.
Write to /tmp/loops_request.json:
{
"email": "user@example.com",
"eventName": "signup",
"eventProperties": {
"planType": "free",
"signupSource": "landing_page"
}
}
bash -c 'curl -s -X POST "https://app.loops.so/api/v1/events/send" --header "Authorization: Bearer $LOOPS_TOKEN" --header "Content-Type: application/json" -d @/tmp/loops_request.json'
Docs: https://loops.so/docs/api-reference/send-event
Send Transactional Email
Send a one-off email using a transactional template. Replace <transactional-id> with the ID from your Loops dashboard.
Write to /tmp/loops_request.json:
{
"transactionalId": "<transactional-id>",
"email": "user@example.com",
"dataVariables": {
"firstName": "Jane",
"resetLink": "https://app.example.com/reset?token=abc123"
}
}
bash -c 'curl -s -X POST "https://app.loops.so/api/v1/transactional" --header "Authorization: Bearer $LOOPS_TOKEN" --header "Content-Type: application/json" -d @/tmp/loops_request.json'
Docs: https://loops.so/docs/api-reference/send-transactional-email
List Transactional Emails
bash -c 'curl -s "https://app.loops.so/api/v1/transactional" --header "Authorization: Bearer $LOOPS_TOKEN"' | jq '[.[] | {id, name}]'
List Mailing Lists
bash -c 'curl -s "https://app.loops.so/api/v1/lists" --header "Authorization: Bearer $LOOPS_TOKEN"' | jq '[.[] | {id, name}]'
List Contact Properties
bash -c 'curl -s "https://app.loops.so/api/v1/contacts/customFields" --header "Authorization: Bearer $LOOPS_TOKEN"' | jq '[.[] | {key, label, type}]'
Guidelines
- Contact identity: Use
emailas the primary identifier. Optionally passuserId(e.g., Clerk user ID) to link contacts across systems. - Event names: Must exactly match the event name configured in your Loops dashboard loop trigger.
- Transactional IDs: Find the
transactionalIdin Loops under Transactional > [template] > API. - Rate limit: 10 requests per second per team. Implement exponential backoff on HTTP 429.
- Field length: Maximum 500 characters per field value.
- No CORS: All requests must be server-side — never expose the API key to the browser.
Didn't find tool you were looking for?