Create PRM invitation for a new partner
POST https://api.suger.cloud/org/{orgId}/prm/invitation
Creates and sends a partner invitation when the sender is inviting a company that is not yet a formal partnership. Runs server-side domain classification, the collision precheck, and paired inbound-row creation. Safe to retry, with the same guard as CreatePrmInvitation: a recipient who already has an invitation in Sent state in this organization is refused with 409 and no second email is sent. The same 409 also reports a company that is already formally linked to a Suger partner organization; the response body says which case it is.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
orgId | path | string | yes | Organization ID |
Request Body
Required. Content-Type: application/json · Schema: CreateInvitationRequest
CreateInvitationRequest fields:
| Field | Type | Required | Description |
|---|---|---|---|
aiContext | string | no | |
ccEmails | array<string> | no | |
contextMessage | string | no | |
createdBy | string | no | |
emailProvider | string | no | EmailProvider specifies which integration to use: "GOOGLE" (Gmail), "MICROSOFT" (Outlook), or "DNS" (the org's verified custom domain, org-level). If empty, tries Gmail first then Outlook as fallback. |
emailScope | string | no | EmailScope selects the sender identity: "user" (default) uses the sender's own connected Gmail/Outlook; "org" uses the org-level Gmail integration (shared service-account mailbox). Org scope is Gmail-only. |
messageBody | string | yes | |
messageSubject | string | yes | |
newPartner | NewPartnerDetails | no | |
partnershipId | string | no | |
purpose | string | yes | |
recipientEmail | string | yes | |
recipientName | string | no | |
referencedDocuments | array<InvitationReferencedDocument> | no | ReferencedDocuments are the partner agreements / shared files the sender chose to link from this invitation. The body carries a literal token per document; the server swaps each one for a real anchor when it renders the email, so the link is built from server data and never from anything the composer or the AI typed. |
tone | string | yes |
NewPartnerDetails fields:
| Field | Type | Required | Description |
|---|---|---|---|
crmObjectId | string | no | CrmObjectID links this new-partner invite to a CRM account (Salesforce Account Id) when sent from the "From your CRM" tab. Threaded onto the created partnership's info.crmAccountInfo at acceptance so CRM document sync can find it. Empty for non-CRM invites. |
intendedChannels | array<string> | no | |
partnerCompanyName | string | yes |
InvitationReferencedDocument fields:
| Field | Type | Required | Description |
|---|---|---|---|
id | string | no | ID is the PartnerFile id. |
name | string | no | Name is the link text shown to the recipient. |
url | string | no | URL is the resolved link. Server-built at send time; never stored. |
Responses
200 — OK
Content-Type: application/json · Schema: PartnerInvitation
PartnerInvitation fields:
| Field | Type | Required | Description |
|---|---|---|---|
createTime | string | no | Creation timestamp |
createdBy | string | no | ISV user ID who sent the invitation (outbound), null for inbound |
direction | string | no | OUTBOUND (ISV invites partner) or INBOUND (partner applies via public URL) |
engagementId | string | no | Shared identifier that pairs an outbound invitation with its inbound counterpart (Case A paired send, Cases B/C accept-synthesized). Null for non-paired rows. |
expiresAt | string | no | When the invitation expires. Defaults at the DB to 15 days after insert (CURRENT_TIMESTAMP + 15 days); past this it can no longer be accepted/declined and the daily cron marks it Expired. |
id | string | no | ID of the ent. Unique invitation identifier (UUID) |
info | PartnerInvitationInfo | no | |
lastUpdateTime | string | no | Last update timestamp |
organizationId | string | no | The ISV organization that owns this invitation |
partnerOrganizationId | string | no | The partner's Suger org ID, set on acceptance after org provisioning |
partnershipId | string | no | Target partnership. Nullable for inbound invitations before a partner record exists. |
purpose | string | no | Invitation purpose: network, account_overlap, deal_collaboration |
respondedAt | string | no | When the recipient responded (accepted or declined) |
sentAt | string | no | When the invitation was sent (outbound) or submitted (inbound) |
status | string | no | Invitation status: Sent, Accepted, Declined, Expired |
trackingToken | string | no | UUID token for accept/decline links (outbound) or form URL (inbound) |
PartnerInvitationInfo fields:
| Field | Type | Required | Description |
|---|---|---|---|
inbound | InboundInvitationInfo | no | |
outbound | OutboundInvitationInfo | no |
InboundInvitationInfo fields:
| Field | Type | Required | Description |
|---|---|---|---|
formData | object | no | FormData holds the submitted form field values. |
formId | string | no | FormID is the ID of the form configuration used for this submission. |
responseMessage | string | no | ResponseMessage explains how this application reached its current status when something other than a human on the Applications surface decided it. Today that is one case: the ISV accepted the applicant's co-sell, which provisions them as a partner and therefore settles the application too — including reversing an earlier Declined or Expired, because a provisioned partner with a live deal cannot also be a rejected applicant. Without the note the Applications tab would show a reversal with no cause. Distinct from OutboundInvitationInfo.ResponseMessage, which carries the RECIPIENT's own words when they answer an invitation the ISV sent. These are inbound rows: nobody replied, the system reconciled them. |
senderOrgId | string | no | SenderOrgID is the resolved Suger org of the applicant who submitted this inbound application (the sender / partner side). Optional: set at submit time only when the work-email domain matches exactly ONE production, PRM-enabled-or-PARTNER Suger org; empty when zero or multiple matched. Read at accept time to link the ISV-side partnership to this org and create the reciprocal partnership record on the sender side. |
submitterEmail | string | no | SubmitterEmail is the email of the partner who submitted the form. |
submitterName | string | no | SubmitterName is the name of the partner who submitted the form. |
OutboundInvitationInfo fields:
| Field | Type | Required | Description |
|---|---|---|---|
acceptInitiatedAt | string | no | AcceptInitiatedAt (RFC3339) is stamped when the recipient submits the public accept form (records intent + ResponseMessage) BEFORE signing in via Auth0. The authenticated finalize step requires it before verifying the Auth0 email against RecipientEmail and provisioning ( two-step accept flow). |
aiContext | string | no | AIContext is additional context provided for AI email generation. |
ccEmails | array<string> | no | CcEmails is the list of CC email addresses. |
contextMessage | string | no | ContextMessage is the user-provided engagement context. |
crmObjectId | string | no | CrmObjectID is the CRM account record id (Salesforce Account Id) this invite was created from in the "From your CRM" flow (/). Threaded to acceptance so the created ISV-side partnership is linked to its CRM account (info.crmAccountInfo.accountId) — which the CRM document sync relies on. Empty for non-CRM invites. Salesforce-only today. |
emailDelivery | InvitationEmailDelivery | no | |
emailProvider | string | no | EmailProvider is the sender integration the original send resolved to: "GOOGLE", "MICROSOFT" or "DNS" (the org's verified custom domain). Empty on legacy rows and when the sender did not pin one. Persisted so a RESEND re-uses the same identity — without it a resend silently falls back to the user-scope Gmail/Outlook path, which changes the From address (and DMARC alignment) for an org that deliberately sent over DNS or org-scope Gmail. |
emailScope | string | no | EmailScope is "user" (the sender's own mailbox, the default) or "org" (the org-level Gmail service account). Persisted for the same reason as EmailProvider — see above. |
intendedChannels | array<string> | no | IntendedChannels is the marketplace channel classification computed at send time from the recipient email's domain: ["Direct"] for Case B, the matched marketplace(s) for Case C, and the matched org's inferred channels (or ["Direct"]) for Case A. Used at acceptance to populate the ISV-side partnership's info.channels when an ISV-side partnership must be created from the invitation. |
messageBody | string | no | MessageBody is the final email body (HTML). |
messageSubject | string | no | MessageSubject is the final email subject line. |
partnerCompanyName | string | no | PartnerCompanyName is the free-text partner company name entered by the sender in "Invite a new partner" mode. Unset when the invitation is for a pre-existing partnership (Select Recommended Partner mode). |
recipientEmail | string | no | RecipientEmail is the partner contact email the invitation was sent to. |
recipientName | string | no | RecipientName is the partner contact name. |
referencedDocuments | array<InvitationReferencedDocument> | no | ReferencedDocuments are the agreements / shared files this invitation linked. Doubles as the allow-list the public document route checks — see InvitationReferencedDocument. |
responseMessage | string | no | ResponseMessage is the partner's response when accepting or declining the invitation. Mandatory for Accepted invitations, optional for Declined. |
tone | string | no | Tone is the selected email tone: executive, sales, technical, alliance, tactical. |
InvitationEmailDelivery fields:
| Field | Type | Required | Description |
|---|---|---|---|
attemptedAt | string | no | AttemptedAt is the RFC3339 time of this attempt. |
provider | string | no | Provider is the identity the email actually left from: GOOGLE / MICROSOFT (the inviter's connected mailbox), DNS (the org's verified custom domain) or SUGER (the Suger SES sender, used when every configured mailbox was unavailable). Empty when Status is FAILED. |
reason | string | no | Reason is a curated failure code, present only when Status is FAILED: sender_unavailable (no mailbox could send and the Suger fallback failed too), send_failed (a mailbox rejected the message after dispatch, so the Suger fallback was not attempted to avoid a duplicate) or paired_inbound_missing (Case A: the recipient org's paired row could not be resolved, so no deep-link email was sent). The raw error stays in the server log — it carries internal ids. |
status | InvitationEmailDeliveryStatus | no |
InvitationReferencedDocument fields:
| Field | Type | Required | Description |
|---|---|---|---|
id | string | no | ID is the PartnerFile id. |
name | string | no | Name is the link text shown to the recipient. |
url | string | no | URL is the resolved link. Server-built at send time; never stored. |
400 — Bad request error
Content-Type: application/json
409 — Partner already linked
Content-Type: application/json · Schema: ConflictPayload
ConflictPayload fields:
| Field | Type | Required | Description |
|---|---|---|---|
error | string | no | |
message | string | no | |
partnerName | string | no | |
partnerOrgId | string | no |
Example
Generated from this operation's schema. Values are placeholders —
substitute your own ids, and set SUGER_TOKEN to a bearer token
from the OAuth client-credentials exchange.
Request
curl -X POST 'https://api.suger.cloud/org/{orgId}/prm/invitation' \
-H "Authorization: Bearer $SUGER_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"messageBody": "string",
"messageSubject": "string",
"purpose": "string",
"recipientEmail": "buyer@example.com",
"tone": "string"
}' Response — 200
{
"createTime": "2026-01-31T12:00:00Z",
"createdBy": "string",
"direction": "string",
"engagementId": "01H0000000000000000000",
"expiresAt": "string",
"id": "01H0000000000000000000",
"info": {
"inbound": {
"formData": {},
"formId": "01H0000000000000000000",
"responseMessage": "string",
"senderOrgId": "01H0000000000000000000",
"submitterEmail": "buyer@example.com",
"submitterName": "Acme Corp"
},
"outbound": {
"acceptInitiatedAt": "string",
"aiContext": "string",
"ccEmails": [
"buyer@example.com"
],
"contextMessage": "string",
"crmObjectId": "01H0000000000000000000",
"emailDelivery": {
"attemptedAt": "string",
"provider": "string",
"reason": "string",
"status": "SENT"
},
"emailProvider": "buyer@example.com",
"emailScope": "buyer@example.com",
"intendedChannels": [
"string"
],
"messageBody": "string",
"messageSubject": "string",
"partnerCompanyName": "Acme Corp"
}
},
"lastUpdateTime": "2026-01-31T12:00:00Z",
"organizationId": "01H0000000000000000000",
"partnerOrganizationId": "01H0000000000000000000",
"partnershipId": "01H0000000000000000000",
"purpose": "string"
} Error — 400
"string" View as Markdown · Interactive API reference
Spotted something wrong or out of date on this page? Tell us and we'll correct it.