SoundGTM API reference
Overview for technology partners
This is for a company building a tool that talks to SoundGTM on behalf of a shared customer. SoundGTM offers a plain REST API under /api/v1 for enrolling referral partners and handing back their tracking links, reading a customer's deals, partners, programs and commissions, and acting on them (stage moves, conversions, invites, commission approvals, announcements). The same tools are also served over MCP for AI assistants. Every call works inside one customer's SoundGTM workspace and carries that customer's permissions.
What you can do, and what you need for each
| You want to | Use | The customer gives you |
|---|---|---|
| Enroll a person as the customer's referral partner from your product and get their tracking link, no invite email | REST: POST /api/v1/partners/register (see Partner registration API) | A Read + Write API key or OAuth connection, from a user who can invite referral partners |
| Look up an existing referral partner's tracking link | REST: GET /api/v1/partners/register | A Read or Read + Write API key or OAuth connection, from a user who can view partners |
| Read a customer's pipeline, deals, partners, programs, pending commissions and action queue | REST (GET) or the MCP server | A Read API key or an OAuth connection, on the Growth plan or above |
| Act in the customer's workspace: move a deal stage, mark a deal converted, invite a partner, authorize commissions, send an announcement, and the other write tools in the list below | REST (POST/PUT) or the MCP server | A Read + Write API key, or an OAuth connection approved with Read + Write, on the Growth plan or above |
Where the customer gets the key or connection
- API key: Settings → AI / MCP → + Create API key. Choose Read or Read + Write (the key form labels them "Read only" and "Read & write"; the OAuth approval screen says "Read only" and "Read + Write"); the key is shown once. You send it as
Authorization: Bearer pt_sk_…. - OAuth connection (Claude, ChatGPT, Gemini): the customer adds SoundGTM from inside the assistant, and the approval screen names the access level. The admin approving the connection chooses Read or Read + Write on that screen; if the client sends no scope, the screen starts on Read + Write when the client's redirect address is on claude.ai, chatgpt.com or openai.com and on Read for every other client, Gemini included, so request
read_writeif you need writes. How Claude and ChatGPT connect is described on the MCP integration page; a tool of your own can use an API key, or register itself as an OAuth client (POST /api/oauth/register, standard dynamic client registration) and send the customer through the approval screen; every client is public (no client secret) and must use PKCE (S256) with https redirect addresses (or http://localhost). Connections are listed and revocable under Settings → AI / MCP → Connected AI assistants (OAuth). - The customer must be a company account (a referral-partner account gets
403), and creating the key or approving the connection needs the organization-settings permission (the AI / MCP tab in Settings is shown to admins). A key acts with its creator's permissions. Every REST call except/partners/register, and the MCP server, need the Growth plan or above, and on plans that cap monthly AI usage, an unspent monthly AI-draft allowance (otherwise403, on every endpoint covered by the plan check). On/partners/registerthe only plan check is the partner limit, applied when a call creates or reactivates a partner. Revoking a key or connection takes effect on the next request (401); an expired OAuth access token is also a401, so refresh it before assuming access was revoked.
REST conventions
Reads are GET with inputs in the query string; writes are POST or PUT with a JSON body. A write needs a Read + Write key, or an OAuth connection approved with Read + Write, and the customer's own permission for that action. Errors come back as a JSON body with an error message and an HTTP status; the Partner registration API below lists its own statuses.
The method, path, inputs and permission for every tool route are listed under MCP tools below.
Not available yet
- No outbound webhooks from SoundGTM to your tool.
- No sandbox. Registering a partner creates a real pending partner that counts against the customer's partner limit, and it cannot be undone over the API; sending the same email and program again returns the same link, except that for a partner the customer deactivated it re-enrolls them (and uses a partner-limit slot).
- Other calls run against the customer's real workspace, and writes are live: stage moves and commission approvals take effect, and announcements and partner invites send real email. Test reads with a key set to Read (choose it in the key form; Read + Write is preselected), and only point a Read + Write key at a workspace you are prepared to change.
Interfaces
The rest of this page has two parts: the MCP tools, which an AI assistant calls on your behalf and which are also served over REST, and the Partner registration API, which your own software calls to register referral partners.
The MCP tools are reached through OAuth (claude.ai, ChatGPT, Gemini, or a tool registered as an OAuth client) or an API key; the Partner registration API takes an API key or an OAuth connection. Create keys in Settings → AI / MCP. Setup guides for Claude and ChatGPT are on the MCP integration page.
MCP tools
Every tool the SoundGTM MCP server serves, with the inputs it accepts and the permission the signed-in user (or key owner) needs. Read tools work with a Read key or OAuth connection; tools marked Read + Write need a Read + Write key, or an OAuth connection approved with Read + Write. This section is generated from the server's own tool definitions, so the tools, their inputs and their required permissions stay in step with the server. Each tool that shows a REST line under its name is also served over REST at that method and path, with the same API key or OAuth connection (sent as a Bearer token), plan and permission checks: reads take their inputs in the query string, writes in a JSON body, and any {name} in the path is filled in from the input of that name. Value limits (such as a maximum) are enforced by the server and are not all listed here.
pipeline_summary
Deal counts by stage, at-risk count, pending commission totals
Access: Read · Permission: View pipeline
REST: GET /api/v1/pipeline · inputs go in the query string
curl "https://partnertracker.soundgtm.com/api/v1/pipeline" -H "Authorization: Bearer $SOUNDGTM_API_KEY"
This tool takes no inputs.
list_deals
List deals with filters (stage, partner, risk, source)
Access: Read · Permission: View pipeline
REST: GET /api/v1/deals · inputs go in the query string
curl "https://partnertracker.soundgtm.com/api/v1/deals" -H "Authorization: Bearer $SOUNDGTM_API_KEY"
| Input | Type | Required | Description |
|---|---|---|---|
stage | string | No | Filter by stage name (exact match) |
partner_id | string | No | Filter by partner UUID |
risk_color | "green" | "amber" | "red" | No | Filter by risk color |
source | string | No | Filter by source (e.g. referral_registration) |
limit | integer | No | Max results (default 50) |
list_stalled_deals
Deals with amber or red risk scores
Access: Read · Permission: View pipeline
REST: GET /api/v1/deals/stalled · inputs go in the query string
curl "https://partnertracker.soundgtm.com/api/v1/deals/stalled" -H "Authorization: Bearer $SOUNDGTM_API_KEY"
| Input | Type | Required | Description |
|---|---|---|---|
limit | integer | No | Max results (default 25) |
get_deal
Full deal detail: members, recent events
Access: Read · Permission: View pipeline
REST: GET /api/v1/deals/{deal_id} · a {name} in the path is required over REST (the Required column below describes the MCP tool) and is filled in from the input of that name; the other inputs go in the query string
curl "https://partnertracker.soundgtm.com/api/v1/deals/<deal_id>" -H "Authorization: Bearer $SOUNDGTM_API_KEY"
| Input | Type | Required | Description |
|---|---|---|---|
deal_id | string | Yes | Deal UUID |
list_partners
List partners with filters (status, at-risk)
Access: Read · Permission: View partners
REST: GET /api/v1/partners · inputs go in the query string
curl "https://partnertracker.soundgtm.com/api/v1/partners" -H "Authorization: Bearer $SOUNDGTM_API_KEY"
| Input | Type | Required | Description |
|---|---|---|---|
status | "active" | "inactive" | No | Default: "active". |
at_risk | boolean | No | If true, returns only at-risk partners (health color red or amber) |
limit | integer | No | Default: 50. |
get_partner_detail
Partner's deals, commission terms, health score
Access: Read · Permission: View partners
REST: GET /api/v1/partners/{partner_id} · a {name} in the path is required over REST (the Required column below describes the MCP tool) and is filled in from the input of that name; the other inputs go in the query string
curl "https://partnertracker.soundgtm.com/api/v1/partners/<partner_id>" -H "Authorization: Bearer $SOUNDGTM_API_KEY"
| Input | Type | Required | Description |
|---|---|---|---|
partner_id | string | Yes | Partner UUID |
list_programs
Your partner programs and their settings
Access: Read · Permission: View partners
REST: GET /api/v1/programs · inputs go in the query string
curl "https://partnertracker.soundgtm.com/api/v1/programs" -H "Authorization: Bearer $SOUNDGTM_API_KEY"
This tool takes no inputs.
get_action_queue
Your prioritized do-this-next queue
Access: Read · Permission: View pipeline
REST: GET /api/v1/action-queue · inputs go in the query string
curl "https://partnertracker.soundgtm.com/api/v1/action-queue" -H "Authorization: Bearer $SOUNDGTM_API_KEY"
| Input | Type | Required | Description |
|---|---|---|---|
limit | integer | No | Default: 20. |
get_ideal_partner_profile
Your saved Ideal Partner Profile
Access: Read · Permission: View partners
REST: GET /api/v1/ideal-partner-profile · inputs go in the query string
curl "https://partnertracker.soundgtm.com/api/v1/ideal-partner-profile" -H "Authorization: Bearer $SOUNDGTM_API_KEY"
This tool takes no inputs.
list_pending_commissions
All commissions awaiting payment
Access: Read · Permission: View payments
REST: GET /api/v1/commissions/pending · inputs go in the query string
curl "https://partnertracker.soundgtm.com/api/v1/commissions/pending" -H "Authorization: Bearer $SOUNDGTM_API_KEY"
| Input | Type | Required | Description |
|---|---|---|---|
limit | integer | No | Default: 50. |
update_deal_stage
Move a deal to a new stage
Access: Read + Write · Permission: Edit deals
REST: POST /api/v1/deals/{deal_id}/stage · a {name} in the path is required over REST (the Required column below describes the MCP tool) and is filled in from the input of that name; the other inputs go in the JSON body
curl -X POST "https://partnertracker.soundgtm.com/api/v1/deals/<deal_id>/stage" -H "Authorization: Bearer $SOUNDGTM_API_KEY" -H "Content-Type: application/json" -d '{"stage":"<stage>"}'
| Input | Type | Required | Description |
|---|---|---|---|
deal_id | string | Yes | Deal UUID |
stage | string | Yes | New stage name |
convert_deal
Mark a deal as converted — creates payout records and notifies the partner if the program notifies partners
Access: Read + Write · Permission: Convert deals
REST: POST /api/v1/deals/{deal_id}/convert · a {name} in the path is required over REST (the Required column below describes the MCP tool) and is filled in from the input of that name; the other inputs go in the JSON body
curl -X POST "https://partnertracker.soundgtm.com/api/v1/deals/<deal_id>/convert" -H "Authorization: Bearer $SOUNDGTM_API_KEY" -H "Content-Type: application/json" -d '{}'
| Input | Type | Required | Description |
|---|---|---|---|
deal_id | string | Yes | Deal UUID |
notes | string | No | Optional conversion notes |
attach_deal_to_partner
Attach an unattributed deal to an existing partner, or to a new partner created on the spot (no email, no portal access)
Access: Read + Write · Permission: Edit deals
REST: POST /api/v1/deals/{deal_id}/partner · a {name} in the path is required over REST (the Required column below describes the MCP tool) and is filled in from the input of that name; the other inputs go in the JSON body
curl -X POST "https://partnertracker.soundgtm.com/api/v1/deals/<deal_id>/partner" -H "Authorization: Bearer $SOUNDGTM_API_KEY" -H "Content-Type: application/json" -d '{"partner_id":"<partner_id>"}'
| Input | Type | Required | Description |
|---|---|---|---|
deal_id | string | Yes | Deal UUID |
partner_id | string | No | Existing partner UUID to attach to |
new_partner_name | string | No | Create a new partner with this company name and attach the deal to it |
new_partner_email | string | No | Optional contact email for the new partner — stored, not emailed |
invite_partner
Send a partner invite email
Access: Read + Write · Permission: Invite referral partners
REST: POST /api/v1/partners/invite · inputs go in the JSON body
curl -X POST "https://partnertracker.soundgtm.com/api/v1/partners/invite" -H "Authorization: Bearer $SOUNDGTM_API_KEY" -H "Content-Type: application/json" -d '{"email":"<email>","program_id":"<program_id>"}'
| Input | Type | Required | Description |
|---|---|---|---|
email | string (email) | Yes | Partner's email address |
program_id | string | Yes | UUID of the program to invite this partner to |
company_name | string | No | Partner's company name |
payout_rule_id | string | No | UUID of the payout rule to attach to this partner |
save_ideal_partner_profile
Create or replace your Ideal Partner Profile
Access: Read + Write · Permission: Add & edit partners
REST: PUT /api/v1/ideal-partner-profile · inputs go in the JSON body
curl -X PUT "https://partnertracker.soundgtm.com/api/v1/ideal-partner-profile" -H "Authorization: Bearer $SOUNDGTM_API_KEY" -H "Content-Type: application/json" -d '{"profile_markdown":"<profile_markdown>","prospect_description":"<prospect_description>"}'
| Input | Type | Required | Description |
|---|---|---|---|
profile_markdown | string | Yes | The full profile as markdown |
prospect_description | string | Yes | One-paragraph prospect-finder description |
authorize_commissions
Bulk-approve commissions for payment (does not send money — transfers stay on the Payments page)
Access: Read + Write · Permission: Authorize payments
REST: POST /api/v1/commissions/authorize · inputs go in the JSON body
curl -X POST "https://partnertracker.soundgtm.com/api/v1/commissions/authorize" -H "Authorization: Bearer $SOUNDGTM_API_KEY" -H "Content-Type: application/json" -d '{"payment_ids":["<payment_id>"]}'
| Input | Type | Required | Description |
|---|---|---|---|
payment_ids | array of string (uuid) | Yes | List of payment UUIDs to authorize |
mark_commission_paid
Record a commission you already paid outside SoundGTM (bookkeeping only — sends no money)
Access: Read + Write · Permission: Manage payment status
REST: POST /api/v1/commissions/{payment_id}/paid · a {name} in the path is required over REST (the Required column below describes the MCP tool) and is filled in from the input of that name; the other inputs go in the JSON body
curl -X POST "https://partnertracker.soundgtm.com/api/v1/commissions/<payment_id>/paid" -H "Authorization: Bearer $SOUNDGTM_API_KEY" -H "Content-Type: application/json" -d '{}'
| Input | Type | Required | Description |
|---|---|---|---|
payment_id | string | Yes | Payment UUID |
payment_reference | string | No | Reference number or note (e.g. wire transfer ID) |
send_announcement
Send an announcement to all or selected partners
Access: Read + Write · Permission: Send announcements
REST: POST /api/v1/announcements · inputs go in the JSON body
curl -X POST "https://partnertracker.soundgtm.com/api/v1/announcements" -H "Authorization: Bearer $SOUNDGTM_API_KEY" -H "Content-Type: application/json" -d '{"title":"<title>","body":"<body>","audience":"select_partners","partner_ids":["i:<partner_id>"]}'
| Input | Type | Required | Description |
|---|---|---|---|
title | string | Yes | Announcement title |
body | string | Yes | Announcement body text |
audience | "all_partners" | "imported_only" | "referral_partners_only" | "select_partners" | No | Who receives this announcement. Default: "all_partners". |
partner_ids | array of string | No | Required when audience is 'select_partners'. Use prefixed IDs: 'i:uuid' for imported partners, 'r:uuid' for referral partner orgs. |
draft_partner_email
Create a Gmail draft addressed to a partner — never sends
Access: Read + Write · Permission: Add & edit partners
REST: POST /api/v1/partners/{partnerId}/email-draft · a {name} in the path is required over REST (the Required column below describes the MCP tool) and is filled in from the input of that name; the other inputs go in the JSON body
curl -X POST "https://partnertracker.soundgtm.com/api/v1/partners/<partnerId>/email-draft" -H "Authorization: Bearer $SOUNDGTM_API_KEY" -H "Content-Type: application/json" -d '{"to":"<to>","body":"<body>"}'
| Input | Type | Required | Description |
|---|---|---|---|
to | string (email) | Yes | Recipient email address |
subject | string | No | Email subject. Default: "Check-in". |
body | string | Yes | Email body (plain text) |
partnerId | string | No | If this draft is a check-in to a specific partner (e.g. a quiet-partner wake-up), that partner's id — records that a check-in was drafted for them. |
Partner registration API
Third-party tools (such as Social OS) can register referral partners programmatically and receive their tracking link without going through the invite email flow. This is useful when your tool already handles outreach and you want SoundGTM to issue the referral link silently.
Authentication: a Read + Write API key or OAuth connection (see where the customer gets the key or connection above), sent as a Bearer token, from a user who can invite referral partners.
Endpoint: POST /api/v1/partners/register
Request body:
{ "email": "jane@example.com", "name": "Jane Smith", "linkedin_url": "https://linkedin.com/in/janesmith", "program_id": "uuid-of-your-program" }
emailis required.name,linkedin_url, andprogram_idare optional.- If
program_idis omitted, the partner is enrolled in your default program.
Response:
201: a new partner, or a deactivated one re-enrolled.200: a link already exists for that email and program, pending or active.
Both statuses return the same body:
{ "referral_link_id": "uuid", "referral_url": "https://partnertracker.soundgtm.com/r/AbCd1234" }
Pass referral_url to your tool to embed in outreach messages. Clicks on that link are attributed to the partner in SoundGTM.
The call is idempotent — calling it again with the same email and program returns the same link without creating a duplicate (200). The exception is a partner the customer deactivated: registering them again re-enrolls them as Pending (201) and uses a partner-limit slot. On either repeat call name and linkedin_url are not updated.
No invite email is sent. The partner appears as Pending in your partner list until they claim their SoundGTM account via the invite flow.
Failed calls are covered under Error statuses below.
Retrieving a partner's link
To fetch an existing partner's referral link without creating or changing anything, call the same endpoint with GET:
Endpoint: GET /api/v1/partners/register?email=jane%40example.com
emailis required; URL-encode it, because an unencoded character such as+changes the address the route receives. Add&program_id=<uuid>to target a specific program; omit it to use your default program. If you have no default program,program_idis required.- Authentication: any API key or OAuth connection — Read or Read + Write — from a user with the View partners permission.
Response:
{ "referral_link_id": "uuid", "referral_url": "https://partnertracker.soundgtm.com/r/AbCd1234", "status": "pending" }
Unlike re-POSTing to register, GET is strictly read-only — it never reactivates a revoked partner, so it's safe to call any time.
Error statuses
On failure both methods return one of these status codes with a JSON { "error": "..." } body; the two answers with no body are under the table:
| Status | POST | GET |
|---|---|---|
400 | Missing or invalid email (over 254 characters is invalid), name over 200 characters, a non-blank program_id string that isn't a UUID, or malformed JSON body | Missing or invalid email (over 254 characters is invalid), a non-blank program_id that isn't a UUID, or no program_id and no default program in your account |
401 | Missing, invalid, revoked or expired credential, or one whose user can't be found | Same as POST |
403 | The credential isn't Read + Write (an OAuth connection approved as Read counts: ask for read_write), its user lacks the Invite referral partners permission, the credential belongs to a referral-partner account rather than a company, or your plan's partner limit has been reached (only the limit case carries upgrade fields such as upgradeRequired and upgradeToTier in the body) | The credential's user lacks the View partners permission, or the credential belongs to a referral-partner account rather than a company |
404 | The program_id doesn't exist in your account | The program_id doesn't exist in your account, no link exists for that email and program, or the link has no referral URL yet (an older invite: register that partner with POST to generate one). The error message says which |
422 | The target program isn't fully set up (for example, it's missing a payout rule or an enabled lead source), or no program_id was given and your account has no default program — finish configuring the program, then retry | Not used: GET doesn't check that a program is set up |
503 | A temporary database read failed, including the check of the program's readiness; this call created and changed nothing — safe to retry | A temporary database read failed; it says nothing about whether the link exists — safe to retry |
500 | The credential or its account type couldn't be read; the link couldn't be saved; or the link was saved but its referral URL couldn't be generated. All are safe to retry: after that last case a retry that succeeds returns the same link with 200 and uses no further partner-limit slot | The credential or its account type couldn't be read — safe to retry |
Either method can also answer 500 with no JSON body if something fails that the route doesn't handle; that is safe to retry too. PUT, PATCH and DELETE get 405, also with no JSON body.