Connect Loops to Fondoo
Loops in Fondoo: what your AI agent can do with it, what to set up first, the permissions it needs and its limits.
In Loops open Settings → API and click Generate key (name it for Fondoo); Loops API keys are team-wide with no finer scopes, so use a dedicated key you can revoke. Loops has no API to list all contacts or to send a campaign with HTML, so Fondoo can push subscribers to Loops and trigger events or transactional emails, but cannot import your Loops audience or send Loops campaigns; send those from the Loops dashboard. Transactional sends and events go to one person each; you are responsible for having consent to email that address.
Official documentation: https://loops.so/docs/api-reference/intro
Use add_connection_key without fields for a signed, one-use secure paste page. Then call test_connection and inspect confirmed versus unknown permissions. Direct tool credentials carry a chat-log warning. list_connections never returns credentials.
Auth: api_key (Authorization: Bearer <key>; credential field apiKey, secret). Category: email. Required provider scopes: none (Loops API keys are team-wide and carry no scopes).
Capabilities are discoverable with list_connector_manifests; invoke them through connector_action. Writes retain shared Fondoo scopes, approvals, dry runs, audit, events and metering. Use rotate_connection_key before expiry and delete_connection to remove stored credentials; revoke upstream credentials separately.
What Fondoo does with Loops
Loops is a push-only email platform here: Fondoo can send subscribers, events and transactional emails to Loops, but cannot import your Loops audience or send Loops campaigns (the API has neither). sync_subscribers_from_provider, create_provider_campaign and send_provider_campaign therefore explain that Loops does not support them; sync_subscribers_to_provider works.
Normalized email capabilities:
audiences.list(read):GET /lists; each mailing list becomes{id, name}.subscribers.upsert_batch(write): one lookup per member (GET /contacts/find?email=), then:subscribed, not found:POST /contacts/createwithsource:"Fondoo", optional first/last name split fromname, and the mailing list whenlistIdis given.subscribedis never sent, so Loops' default applies (new contacts are subscribed). Outcomecreated.subscribed, found withsubscribed:falseoroptInStatus:"rejected":skipped_provider_unsubscribed, nothing written. Found and subscribed: only a missing list membership or changed names are written (PUT /contacts/updatewithoutsubscribed); otherwiseunchanged.unsubscribed: only for an existing contact (PUT /contacts/updatewithsubscribed:false, plus the list set tofalsewhenlistIdis given); not found givesunchanged/not_found. Nobody is created just to be unsubscribed.- One execute makes at most 25 Loops requests; members beyond that budget come back as
outcome:"error", message:"batch_limit"and must be resent. 401/403 and 429 abort the batch; other per-member failures areerrorrows.
Vendor-native capabilities:
contacts.find(read, by exactly one ofemail/userId),contacts.suppression(read; suppression status and removal quota).contacts.create(write): validated standard fields plusproperties(custom property names must start with a letter; reserved names are refused).subscribedmay be set only when explicitly supplied.contacts.update(write): looks the contact up first because Loops' update endpoint would otherwise create it. It can setsubscribed:falsebut refusessubscribed:true: re-subscribing must come from the person (a Loops form or dashboard), never an agent.contacts.delete(destructive):POST /contacts/delete; a 404 is reported asdeleted:false.mailing_lists.list,contact_properties.list,contact_properties.create(camelCase names, types string/number/boolean/date).events.send(write): sends only for contacts that already exist (Loops would otherwise create a subscribed contact);eventPropertiesare flat; theIdempotency-Keyheader isidempotencyKeyor the runtime request key. A 409 is reported assent:false, reason:"duplicate_idempotency_key".transactional.list(read) andtransactional.send(write):POST /transactionalwithtransactionalId,email, optionaladdToAudienceanddataVariables(strings, numbers, arrays of flat objects). Attachments are refused. Transactional email is for one person at a time; you remain responsible for having a lawful basis to email that address.
API endpoints used
- Introduction, base URL and auth: https://loops.so/docs/api-reference/intro
- Test API key:
GET /api-key: https://loops.so/docs/api-reference/api-key - Find contact:
GET /contacts/find(empty array when absent): https://loops.so/docs/api-reference/find-contact - Create / update / delete contact:
POST /contacts/create,PUT /contacts/update,POST /contacts/delete: https://loops.so/docs/api-reference/create-contact , https://loops.so/docs/api-reference/update-contact , https://loops.so/docs/api-reference/delete-contact - Suppression:
GET /contacts/suppression: https://loops.so/docs/api-reference/check-contact-suppression - Mailing lists and properties:
GET /lists,GET /contacts/properties,POST /contacts/properties: https://loops.so/docs/api-reference/list-mailing-lists , https://loops.so/docs/api-reference/get-contact-properties , https://loops.so/docs/api-reference/create-contact-property - Events:
POST /events/send: https://loops.so/docs/api-reference/send-event - Transactional:
GET /transactional-emails,POST /transactional: https://loops.so/docs/api-reference/list-transactional-emails , https://loops.so/docs/api-reference/send-transactional-email
Limits and uncertainties
- Rate limit: Loops documents a baseline of 10 requests per second per team; Fondoo budgets 20 executes per minute because one execute may make up to 25 requests. 429 surfaces as
rate_limitedwithRetry-Afterwhen sent. - Only the find-contact page was re-read while writing this guide (confirming the empty-array response and the
subscribed,optInStatusandmailingListsfields); the other endpoint pages are cited from Loops' reference index and were not re-fetched, so verify exact request fields against them. - Uncertain: whether
PUT /contacts/updatewithmailingLists:{id:false}unsubscribes from that list only (it does per Loops' mailing-list documentation) and leaves the globalsubscribedflag unchanged. - Uncertain: the idempotency header applies to event and transactional sends only; contact writes are not idempotent, so retries re-run the lookup first.
- Loops has no member listing API, so provider unsubscribes made inside Loops are only noticed when Fondoo pushes that address again; Fondoo does not poll.
