Integration details
Description
Manage your partner program and access your Partner Data Lake with ChatGPT. Instant actions and answers on deals, commissions, onboarding, and partner performance, no dashboard required. Partners can register deals and access live data across their pipeline, enablement, certifications, payouts and more.
- Integration type
- Plugin
- Verification status
- Not applicable
- Platform
- ChatGPT
- Primary Subcategory
- Partner & Ecosystem Revenue
- Secondary Subcategories
- None listed
- Brand
- EULER
- Access
- Account required
- First tracked
- 2026-09-13
- Tool count
- 52
- Geography
- US
The Primary Subcategory used for this profile’s headline score.
Other Subcategories where the Integration is listed.
ChatGPT Plugin Discovery Score
ChatGPT Plugin discovery is coming soon
ChatGPT can surface a Plugin when it matches a user's request.Your Plugin Discovery Score measures how often yours appears.
No spam. Unsubscribe any time.
What discovery looks like

Competing in ChatGPT Partner & Ecosystem Revenue
View Category52 tools agents can invoke
[Partners — general management] Approves or rejects a PENDING partner-registration application. Approving runs the company's onboarding: it finds or creates the partner and the partner contact from the application's answers, stamps the application approved, syncs to the connected CRM, applies tags and mints an affiliate link. Rejecting stamps it rejected with the reason and the decider. Both are ASYNCHRONOUS — the decision is scheduled, so the response reports application_status 'approving' or 'rejecting' and the application is still pending at the moment it returns. There is no partner_id in the response because none exists yet; wait a few seconds and call partner_applications(action:'get') to confirm the outcome and read partner_id, which invite_partners_to_portal and flows_manage need. accept_scheduled means an accept was scheduled, not that a partner was created — an approve may match an existing partner instead. Only status='pending' applications can be decided, and only once: a second decision on the same application is refused, as is an id belonging to another company, a referral's id (use resolve_referral for those) and an unsubmitted draft. internal_note is stored on the application on both approve and reject and is not shown to the applicant. Rejecting requires a rejection_reason_id when the registration form has reasons configured — list them first with partner_applications(action:'rejection_reasons'); a form with none configured needs no reason. Set send_email to email the applicant, with email_subject, email_body and email_from.
resolve_partner_application
[Partner Relationships] Approve or reject a PENDING referral. Works in both directions, and who may decide depends on the direction — the tool figures this out from the referral itself, you do not pass a direction. Inbound (a partner submitted it to the company): the CUSTOMER decides; approving creates the referral in the company's CRM. Outbound (the company sent it to a partner): the PARTNER decides; approving accepts the lead, reveals the form answers and opens the deal. You can only resolve a referral addressed to you — resolving someone else's returns an authorization error. Find resolvable referrals with referrals(action:'search') as a customer or referrals(action:'for_partner') as a partner; only status='pending' can be resolved, and only once. Rejecting an INBOUND referral requires a rejection reason when the company has them configured — list them first with referrals(action:'rejection_reasons'). Outbound rejections take a free-text note instead. Optionally email the other side about the decision via notify_partner + notification_details.
resolve_referral
[SI Service Projects — Customer Admin] Customer-admin WRITE actions on SI (System Integrator) service projects — approve or reject a partner's project, one at a time or in bulk. The customer company is resolved server-side (NOT an AI input); a project outside your company is not found. action='approve' / 'reject' act on ONE project (require `project_id`) and return a confirmation `{success, project_id, status ('approved'|'rejected'), note_recorded}`. action='approve_batch' / 'reject_batch' act on MANY at once (require `project_ids`, an array of up to 100 ids) — the server fans out per project, each tenant-checked, and returns `results[]` (each `{project_id, status: approved|rejected|not_found|error}`) plus counts. In the batch counts: `processed` = how many were ATTEMPTED on this page (= approved/rejected + not_found + errors), `approved`/`rejected` = how many actually changed state, `not_found` = ids that are not your company's (skipped, no change), and ids beyond 100 come back in `skipped_over_limit` (call again with the next page). Use the batch actions to remediate large backlogs (e.g. junk bulk uploads). `note` is OPTIONAL (applies to every project in a batch call) — on approve it records an approval note; on reject it is the rejection reason surfaced to the partner. IMPORTANT: for REJECTIONS, recommend the customer include a note explaining WHY (so the partner understands and can fix/resubmit) — it stays optional but a rejection without a reason is poor practice. All project ids come from si_customer_service_projects action='list' or 'export'. Read / monitor projects (and their scope forms) with si_customer_service_projects — this tool only changes approval status.
si_customer_manage_service_project
[Partner Directory] Read and author your Partner Directory: read a profile's editable content, add partners to the directory, rewrite a profile's content, and add or remove a profile resource (Testimonial, Resource, Case Study, Client, Video, Top Service, Certification — those exact seven, matched on the option's display text). Takes `profile_id` values from `partner_directory_search` (NOT partner_ids) - except action='add_partners', which takes partner_ids because the profile does not exist yet. action='read_profile' returns the CURRENT value of every field write_profile can set (name, website, short_description, long_description, accepting_clients, hide_contact_button) - it is the only way to read website and the two flags, which no search mode returns. action='write_profile' overwrites ONLY the fields you send: omit a field and its current value is kept, so you never have to restate what you are not changing, and you must never guess a value to fill a slot. accepting_clients and hide_contact_button are the exception - they are always written, so read them first with read_profile and pass them back. Fields this tool does not expose at all (logo, address, languages, custom filter answers, resources) are carried over untouched. A write by a customer admin publishes immediately (status Active); the review queue is for partner-side edits. The public directory is a cached JSON blob refreshed on a ~10-minute cycle, so a change is not visible on the public page immediately. To EDIT a resource, remove it and add it again - editing in place is not offered because a resource carries no link back to its profile, so it cannot be scoped to your directory.
partner_directory_profiles
[Content Management — Customer Admin] Read side of the customer-admin content library. action='search' lists/filters the company's content (ALL content, not just what one partner sees — that's `content_search`/`content_list`) and returns content_id + folder_name + categories for the write actions. action='folders' lists content folders and returns folder_id; folders are FLAT (no nesting). action='categories' lists the company's content categories (id + name) — every content item needs at least one, so call this BEFORE content_manage(action:'create'). Filter values must match EXACTLY what this tool returns for that field (case-sensitive); the backend rejects other spellings. search/folders results include both raw `visibility`/`share_with_all` and a derived `effective_visibility` — trust `effective_visibility` and flag `visibility_conflict:true` items to the user instead of guessing from the raw pair. search and folders results also include `shared_partner_ids`/`shared_tag_ids` — the specific partners/tags an item or folder is shared with; only populated when visibility is 'Selected Partners'/'Partner Tags', empty otherwise (that's expected, not an error).
content_admin
[Partner Relationships] Inspect specific charges (for partner-scoped charge lists, use `partner_artifacts(action: 'charges')`). action='for_deal' returns all charges linked to a deal_id (e.g. 'show me what was charged on deal X', 'list charges for deal abc'). action='by_id' returns the full detail of a single charge — amount, commission, partner, date, status (e.g. 'inspect charge xyz', 'why was this charge created'). Customer-only.
charges_lookup
[Commissions & Payouts] Commission payouts and expense calculations over a date range. action='company' returns the third-person aggregate (e.g. 'how much did we pay', 'our commission expense', 'company-wide payout', 'total spent on partner commissions') — customer-only. action='partner' returns first-person or specific-partner queries (e.g. 'how much commission did I earn this month', 'minha comissão', 'commission owed to <Partner X>', 'partner X earnings') — requires partner_id, callable by partner-role tokens. Partner_id sources for action='partner': `list_accounts` (the user's own partner roles, match by `affiliate_company_name`) or `partners(action: 'list', filter_name: ...)` (customer admin querying their company's partners). IDs from `partner_directory_search` are profile_ids and will be rejected as `partner_not_in_consent`. start_date and end_date are required (no defaults). RESPONSE FIELDS — two different statuses exist, do not confuse them: `commission_status` is the status of the COMMISSION payout, and matches the 'Commission Status' column of the Payments tab. 'Created by Partner' is displayed in the UI as "Awaiting Confirmation" (partner reported the payment, customer has not confirmed it); other values are 'Marked as Paid by Partner', 'Confirmed as Paid by Customer' and the 'Euler Pay - *' states. Empty means no payout activity yet. `customer_payment_status` is NOT about the commission — it is the billing status of the END CUSTOMER's payment for the deal (typically 'paid'). Never use it to say whether a commission was paid. `charge_type` gives the direction: 'Outbound' = a deal YOUR company sent to this partner, so the commission is owed TO YOU (Marketplace 'Sent deals' tab). 'Referral' / 'Reseller' = deals the partner sent you, so YOU owe them ('Received deals' tab). 'Demo' and 'Fund Reimbursement' are neither. `commission_Sum` mixes both directions — never present it as "what this partner owes us". For that use `commission_sum_outbound` (all sent-deal commissions in the period) and `commission_sum_awaiting` (the subset still Awaiting Confirmation). `charge_date` (ISO) is the date the start_date/end_date range filters on, and is what the UI shows as 'Payment Date'. `when_to_be_paid` is frequently empty — do not rely on it. `total_charges` is the row count. `count_outbound` and `count_awaiting` are the row counts matching `commission_sum_outbound` and `commission_sum_awaiting`. Use the provided sums and counts as authoritative; never recompute totals or counts by adding up `list_of_charges` yourself. `list_of_charges` can contain multiple charges for the same `deal_name` (recurring billing, or several charges on one deal). Never merge or deduplicate rows by deal name. Each row is uniquely identified by `charge_id`, and the number of rows you display must equal `count_awaiting` / `count_outbound` / `total_charges` for the subset you are showing. Per charge, `commission_to_be_paid` is the commission for that charge and `amount` is the charge amount it was calculated from — never present `amount` as the commission. A period with no charges returns commission_Sum 0 and list_of_charges [] — that is a valid empty result, not an error. action='company' additionally returns page / limit_per_page / has_more. A response of {"error":"partner_not_found","partner_id":"…"} means the partner_id sent does not match any partner. Re-resolve it via `partners(action:'list', filter_name: …)` and retry. Never report this as "this partner has no commission" or as a zero.
commissions
[Communications Hub] Read-only access to the Communications Hub (partner email program). action='list_audiences' lists the company's audiences with name, active flag, and contact count. action='list_templates' lists email templates (name, description, published). action='list_sent_emails' lists individually-sent emails (recipient, subject, status, opens, clicks). action='emails_by_broadcast' lists the emails sent in one broadcast (requires broadcast_id). action='preview_broadcast' returns how many recipients an audience + template would reach plus a sample of eligible contacts (requires audience_id + template_id) — call this before sending. action='preview_template' renders a template with one contact's data substituted so you can show the final email (requires template_id + sample_contact_id). Everything is scoped to the user's company automatically.
communications
[Communications Hub] Create and send within the Communications Hub (partner email program). action='create_audience' creates an empty partner audience (requires name). action='create_template' creates an email template from raw HTML (requires name + html); the ONLY supported merge tokens are [Contact First Name], [Contact Last Name], [Contact Email], and [Company Contact] — any other token (e.g. {{name}}) is rejected before saving. action='add_contacts' adds up to 100 partners to an audience (requires audience_id + partner_ids); idempotent (partners already in the audience are skipped). action='send_broadcast' sends a template to all eligible contacts of an audience (requires audience_id + template_id + subject + confirm) — this emails real partners and cannot be undone, so call communications(action:'preview_broadcast') first and pass confirm=true only after the user explicitly approves. Everything is scoped to the user's company automatically.
communications_manage
[Partner Relationships] Create or update deals attributed to your partners. action='create'/'update' handle one deal; action='create_batch'/'update_batch' handle many at once. Batch operations are scheduled and run in the background — the response confirms how many were queued (schedule_amount) and does not return the rows; confirm results later with get_search_deals rather than resubmitting. Every deal validates its partner against your company; amount must be greater than 0; close_date must be after created_date. Dates are YYYY-MM-DD.
manage_deals
[Partner Contacts & Portal Invites] Creates a `partner_contact` (a person inside a partner organisation) for a given partner. **Idempotent**: if a contact with the same email already exists for that partner, no duplicate is created — the existing one is returned with `was_created: false`. Use this to add a new person BEFORE granting them portal access with `invite_partners_to_portal` (which takes contact ids, not emails). Returns `{ contact_id, was_created }`. Customer-side only. **Two failure modes** (both safe — nothing created): (1) If `partner_id` doesn't exist at the backend (typo / stale id), rejected upstream with HTTP 400 `dispatch_failed` + a `MISSING_DATA` body — the most common failure for a bad id; ask the user to verify the partner. (2) If `partner_id` exists but belongs to a different company than the caller's, the response is `{status: 'success', response: {}}` (empty body) — the tenant guard terminated. Resolve `partner_id` via `partners(action: 'list', filter_name: ...)` or `list_accounts` (match by affiliate_company_name); IDs from `partner_directory_search` are profile_ids and will be rejected.
create_partner_contact
[Partner Relationships] Creates an affiliate/tracking link for ONE of your company's partners (customer-admin only — partners read their links via `partner_artifacts(action: 'tracking_links')` and cannot create them). Wraps a destination URL with an auto-generated 6-char tracking id (`eid`) and optional URL parameters. REQUIRED: partner_id, url, label. Optional: extras (extra URL query params). Resolve partner_id via `partners(action: 'list')` — the partner must belong to your company. Idempotent by (partner_id, label): a repeated call with the same label returns the existing link without creating a duplicate. Returns `{ link, status, AI_instruction }`: status='Created' (new link, `link` carries the new URL); status='Duplicated' (a link with this label already exists for the partner — `link` is empty but `AI_instruction` contains the existing URL to surface); status='Error' (partner_id is not a partner of your company — `link` empty, `AI_instruction` carries the hint). Confirm the destination URL and label with the user before calling: the link is created immediately.
create_tracking_link
[Performance & Rankings] Returns deal attribution data for a date range: counts and totals for sourced deals (partner-originated), influenced deals (partner-touched), and combined sourced-and-influenced deals — with per-partner breakdowns suitable for ranking. Use for deal-source-attribution questions: counts of sourced/influenced deals, total value of sourced/influenced deals, sourced vs influenced comparisons, and partner rankings by sourced/influenced deal performance. Pass `partner_id` to scope the response to a single partner's attribution (sourced/influenced deals owned by that partner only); omit it for the company-wide view across all partners. For generic partner deal lists without sourced/influenced framing, `partner_artifacts(action: 'deals')` is the right tool; for company-wide aggregates use `performance(action: 'overall')`; for looking up a specific deal by name use `get_search_deals`.
influenced_sourced_deals
[Fund Requests — Customer Admin] [Fund Requests — Customer Admin] Decides on a Marketing Development Fund (MDF) / Co-op Investment Fund (CIF) request a partner has submitted against your company's funds. All three actions require fund_request_id and fund_request_step_id, both from customer_fund_requests(action:'get_request') — fund_request_step_id is current_step.id. action='approve' completes the approval step and moves the request to whatever comes next. action='reject' ends the request: it is marked rejected and does not continue. action='request_info' asks the partner for more before you decide — the request stays open on the same step and flips to waiting on them until they answer, so it is NOT a decision and can be followed later by approve or reject. Only a request whose current_step.type is 'customer approval' can be decided here, and only by a user configured as an approver for that step; any other step or a non-approver is refused. notes_public is visible to the partner (use it to say why, especially on a rejection); notes_private is an internal note the partner never sees. Completion is processed in the background, so after deciding, read the request back ONCE with customer_fund_requests(action:'get_request') after a short pause rather than repeating the call.
customer_fund_requests_manage
[Content Search] EULER product help & support search — THE tool for any question about how EULER itself works or how to do something in the EULER product: 'how do I add a user', 'how do I submit a referral', 'where do I find X in the portal', 'how does EULER work', 'what is <EULER feature>', 'how do I set up Y'. Searches EULER's public help center / support articles (the support.eulerapp.com knowledge base) and returns the matching article text plus a citable `article_url`. ALWAYS call this before telling the user you can't find a procedure or that there's no documentation — do not guess generic SaaS steps. Needs only the question — no partner_id or other context. (To semantically search a partner's privately-shared content instead, use `content_search`; to list a partner's files by name, use `content_list`.)
euler_help
[Conversation Insights] Lists the company's own support CONVERSATIONS behind a problem area — the same data as the dashboard's trending-topics and resolution-by-category views. Give a category OR a trending topic (exactly one), optionally a resolution outcome and a time window, and it returns the matching conversations (newest classified first) with their resolution outcome. Use it when the user asks to see, pull up, or list conversations / chats / support threads about something. Each conversation also carries who it is with: userName, userEmail, partnerName, partnerId, the partner's crmId (the CRM record id, null when the partner has no CRM link or the conversation has no partner) plus crmType (which CRM that id is from — e.g. Salesforce / Hubspot — so you can label or link it correctly), partnerDomain (the partner company's own domain, e.g. acme.com), and companyName (the company the user belongs to). Returns totalCount (exact) and capped (true when only the first page is shown). When capped, say 'M total, showing the first N'. If available is false the lookup failed — say so and suggest trying again; never report zero as if genuine.
find_conversations_by_problem
[Flows — onboarding & training lifecycle] Read Flows (onboarding / training / certification programs), their steps, assignments, and attachable resources. Customer-admin actions: action='list' returns all the company's flows as {id, name, status} records (newest first; no server-side filters — filter the returned list yourself by name/status) — the discovery entry point when you don't have a flow_id yet; drill into one with action='flow_details'. action='list_standard' returns the company's Standard Flows — the default flow set automatically assigned to partners when they join the portal — as {id, flow_id, flow_name, completion_rule, status} records; `id` is the flow_standard_id used by flows_manage(action:'remove_standard'), and `status` distinguishes active from archived (removed) entries. action='flow_details' returns flow/step details — name alone searches flows by title (returns matching flow IDs), flow_id alone returns that flow's details plus its assignments and step IDs, flow_step_id alone returns that step's details; pass at most ONE of name/flow_id/flow_step_id per call (combining them makes it return only the first matching intent and silently drop the rest), so drill down in separate sequential calls (name → flow_id → flow_step_id). The returned can_be_updated_now shows whether the flow's steps/content can be edited ('no' while Active); it does NOT affect assigning. A flow's status is Draft (creation), Active (published), Unpublished (an Active flow taken down to edit — not Draft), or Archived (retired and locked: it can neither be assigned nor edited). action='attachable_resources' lists content/agreement/quiz items embeddable in a step (requires entity_key ∈ content/agreement/quiz — Task/File Upload/SCORM/Text are valid step types but have no attachable-resource pool); returned ids feed flows_manage(action:'create_or_edit_step') via content_id / agreement_term_id / quiz_from_schema_id. action='assignment_candidates' lists partners/users assignable to a flow (requires partner_id; optional email resolves one user's id). action='assignments' returns the company's flow-assignment roster (optional filters: partner_id → that partner's flows, flow_id → that flow's partners); response has results (current page) and grouped_by_partners (same data grouped per partner) as comma-joined text payloads to parse before presenting, plus total_count / total_for_this_page / has_more. Each result row carries user_id/user_email (the specific team member — populated for the 'All users…' and 'Specific users…' completion rules; blank for the 'Any user…' rule, which completes at the team level) alongside progress_status, so filtering by flow_id gives a per-user completion roster of who finished. action='recipient_count' is a read-only dry-run of an assignment: pass the same audience inputs as flows_manage(action:'assign') (flow_id + assign_to + completion_rule, plus selected_partner_ids / tag_ids / partner_user_pairs as the combo requires) and it returns how many partners/recipients would receive the flow (new_count) WITHOUT assigning — use it to confirm 'N partners will receive this' before calling flows_manage(action:'assign'). Partner actions (partner-role sessions): action='partner_flow_details' returns the calling partner's assigned flows/steps (requires partner_id; optional flow_id / name / flow_step_id drill-down, mutually exclusive); action='partner_flow_progress' returns per-flow completion stats for the partner (requires partner_id + flow_id). action='partner_team_progress' returns the calling partner's flow-assignment roster with per-user completion (requires partner_id; two OPTIONAL filters — flow_id scopes to one flow, and target_user_id scopes to one team member's assignments; omit both for the full roster across every flow and user, including the team-level 'Any user…' flows open to the whole company) — admin-only: a partner user without an admin role gets an authorization error. Each row has user_id/user_email + progress_status + completion_rule (plus flow_id, flow_name, partner_id, assignment_id, partner_flow_status; 'Any user…' assignments have a blank user, being team-level), and the response adds total_count / has_more / total_for_this_page. Resolve partner_id via list_accounts (partner-role) or partners(action:'list') (customer-admin querying a partner of their company).
flows
[Flows — onboarding & training lifecycle] Create, edit, and manage Flows and their steps + assignments (customer-admin only). action='create_flow' creates a flow (requires name, description, type, enable_due_date; optional due_date_days). action='save_flow' saves/activates/publishes/archives a flow (requires flow_id, flow_status; optional name, description, type, enable_due_date, final_order, and certification_badge_b64 — a base64 image required to ACTIVATE a Certification flow: activating a Certification flow without a badge is blocked). action='create_or_edit_step' creates/edits a step (requires flow_id, name, description, os_flow_step_type, order_temp, entity_key='create'|'edit'). action='deactivate_step' enables/disables a step (requires flow_id, flow_step_id, step_status, entity_key='step', and flow_status — the flow's CURRENT status). This is a staged edit: it changes the step on the flow but does NOT update partners already assigned to the flow — that happens only when the flow is saved. After calling it, tell the user the change won't reach existing/in-progress assignments until the flow is saved, and ask whether to save now; call action='save_flow' only once the user confirms (do not save automatically). action='assign' assigns a flow (requires flow_id, assign_to, completion_rule, and confirm=true). assign_to picks which partners receive it: 'All Partners' (whole company), 'Selected Partners' (needs selected_partner_ids), or 'Partners by Tags' (needs tag_ids). completion_rule is how the partner's team completes it; the 'Specific users…' rule works only with assign_to='Selected Partners' and needs partner_user_pairs (each 'partner_id|user_id'). Assigning notifies the targeted partners, so it is confirmation-gated: first call flows(action:'recipient_count') with the SAME inputs to get how many partners/recipients will receive it, tell the user that number, and ask them to confirm; only after the user agrees, call assign with confirm=true. An assign call without confirm=true is rejected with assignment_confirmation_required and does nothing. action='unassign' removes an assignment (requires flow_id, entity_key='all'|'partner'|'user'). assign/unassign are actions you perform (not stored settings), allowed while the flow is Draft, Unpublished, or Active — identical in all three (an Active flow behaves the same whether or not it already has assignments) — and they NEVER require unpublishing. An Archived flow is locked: it can be neither assigned nor edited. A `can_be_updated_now` value of 'no' from flows(action:'flow_details') concerns editing the flow's steps/settings, not its assignments. To edit an Active flow's steps/settings, unpublish it (save_flow flow_status='Unpublished' — it becomes Unpublished, NOT Draft; Draft is only the initial creation state), make the changes, then republish (flow_status='Active') to re-propagate them to existing assignments. action='add_standard' adds a flow to the company's Standard Flows — the default set auto-assigned to every partner when they join the portal (requires flow_id and standard_completion_rule). It is idempotent: re-adding a flow already in the set just re-activates it, so it never creates duplicates. standard_completion_rule offers only two options ('Any user…' or 'All Users…'); the 'Specific users…' rule is not available for standard flows. action='remove_standard' removes a flow from the standard set (requires flow_standard_id — the `id` from flows(action:'list_standard'), not the flow_id); it archives the entry rather than hard-deleting, so re-adding restores it. Read the current standard set with flows(action:'list_standard'). To read flows, steps, assignable candidates, or the assignment roster, use `flows`.
flows_manage
[Fund Requests — Customer Admin] [Fund Requests — Customer Admin] Reads the Marketing Development Fund (MDF) / Co-op Investment Fund (CIF) requests your partners have submitted against your company's funds. action='list_requests' lists every request across all your partners (optional filters: partner_id to narrow to one partner, request_name to find one by its request/campaign name, fund_id, fund_type MDF|CIF, status, period dates); each row has an id, name, fund, amount_total, status, and pending_action_from — 'customer' means it is waiting on YOU, 'partner' means you are waiting on them. action='get_request' returns one request in full detail (requires fund_request_id): amounts, the ordered steps[], request_info with the answers the partner submitted, your internal notes, and current_step — the pending task, its type ('customer approval' | 'partner fill form' | 'partner upload' | 'partner execution' | 'customer upload' | 'reimbursement' | 'assign deal to cif'), and any additional information already requested. action='list_funds' lists the funds your company offers (optional filters: fund_id, fund_type, status, period dates). The normal loop is list_requests (find what is waiting on you) → get_request (read the detail and the partner's answers) → customer_fund_requests_manage (approve, reject, or ask for more information). Only a request whose current_step.type is 'customer approval' can be decided through the assistant; a request sitting on 'customer upload', 'reimbursement' or 'assign deal to cif' is waiting on your team but must be finished in the EULER portal.
customer_fund_requests
[Conversation Insights] Opens ONE support conversation (by id, from a find_conversations_by_problem result) and returns its messages plus the resolution outcome, so you can summarize it: what the user asked, what happened, and how it resolved. Also returns an `identity` object with the full party behind the conversation — userName, userEmail, partnerName, partnerId, crmId, crmType (the company's CRM, e.g. Salesforce/HubSpot/Pipedrive), partnerDomain (the partner company's own domain, e.g. acme.com), and companyName; partner/CRM fields are null for internal conversations (no partner). If found is false, that conversation does not exist or is not part of this company — tell the user you could not find it; do not invent its contents. If available is false the fetch failed — say so and suggest trying again.
get_conversation_detail
[Partner Relationships] Returns your company's OUTBOUND referral form — the form_id and its questions — used to send a referral TO a partner via send_outbound_referral. It is company-scoped (reads your own company's outbound form) and takes no partner_id; the per-partner INBOUND form is referrals(action: 'get_form_for_partner') instead. Call this to discover the form_id and question list before collecting the user's answers, then pass the answers (each keyed by its question id) to send_outbound_referral.
get_outbound_form
[Partner Relationships] Returns artifacts linked to a specific partner. All actions require partner_id. To resolve partner_id, prefer (a) `list_accounts` (when the user has an account with that partner, match by `affiliate_company_name`) or (b) `partners(action: 'list', filter_name: ...)` (customer admin querying their company's partners). From `partner_directory_search`, the item's `id` is a profile_id and will be rejected as `partner_not_in_consent` — the SAME item also carries `partner_id`, which is the id to pass here. Empty on a profile whose partner link was never set; treat that as unknown. action='agreements' returns signed agreements; 'tracking_links' returns affiliate links; 'deals' returns the partner's deals (paginated); 'charges' returns charges assigned to the partner (paginated); 'invoices' returns the partner's invoices (paginated).
partner_artifacts
[Incentives] One page of the company's incentive roster — ONE ROW PER ACTIVE INCENTIVE ASSIGNMENT, each row naming the partner and their current incentive: `partner_id`, `partner_name`, `program_name`, `tier_name`/`tier_order` (null on Inc 1.0 — packages have revenue ranges, not tiers), `enrolled_on`, `commission_lines`, and `commission_pct`. Use for program-wide incentive questions: 'which incentive is each partner on', 'list partners by tier', tier-migration comparisons. `commission_pct` is the partner's rev share ONLY when their tier has exactly one commission line (`commission_lines: 1`); with several product-group/range/period lines it is null — there is no single percentage, so drill into that partner with `partner_inc2_incentives(action: 'status')` instead of guessing. A partner ABSENT from the roster has no active incentive assignment (the full partner list lives in `partners`). The response also carries `program_version` ('2.0' or '1.0', decided by the company's incentive system), `direction`, `total_count`, `page`, `limit`, `has_more`. Paginate with page/limit (limit max 50); `direction` defaults to 'inbound' (what the company pays its partners) — pass 'outbound' for the reverse flow. For company-wide aggregates use `incentives_summary`; for one partner's full detail (benefits, campaigns, progression) use `partner_inc{1,2}_incentives`.
incentives_roster
[Incentives] The company's incentive programs with per-tier enrollment counts — BOTH incentive systems in one list. Returns `tier_counts[]`, one row per tier/package with `program_version`, `program_name`, `tier_name`, `tier_order`, `count`. Inc 2.0 rows (program_version '2.0'): one per tier of each program, count = ACTIVE inbound assignments on that tier. Inc 1.0 rows ('1.0'): one per tier package, `tier_name` null (packages have revenue ranges, not tiers), count = DISTINCT partners on the package — the same number the Incentives dashboard shows. A count of 0 means the tier/package exists and nobody is on it; a company is on exactly one system, so all rows share one program_version. Use for aggregate questions: 'how many partners are on tier X / each incentive', tier distribution before a migration — ONE call, never paginate the roster to count. For the partner-by-partner list use `incentives_roster`; for one partner's detail use `partner_inc{1,2}_incentives`. (The `program-version`/`Inc_1_results`/`Inc_2_results` fields are a legacy per-partner view — meaningless without a partner context; ignore them and read `tier_counts`.)
incentives_summary
[Partner Contacts & Portal Invites] Invites one or more EXISTING partner_contacts (by their contact ids) to a partner's portal in a single call. Get the ids from `list_partner_contacts` (the `id` in each contact object) or by creating them first with `create_partner_contact`. The backend reuses the partner's single `externally_invited_user_mapping` (or creates it on the first invite), then adds a per-contact invitation and sends the invitation email; if a contact's email already corresponds to a Euler account, portal access is granted immediately, otherwise on accept. **Idempotent per contact**: a contact already invited is not duplicated or re-emailed. Optional `agreement_id`, `restrict_access`, and `tags` mirror the in-app bulk-invite. Returns `{ success, invited_count, mapping_existed }` (`invited_count` = number of contact ids submitted; the actual sends happen asynchronously). Customer-side only. **Failure modes** (all safe): (1) invalid `partner_id` → HTTP 400 `dispatch_failed` + `MISSING_DATA` body. (2) `partner_id` of a different company, OR an EMPTY `partner_contacts` list → `{status: 'success', response: {}}` (empty body) — a guard terminated the workflow before anything was created. Resolve `partner_id` via `partners(action: 'list', filter_name: ...)` or `list_accounts`.
invite_partners_to_portal
[Account Management] Returns the customer + partner accounts the user approved during the MCP consent screen. Call this first when you need to resolve a partner by name or when the user has multiple roles. Each entry has: id, type ('customer' | 'partner'), name, company_id, partner_id (null for customer), affiliate_company_name (partner only — the customer company hosting the partnership), and dashboard_url (the canonical EULER web-app URL for this account's role — use this when the user needs to do something MCP doesn't expose, like creating an incentive program; customer accounts point to /dashboard, partner accounts to /partners). To resolve a partner by name, match `type === 'partner'` AND `affiliate_company_name === <target>`; use that entry's `partner_id` for referrals / partner_artifacts / performance / commissions. Response also includes `consent_summary` with `hidden_count` — if non-zero, some user accounts were not authorized in this session; ask the user to disconnect/reconnect to include more rather than guessing. Downstream tools auto-resolve partner_id to its company_id, so you only need to pass partner_id. IF the response includes a `backend_data_issue` field (only ever present when the backend returned zero accounts for a provisioned user), this is a backend data anomaly, NOT a consent problem — do NOT suggest disconnect+reconnect; surface the support_email from that field and offer to continue with other tools (partners, performance, commissions) which read directly from the user's company and may still work. When the user asks to do something this MCP doesn't cover (creating incentives, billing/account settings, adding new partners from scratch), surface the matching account's `dashboard_url` instead of guessing a URL.
list_accounts
[Partner Contacts & Portal Invites] Returns the contacts (people) associated with a specific partner — the COMPLETE team roster, including people who never logged into the portal (unlike `partner_users` action='list_users', which returns only the subset with an activated login). Customer-admin view only. Resolve `partner_id` via `partners(action: 'list', filter_name: ...)` or `list_accounts` (match by affiliate_company_name); IDs from `partner_directory_search` are profile_ids and will be rejected. Pair with `create_partner_contact` (to add a new person) and `invite_partners_to_portal` (to grant portal access). Returns `contacts_count` (number) plus `contacts` — a comma-separated string of compact JSON objects, one per contact, each with `id`, `email`, `first_name`, `last_name` (e.g. `{"id":"..","email":"..","first_name":"..","last_name":".."},{..}`). Use the `id` values directly as input to `invite_partners_to_portal`. NOTE: the `contacts` string is NOT wrapped in `[ ]` — wrap it yourself if you need a strict JSON array.
list_partner_contacts
[Content Search] Lists the actual content/files a partner has access to in their Partner Portal — PDFs, Word docs, images, uploaded videos, and external links (YouTube, Vimeo, Loom, Google Drive), newest first. Use for 'what content/files do I have', 'list my documents', 'show the PDFs shared with me', 'do I have a deck about X'. Returns each item with name, description, file_type, a URL (file_url for uploaded files OR link for external), cover image, size, `created_date`, and `is_downloadable`. IMPORTANT — `is_downloadable: false` does NOT mean the partner can't see the item: they may VIEW it in the Partner Portal's Content section, they just may not download the file. For those items, describe the content and point the user to the Content section of their Partner Portal — do NOT hand out `file_url` as a download link. (`is_downloadable` governs only `file_url`, the uploaded file; an external `link` such as YouTube/Vimeo/Drive is always fine to share, since viewing happens at the destination.) Also note a `file_url` generally opens only inside an authenticated Partner Portal session — if the user reports an access/permission error on the link, do not retry it or claim the content is missing: tell them to open it from the Content section of the portal. Pass `partner_id` (resolve via `list_accounts` for partner-role, or `partners(action: 'list', filter_name: ...)` for customer-admin). Optional `query` matches by WHOLE WORD, case-insensitive — not a substring (confirmed live 2026-08-13, QA finding M-01: 'ickson' will NOT match 'PPTX Dickson' — pass the full word, e.g. 'Dickson') — omit it (or pass '') to list everything. This is direct catalog retrieval; for conceptual 'how does X work' / documentation lookups that search INSIDE content, use `content_search` (semantic) instead. IDs from `partner_directory_search` are profile_ids and will be rejected.
content_list
[Content Management — Customer Admin] Write side of the customer-admin content library. action='create' adds a content item ('File' needs file_url from content_upload; 'Link' needs link) — every item needs at least one category_id from content_admin(action:'categories'). action='create_folder' adds a folder (FLAT, no nesting). action='add_to_folder' places or moves an existing item. action='edit' updates metadata and/or replaces the file/link — omitted fields keep their CURRENT value (the worker fetches the record first), and category_ids REPLACES the whole list when passed. action='change_visibility' / 'change_folder_visibility' set who can see an item or a folder; omitted visibility is preserved, and omitted share_with_all is preserved UNLESS visibility is explicitly changed away from 'All partners', which resets share_with_all to false (a visibility restriction always wins over a stale share_with_all — pass share_with_all explicitly to control it directly). partner_ids/tag_ids REPLACE the share list while add_partner_ids/remove_partner_ids change it incrementally (ignored when partner_ids is set). share_with_all=true exposes the content to EVERY partner and is confirmation-gated: tell the user what it means, get their agreement, then retry with confirm=true (without it the call is rejected with share_with_all_confirmation_required and nothing changes). action='delete' permanently removes a content item (and its category/folder links) — irreversible, confirmation-gated like share_with_all (rejected with delete_confirmation_required without confirm=true). action='archive_folder' hides a folder for good — also irreversible and confirmation-gated (archive_confirmation_required); the content that was inside it is NOT deleted or touched, it just loses that folder's organization. Get ids from content_admin.
content_manage
[Partner — Users & Roles] Creates and modifies a partner organisation's permission roles, and assigns/removes them for members. action='create_role'/'edit_role'/'assign_roles'/'remove_roles'/'update_default_roles' work for BOTH a partner-admin managing their OWN team AND a customer-admin managing a partner of their company — ⚠️ AS A CUSTOMER-ADMIN, these writes change the roles and portal access of users in ANOTHER company (your partner's organisation); BE CERTAIN and confirm the intent with the user first. **action='add_user' and action='invite_user' are PARTNER-ONLY — a customer-admin cannot call them (they fail with a scope error), even on a partner of their own company.** action='add_user' creates one or more partner_contacts from emails (requires partner_id, emails[], up to 50 per call); optional role_ids[] (assigning roles requires the caller to be a partner admin), send_invite (boolean, default false — true also emails each new contact a portal invite). Contacts are created immediately for emails not already on the team; already-existing emails are skipped (skipped.emails). **`affected_ids` is always empty for add_user** — the new contacts are created asynchronously after this call returns, so their ids don't exist yet at response time; call `list_partner_contacts` afterward to look them up by email. action='invite_user' sends a portal invite to a partner_contact that already exists (requires partner_id, contact_id — get contact_id from `list_partner_contacts`). action='create_role' creates a role (requires partner_id, role_title, category); optional: have_admin_permissions ('yes'/'no'), enable_all_sections ('yes'/'no'), default_sections[] (portal sections the role may see), custom_sections[] (custom partner-portal section ids). action='edit_role' edits a role — only the fields you pass change (requires role_id; same optional fields as create). action='assign_roles' assigns one or more roles to one or more members BY EMAIL (requires partner_id, emails[], role_ids[]); keep_old_roles (boolean): true ADDS to the members' current roles, false REPLACES them. **The emails must be people already in this partner's team — find them via `list_partner_contacts` (the full team roster), NOT via `partner_users` action='list_users' (which returns only the few people who have an activated portal login). An email that isn't one of the partner's contacts is silently skipped.** action='remove_roles' removes ONE role from ONE member (requires partner_id, email, role_id); remove_all_roles (boolean) strips ALL of that member's roles instead. action='update_default_roles' sets which roles new members are auto-assigned (requires partner_id, role_ids[]). Get role ids from partner_users action='list_roles'; `category` is one of the partner role categories (e.g. Partnerships, Sales, Marketing, Finance, Support). partner_id comes from list_accounts.
manage_partner_users
[Partner Directory] Moderate your Partner Directory: approve or reject a partner's profile edit, hide or unhide a profile, flag it as featured, or set its tier. Takes one or more `profile_ids` from `partner_directory_search` (NOT partner_ids). Only profiles in YOUR directory can be changed — ids belonging to another customer are silently not matched, and the response says how many actually applied. Rejecting requires `rejection_message`, which the partner reads. 'unhide' restores the status the profile had before it was hidden, so it only works on a hidden profile; 'hide' only works on a profile that is not already hidden. The public directory is a cached JSON blob refreshed on a ~10-minute cycle, so a change is not visible on the public page immediately. The valid values for `tier` come from your directory settings and are not readable through MCP yet — an unrecognised tier is written verbatim and will show as a tier no filter offers.
partner_directory_manage
[Partners — general management] Diagnoses why access to the partner portal (or a specific section) is blocked. Returns, in one call: flow locks (which flow is gating access, progress, due date, locked sections), pending agreements that block access until signed, and invitation status (invited, email status, activated). Returns healthy=yes when nothing is blocking. As a PARTNER, use it to diagnose YOUR OWN access ("why can't I see the agreements tab?", "nothing loads in the portal", "I can't open X") — do NOT pass partner_id and do NOT ask the user for one; the caller's own partner is used automatically. As a CUSTOMER admin, pass the `partner_id` of one of your partners to diagnose them ("why can't partner X access/see Y?", "did partner X receive the invite?"). Pass `section` only when a specific portal area is named. Prefer this tool over guessing at bugs/permissions or returning a raw authorization error: name the blocking flow / unsigned agreement / pending invite and the concrete unblock step. Never invent a URL, id, or date.
partner_access_diagnosis
[Partners — general management] Reads partner-registration applications (partner signups awaiting or past a decision) for the user's company, including the applicant's contact details and every answer they gave on the registration form. action='list' returns applications newest first, paginated by offset/limit, optionally filtered by status and a submitted-on date range. action='get' returns one application in full (needs application_id) and is the only mode that includes the `answers` array. Every row carries the applicant's identity as first_name, last_name, email_address, company_name, website, phone_number and country — these are resolved from the form's mapped questions, so they are reliable regardless of the order the questions appear in. company_name falls back to the company name typed on the application when the form has no question mapped to it. A field with no value comes back as null. `status` is free text on the record; the values seen in practice are 'pending', 'approved', 'rejected' and 'error writing to crm'. Half-filled forms the applicant never submitted have status 'draft' and are excluded from both modes, so filtering for status='draft' returns nothing — that is the filter, not evidence that no drafts exist. Answers whose question was deleted are excluded. An answer on a question the program marked hidden may still be returned — that filter is pending a platform privacy change, so do not rely on it to withhold an answer. An application_id belonging to another company returns an empty list rather than an error. action='rejection_reasons' lists the rejection reasons configured on that application's registration form (needs application_id); call it before rejecting via resolve_partner_application. It returns `rejection_options` as {id, reason} and a `reason_required` flag — when the form has no reasons configured the list is empty and no reason is needed; a response with NO `reason_required` field means the configured reasons could not be read, so do not treat it as 'no reason needed' — read them again before rejecting. If a row carries `answers_unreadable: true`, that application's answers could not be read: the seven identity fields on that row are null because they are derived from the answers, NOT because the applicant left them blank — say the answers could not be read rather than describing an empty application. Decide an application with resolve_partner_application. This payload contains personal contact information for real people.
partner_applications
[Partner Incentives] Get a partner's active Inc 1.0 incentive plan. Requires partner_id — the data is scoped to THAT partner, not the logged-in user. action='status' returns: package name, payout frequency, net days post payment, and the commission tiers as `tiers[]` — each tier has name, min/max revenue range, commission_pct (%), flat_payout (fixed fee), and net_days. Use when a partner asks about their own commission structure, tier package or payout terms, or when a customer admin asks about one of their partners'. Returns found=false if this partner has no Inc 1.0 plan.
partner_inc1_incentives
[Partner Incentives] Get a partner's Inc 2.0 incentive program data. Requires partner_id — the data is scoped to THAT partner, not the logged-in user. action='status' returns the current tier (`tier_name`, `tier_badge`, `tier_badge_color`, `tier_order`), `program_name`/`program_status`/`progression_type`, `payout_frequency`, plus three flat lists: `commission_structure[]` — one row per product-group × revenue-range × time-period, each row with `group_name`, `all_products`, `range_min`, `range_max`, `is_max_infinite`, `fixed_payout`, `demo_payout`, `net_days`, `period_months`, `commission_pct`; `benefits[]` — the current tier's non-monetary benefits (`property_name`, `type`, `answer_text`/`answer_bool`/`answer_number`/`answer_select`); and `active_campaign[]` — 0 or 1 active temporary boost/override campaign (`name`, `type`, `date_start`, `date_end`, `boost_pct`, `boost_fixed`, `override_tier_name`). action='progression' returns `current_tier_name`/`current_tier_order`, `program_tiers[]` — every tier in the program (`tier_name`, `tier_order`, `tier_badge`, `badge_color`), `at_highest_tier`, `next_tier_name`/`next_tier_order` (the next tier above the partner's current one), `all_tiers[]` — one row per advancement rule across the program's tiers (`tier_name`, `tier_order`, `logic`, `metric`, `operator`, `value`, `period`) — and `live_metrics[]` — the partner's live progress, EACH ROW already carrying its rule + which tier it belongs to: `tier_name`, `tier_order`, `logic`, `metric`, `operator`, `goal` (the rule's threshold), `calculated` (current value), `passing`, `period`. Returns found=false if no Inc 2.0 assignment exists. To explain what's needed to reach the next tier, filter `live_metrics[]` by `tier_name === next_tier_name` — each row is a requirement with its target (`goal`), current progress (`calculated`), and whether it's met (`passing`). `all_tiers[]` is the full rule catalog per tier (use it for tiers that have no live metric yet); `live_metrics[]` is the one that carries progress.
partner_inc2_incentives
[Performance & Rankings] Partner performance metrics and rankings over a date range. action='overall' ranks all partners (e.g. 'top 5 partners', 'best performing partners', 'leaderboard', 'highest performers', 'partner ranking') and REQUIRES start_date, end_date, page, limit, and entity_key. Dates use YYYY-MM-DD format (e.g. '2024-04-07') — NEVER include a time component; full ISO 8601 datetimes are silently mis-parsed downstream and return corrupted years. When the user doesn't specify a window, default start_date to today − 90 days and end_date to today. Pagination defaults: page=1, limit=10. entity_key selects the ranking metric — pass 'revenue' for closed-won/invoiced revenue ($) questions (top sellers, biggest accounts, highest revenue contributors) and as the default for generic performance questions; pass 'deals' only when the question is specifically about deal COUNT (most deals closed, most wins). 'overall' is terminal — it returns ranking plus aggregate metrics in one call, considering deals only (no commissions data); subsequent partner_artifacts/commissions calls aren't necessary unless the user asks for more depth. action='partner' returns a single partner's metrics — requires partner_id, callable by partner-role tokens. action='company' returns the user's own company aggregate (sales/deals/charges) — customer-only. Disambiguation when the user names an entity: if the name matches the user's own company (`list_accounts` entry where `type==='customer'` AND `name===<asked>`), use action='company'. If it matches an `affiliate_company_name` in `list_accounts` OR a partner of the user's company, use action='partner' with that partner_id. Partner_id sources for action='partner': `list_accounts` (match by `affiliate_company_name`) or `partners(action: 'list', filter_name: ...)`. IDs from `partner_directory_search` are profile_ids and will be rejected as `partner_not_in_consent`.
performance
[Dashboards — Program-wide Overview] Single-call executive snapshot of the company's partner program. Returns total partner count (all), active partner count, pending partner count, total deal count, won deal count, total revenue (sum), and the top 100 partners ranked by revenue. Use when the user wants a quick at-a-glance picture of the program (e.g. 'give me a program overview', 'how is our partner program doing overall', 'top performers'). Customer-side only; scoped to the caller's company automatically. For ranking by date range / pagination, use `performance(action: 'overall')` instead — this tool is unfiltered and lifetime-to-date.
get_partner_overall_stats
[Partner — Users & Roles] Reads the users and permission roles of a partner organisation. Works for BOTH a partner-admin reading their OWN team AND a customer-admin reading one of their company's partners. action='list_users' returns ONLY the partner's people who have an activated EULER portal login, as `users[]` (each: id, email, first_name, last_name, roles); requires partner_id. ⚠️ This is NOT the partner's full team — most partner people are contacts who were never invited or never logged in and do NOT appear here, so a partner with hundreds of contacts may legitimately return only a handful of users (or zero); that is correct, not a truncation. For the COMPLETE team roster (everyone, with or without a login) use `list_partner_contacts`. action='list_roles' returns the partner's permission roles as `roles[]` (each: id, role_title, category, have_admin_permissions, all_sections_enabled, default_sections_enabled, custom_sections_enabled, qty_users_assigned); requires partner_id. action='get_default_roles' returns the role(s) auto-assigned to new members (same role shape); requires partner_id. Everything is tenant-isolated by privacy rules — you only ever see your own partner account (partner-admin) or a partner of your own company (customer-admin). partner_id comes from list_accounts. NOTE: `list_roles`'s `qty_users_assigned` counts how many of the partner's CONTACTS hold each role, so its total is typically far larger than `list_users` (which is only logged-in users) — they are different populations and are NOT expected to match.
partner_users
[Diagnostics] Returns pong + echoes the caller's identity (user_id, company_id, partner_ids, roles). Useful for smoke-testing the auth chain.
ping
[Invoices] Query invoices at the company level. action='list' returns invoices with advanced filters (status, currency, date range, sort, descending); 'summary' returns aggregate totals by status (paid/pending/processing) — use for 'how much was invoiced', 'total revenue', invoice aggregate questions.
company_invoices
[Partners — general management] Query partners of the user's company (customer-admin view). action='list' searches by name (filter_name='<name>') and returns partner_id values usable in referrals / partner_artifacts / performance / commissions. If the user is asking about a partner where they themselves have an account (they are a partner OF that company), prefer `list_accounts` matched by affiliate_company_name. action='pending' returns partners awaiting approval. action='summary' returns company-wide aggregate metrics broken down by partner status — this is the canonical source for company-level partner-status / partner-count questions like 'how many partners are active?', 'how many active partners do we have?', 'partner status breakdown', 'partner totals'. Generic mentions of partner status refer to the company's partner roster and belong here; route to `partner_directory_search` ONLY when the user explicitly mentions the Partner Directory (which uses a separate profile-status concept). The summary result is stable across a conversation, so call it at most once per conversation when needed. action='tags' lists the company's partner tags (partner groupings) as {id, name} records — feed the returned ids into flows_manage(action:'assign', assign_to:'Partners by Tags', tag_ids:[...]) or invite_partners_to_portal(tags:[...]).
partners
[Partner Relationships] Query existing referrals / deal-registrations. action='search' returns the company's referrals in BOTH directions — inbound (received FROM partners) and outbound (sent TO partners) — with optional partner_id filter, date range, status and `direction`. Each row's `approval_type` states its direction, and `total_referrals_received_from_partner` / `total_referrals_sent_to_partner` count each side of the full result (not just the returned page); treat those counts as authoritative. For questions like 'pending outbound referrals' pass direction='outbound' (+ filter_status); 'which partner sent us the most referrals' is direction='inbound'. action='for_partner' returns ONE partner's referrals in BOTH directions (paginated) — what that partner submitted to the company AND what the company sent to that partner — narrowable with `direction`. Each row's `approval_type` states its direction, and `total_referrals_you_submitted` / `total_referrals_sent_to_you` count each side of the full result (not just the returned page); treat those counts as authoritative. Those two field names are written from the PARTNER's point of view even when a customer admin makes the call — 'you_submitted' is what the partner sent the company (inbound), 'sent_to_you' is what the company sent the partner (outbound). action='get_form_for_partner' returns the referral-form question schema a partner must fill in — call this before `submit_referral` to discover form_id + questions[]. Each question carries an `answer_field` ('answer_text' | 'multiselect_options') telling you exactly which field to put its answer in (only true multi-select uses multiselect_options; everything else, dropdown included, uses answer_text). The response also includes `question_count` and a `presentation_guidance` string with formatting tips for displaying the questions cleanly to the user — follow it, especially for long forms. action='get_answers' returns the form answers submitted with a specific referral (requires approval_id — obtain it from a prior `search` (POPs / customer-side) or `for_partner` (PAM / partner-side) call; each referral record carries the identifier). action='rejection_reasons' lists the valid rejection reasons for a referral; call it before rejecting via resolve_referral. Partner_id sources: `list_accounts` (the user's own partner roles) or `partners(action: 'list', filter_name: ...)` (customer admin querying their company's partners). From `partner_directory_search`, the item's `id` is a profile_id and will be rejected — use the same item's `partner_id` field instead (empty when the profile's partner link was never set). Use `submit_referral` to actually send a new referral after collecting answers.
referrals
[Flows — onboarding & training lifecycle] Read quizzes and their questions (customer-admin only; a quiz attaches to a Flow step of type 'Quiz'). action='list' returns the company's quizzes as {id, name} records. action='get' returns one quiz's settings and, if quiz_question_id is also passed, that question's details (requires quiz_id). action='all_questions' returns a quiz's question list as {id, name} records (requires quiz_id). action='list_categories' returns the company's quiz-question categories as {id, name} records. action='attempts' returns the quiz's attempt records across the company's partners (requires quiz_id; optional partner_id filter) — each {id, user_id, partner_id, score, status, attempt_number}; use it to answer 'how did partner X score on quiz Y' or 'who is mid-attempt'. There is no stored pass/fail — compare score to the quiz's quiz_passing_score from action='get'. To create or edit quizzes/questions, use `quizzes_manage`.
quizzes
[Flows — onboarding & training lifecycle] Create, edit, and delete quizzes and their questions (customer-admin only). Quiz questions are multiple-choice only: question_type='single_choice' (exactly one correct answer) or 'multiple_choice' (one or more correct answers). action='create' creates an empty draft quiz and returns its id. action='save' saves quiz-level settings AND propagates all pending question changes to existing/in-progress attempts (requires quiz_id and name — pass the quiz's CURRENT name if you're not renaming it; optional quiz_description, quiz_enable_retake, quiz_passing_score) — run it ONLY after the user confirms they want to propagate. action='add_question' adds a question (requires quiz_id, name, question_type, order, options, correct_answers; quiz_category_id is OPTIONAL — omit it to create the question without a category). action='update_question' fully replaces a question (requires quiz_question_id — NOT quiz_id — plus name, question_type, order, required, options, correct_answers); every field is overwritten, so resend the current values you want to keep — EXCEPT quiz_category_id, which is optional: omitting it KEEPS the question's current category, passing it changes the category, and there is no way to clear a category via this tool. `options` is the list of answer choices; `correct_answers` must be a non-empty subset of `options` (exactly one for single_choice). action='delete_question' soft-deletes a question (requires quiz_id, quiz_question_id). action='delete' deactivates a quiz (requires quiz_id). action='create_category' creates a quiz-question category (requires name) and returns quiz_category_id; action='edit_category' renames one (requires quiz_category_id, name); action='delete_category' soft-deletes one (requires quiz_category_id). Resolve category ids via quizzes(action:'list_categories'). add_question / update_question / delete_question are mutate-only and do NOT reach existing quiz attempts on their own — do NOT save automatically: after any of these, tell the user the change won't propagate to existing/in-progress attempts until the quiz is saved, and ask whether to save now; call action='save' only once the user confirms. To read quizzes, use `quizzes`.
quizzes_manage
[SI Service Projects — Customer Admin] Reads SI (System Integrator) service projects from the CUSTOMER ADMIN side — service delivery across ALL of the company's partners. The customer company is resolved server-side (NOT an AI input). action='list' returns the company's projects (paginated via offset/limit; optionally filtered to one partner via partner_id) as `items[]` — each item has id, name, partner_id, partner_name, status, service_types[], start_date, end_date, completed_date, created_date — PLUS total_count and has_more. action='scope_form' returns ONE project's full scope form (requires project_id): `questions[]` (each with field_id, field_name, type, required, order, and the current answer in answer_text / answer_number / answer_date / answers_list, plus `options` for Dropdown/Multi-select/Checkbox) and `checkboxes[]`. action='export' is a BATCH for pulling large volumes: it returns a page of projects (offset/limit, max 100) where EACH project is already enriched with its full `scope_form` (+ `checkboxes`) — use it to extract all ~N projects' complete data in pages without calling scope_form one-by-one (a project may carry `scope_form_error` if its form couldn't be fetched; the rest of the batch still returns). Everything is tenant-isolated by privacy rules (a project outside your company is never returned). NOTE: 'In Progress' here is the project lifecycle status; a scope-form field literally named 'Project Status' (e.g. 'Scoping') is a different value that lives inside the scope form.
si_customer_service_projects
[Partner Relationships] Query deals — look one up by name, or list/rank/filter them. `deal_name` is OPTIONAL: pass it to find a specific deal ('find the Acme deal', 'deals named *renewal*'); omit it to list or rank deals by filter and sort instead ('list my open deals', 'top 10 deals by value', 'deals in the Negotiation stage'). Filter with `stage`, `pipeline`, `status` (won/lost/open) and a `start_date`/`end_date` close-date window; order with `sort` and cap with `limit` — both applied server-side. Each row returns deal_name, amount, stage, close_date and the associated company/partner. SCOPE: partner-role callers MUST pass partner_id (scopes to that partner's deals); customer-role callers MAY pass partner_id to narrow to one partner, otherwise the search spans all the company's deals. For PARTNER rankings/leaderboards (top partners by revenue or deal count) use `performance(action: 'overall')` instead; for the raw unfiltered page-through of a single partner's deals use `partner_artifacts(action: 'deals')`.
get_search_deals
[Partner Directory] Searches EULER's Partner Directory — public-facing partner profiles, tiers, status, custom-fields completeness, iframe analytics, saved filters. Every directory item carries TWO DIFFERENT ids: `id` is the `profile_id` (this tool's filters and `partner_directory_profiles` take it), and `partner_id` is the roster id used by referrals / partner_artifacts / performance / commissions. Passing `id` where a partner_id is expected produces `partner_not_in_consent`. Use the item's `partner_id` to cross a directory result over to those tools, and to answer which partners already have a profile — do NOT match the two rosters by NAME, which is unreliable (a partner's roster name and its directory name legitimately differ). `partner_id` is EMPTY on a profile whose partner link was never set (9 of 213 measured on 2026-09-01): treat an empty one as unknown, never as 'no such partner'. To resolve a partner_id from a name instead, prefer `list_accounts` (match by `affiliate_company_name`) or `partners(action: 'list', filter_name: ...)`. entity_key selects mode: 'partner_directory' is THE workhorse search mode — filters by name, status, tier, type, email, featured, and incomplete ONLY (the `language` and `website` params are NOT applied in this mode, and its results do not include language data). 'partner_history' returns a single profile's change history (requires profile_id) — each entry carries id, latest_update, inputs_updated, created_by, short_description, long_description, languages and rejection_message, and this is the ONLY mode where the `language` / `website` filters apply. It does NOT return the profile's website, accepting_clients or hide_contact_button, and neither does the directory mode — for those use `partner_directory_profiles(action:'read_profile')`. To answer 'does partner X serve <language>?': first entity_key='partner_directory' with name='X' to get the profile_id, then entity_key='partner_history' with that profile_id + language='<language>' (total_count > 0 means yes). Directory-WIDE language coverage ('which partners serve Spanish?') cannot be answered by a single filtered search — apply the history recipe ONLY to partners the user explicitly names (a handful at most); NEVER enumerate the whole directory profile-by-profile (dozens of calls that will be cut off before finishing), and NEVER present an unfiltered directory listing as a language-filtered answer. When no specific partners are named, tell the user the directory can't be filtered by language yet. 'partner_filter' applies a named saved filter via `version_description` — only used when the user explicitly references a saved filter name. The `status` enum here filters Directory profile status (Active / Under Review / Awaiting Setup / Rejected / Hidden) — that's distinct from the partner roster's active-vs-pending state. Route generic partner-status / partner-count questions ('how many partners are active?', 'how many active partners do we have?', 'partner status breakdown') to `partners(action: 'summary')`; only use this tool's `status` filter when the user is explicitly asking about the Partner Directory. Filterable by name, status, featured, incomplete, tier, profile_id, type, email (directory mode); language, website, version_description (history / saved-filter modes).
partner_directory_search
[Content Search] Semantic (vector) search INSIDE a partner's privately-shared content — the documents/decks/files the customer shared with a specific partner — matches on meaning, not filename. Use for 'find content about <topic>' / 'what do my shared docs say about X' scoped to a partner. Partner-scoped: requires `partner_id` (resolve via `list_accounts` for partner-role, or `partners(action: 'list', filter_name: ...)` for customer-admin). For product HELP / how-to questions about EULER itself ('how do I add a user', 'how does EULER work'), use `euler_help` instead. To LIST or browse a partner's files by name, use `content_list`. NOT for the caller's OWN records or numbers — this searches documents, so it can only ever return prose ABOUT a topic, never the user's actual data. Questions like 'what are my top commission earning deals', 'what is my affiliate link', 'when is my next payout', 'why haven't I been paid', 'how many referrals did I send' must go to the data tools instead: `commissions` (earnings/payouts), `partner_artifacts` (action 'tracking_links' for affiliate links, 'deals', 'invoices', 'charges', 'agreements'), `get_search_deals` (a specific deal by name), `referrals`, `performance(action: 'partner')` (that partner's metrics). Searching documents for those returns a generic article instead of the answer — if a question asks for the user's own figures, records or status, call the data tool, not this one.
content_search
[Partner Relationships] Sends an OUTBOUND referral from your company TO one of your partners (the customer-side counterpart of a partner's submit_referral). The partner receives it and decides via their assistant or the partner portal; the form answers stay hidden from them until they accept. Required flow: (1) resolve partner_id for the recipient with `partners(action: 'list', filter_name: ...)` — it must be a partner OF YOUR COMPANY (EULER rejects a partner outside it). (2) call `get_outbound_form` to fetch the outbound form_id + questions[]. (3) have the user fill in every required question. (4) call this tool with partner_id + form_id + answers (a JSON array of {question_id, answer_text, multiselect_options[]} entries). Each call sends to ONE partner. IDs from `partner_directory_search` are profile_ids, NOT partner_ids — they'll be rejected.
send_outbound_referral
[Feedback] Sends feedback to the EULER engineering team about the MCP itself — tool errors, ambiguous descriptions, missing capabilities. Use proactively when: (a) type='error' — a tool returned an unrecoverable error and the user couldn't get what they asked for; (b) type='improvement' — a tool's description was ambiguous and led down the wrong path before recovering; (c) type='feature_request' — the user asked for something this MCP doesn't support yet; (d) type='recommendation' — a general suggestion (UX, naming, missing context, etc). Feedback is delivered to a Slack channel monitored by EULER engineering. Do NOT use for routine user-fixable errors (wrong input, missing partner_id, malformed deal_id) or to surface successful operations — only when the MCP itself fell short.
submit_feedback
How do I improve a ChatGPT Plugin's discoverability?
The levers are the listing surface agents actually read: names, descriptions, keywords, tool metadata, and registry health. Which lever matters depends on where discovery breaks, which is what continuous measurement shows.
What are EULER alternatives on ChatGPT?
As of 2026-09-13, EULER competes with Crossbeam, Introw PRM, Nesha, Partner.io, Suger in ChatGPT Partner & Ecosystem Revenue, ranked by public Discoverability Score.
Where is this profile measured?
This profile uses the geography attached to the latest public registry snapshot: US. Locale tags are intentionally omitted.