Dry-run validate a co-sell referral against partner schema
POST https://api.suger.cloud/org/{orgId}/cosell/referral/validate
Validate a mapped marketplace opportunity against the partner-specific schema (AWS ACE / Azure Partner Center / GCP). Returns schema violations and missing required fields WITHOUT creating or submitting anything. Use this when: you are about to create or update a referral and want to catch missing required fields first. Runs as a pre-flight check before calling CreateCosellReferral or BatchCreateCosellReferrals. The response also carries `duplicateOpenReferrals`: referrals already in this organization, for the same partner, whose title matches the one being validated and whose status is not yet concluded. It does not change `valid` and does not block creation — two referrals can legitimately share a title, such as a renewal or a phased project. When the list is non-empty, tell the seller which referrals matched and ask whether to continue before calling CreateCosellReferral. `opportunity` is the bare partner object, not a whole referral: for AWS the `info.aceOpportunityV2` value, for AZURE the `info.createMicrosoftReferralRequest` value, for GCP the `info.gcpOpportunityV2` value. The verdict is stricter than CreateCosellReferral: values create fills in for you (for AZURE: country, currency, phone and marketplace intent) are reported missing here, and `normalizedOpportunity` shows the filled-in result. When validating a change to a referral that already exists, pass its `referralId` so that referral is not reported as a duplicate of itself. Omit `referralId` for a referral that does not exist yet.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
orgId | path | string | yes | Organization ID |
Request Body
Required. Content-Type: application/json · Schema: ValidateReferralRequest
ValidateReferralRequest fields:
| Field | Type | Required | Description |
|---|---|---|---|
opportunity | object | no | Opportunity is the bare partner opportunity, not a whole referral: the info.aceOpportunityV2 value (AWS), info.createMicrosoftReferralRequest (AZURE) or info.gcpOpportunityV2 (GCP). |
partner | string | no | Partner is the cloud marketplace partner: "AWS", "GCP", or "AZURE". |
referralId | string | no | ReferralID is the referral being validated, set only when validating an update to an existing referral. It is excluded from the same-title duplicate check, which would otherwise always report the referral under validation as its own duplicate: same organization, same partner, identical title, not yet concluded. Leave empty when validating a referral that does not exist yet. |
Responses
200 — OK
Content-Type: application/json · Schema: ValidateReferralResponse
ValidateReferralResponse fields:
| Field | Type | Required | Description |
|---|---|---|---|
duplicateOpenReferrals | array<DuplicateOpenReferral> | no | DuplicateOpenReferrals lists existing referrals in the same organization and for the same partner whose normalised title matches and whose status is not yet concluded. It does not affect Valid and does not block creation. Two referrals can legitimately share a title — a renewal, or a phased project — so blocking outright would stand in the way of real work. This informs the seller and leaves the decision to them. The field is additive, so existing consumers ignore it. |
errors | array<ValidateReferralFieldError> | no | |
normalizedOpportunity | object | no | NormalizedOpportunity is the opportunity after the partner validator's own normalisation -- the payload the partner would actually receive. So a caller that shows the pre-validation payload shows values that will never arrive, with nothing to indicate it. The handler already computes this -- Validate mutates the opportunity in place -- and used to throw it away. Additive: existing consumers ignore it. |
valid | boolean | no |
DuplicateOpenReferral fields:
| Field | Type | Required | Description |
|---|---|---|---|
externalId | string | no | ExternalID is the partner-side opportunity ID; empty until the referral has been submitted to the partner. |
partner | string | no | Partner always equals the partner in the request. |
referralId | string | no | ReferralID is the Fours-side referral ID. |
status | string | no | Status is the unified Fours status, always one of the not-yet-concluded set. |
title | string | no | Title is the title as stored, not the normalised form used for comparison, so the reader sees what was actually recorded. |
ValidateReferralFieldError fields:
| Field | Type | Required | Description |
|---|---|---|---|
field | string | no | |
message | string | no |
400 — Bad Request
Content-Type: application/json · Schema: ErrorResponse
ErrorResponse fields:
| Field | Type | Required | Description |
|---|---|---|---|
code | ErrorCode | no | |
info | object | no | |
message | string | no |
500 — Internal Server Error
Content-Type: application/json · Schema: ErrorResponse
ErrorResponse fields:
| Field | Type | Required | Description |
|---|---|---|---|
code | ErrorCode | no | |
info | object | no | |
message | string | no |
Example
The request bodies are this operation's documented examples; the
response and error bodies are generated from its schema. Substitute your
own ids, and set SUGER_TOKEN to a bearer token from the
OAuth client-credentials exchange.
Request
Dry-run an AWS opportunity
`opportunity` is the bare partner object -- for AWS the `aceOpportunityV2` value, not a whole referral. Nothing is created. Unlike CreateCosellReferral, no missing fields are filled in for you.
curl -X POST 'https://api.suger.cloud/org/{orgId}/cosell/referral/validate' \
-H "Authorization: Bearer $SUGER_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"partner": "AWS",
"opportunity": {
"Customer": {
"Account": {
"CompanyName": "Contoso Analytics",
"Industry": "Software and Internet",
"WebsiteUrl": "https://contoso-analytics.example.com",
"Address": {
"CountryCode": "US",
"PostalCode": "94105",
"StateOrRegion": "California",
"City": "San Francisco"
}
},
"Contacts": [
{
"Email": "jamie.lee@contoso-analytics.example.com",
"FirstName": "Jamie",
"LastName": "Lee",
"BusinessTitle": "VP Engineering"
}
]
},
"PrimaryNeedsFromAws": [
"Co-Sell - Technical Consultation"
],
"OpportunityType": "Net New Business",
"Project": {
"Title": "Contoso Analytics - data platform migration",
"CustomerBusinessProblem": "Contoso runs its analytics stack in a colocation data center that is reaching end of life and wants to move it to AWS before renewal.",
"CustomerUseCase": "Migration / Database Migration",
"DeliveryModels": [
"SaaS or PaaS"
],
"ExpectedCustomerSpend": [
{
"Amount": "15000",
"CurrencyCode": "USD",
"Frequency": "Monthly",
"TargetCompany": "AWS"
}
],
"SalesActivities": [
"Initialized discussions with customer"
]
},
"RelatedEntityIdentifiers": {
"Solutions": [
"S-0060105"
]
},
"LifeCycle": {
"TargetCloseDate": "2027-06-30"
}
}
}' Dry-run an Azure create request
For Azure `opportunity` is the `createMicrosoftReferralRequest` value. The verdict is strict: values CreateCosellReferral would fill in for you (country, currency, phone, marketplace intent) are reported missing here; `normalizedOpportunity` in the response shows the filled-in version.
curl -X POST 'https://api.suger.cloud/org/{orgId}/cosell/referral/validate' \
-H "Authorization: Bearer $SUGER_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"partner": "AZURE",
"opportunity": {
"name": "Contoso Analytics - AI assistant rollout",
"customerProfile": {
"name": "Contoso Analytics",
"address": {
"country": "US",
"city": "San Francisco",
"state": "CA",
"postalCode": "94105"
}
},
"team": [
{
"email": "alex.morgan@your-company.example.com",
"firstName": "Alex",
"lastName": "Morgan",
"phoneNumber": "+14155550100"
}
],
"details": {
"closingDateTime": "2027-06-30T00:00:00Z",
"dealValue": 50000,
"currency": "USD",
"requirements": {
"solutions": [
{
"id": "7c574f32-b3ce-44fb-bb8b-bfe11d71a07a"
}
],
"additionalRequirements": {
"attributes": [
{
"type": "SolutionArea",
"id": "AI Business Solutions"
},
{
"type": "Conversation",
"id": "AI-ready productivity and security for every employee"
},
{
"type": "CustomerMarketplaceIntent",
"id": "HaveNotDecided"
}
]
}
}
},
"invitations": [
{
"organizationId": "msft",
"assistanceRequestCode": "NoHelpRequired"
}
]
}
}' Response — 200
{
"duplicateOpenReferrals": [
{
"externalId": "01H0000000000000000000",
"partner": "string",
"referralId": "01H0000000000000000000",
"status": "string",
"title": "string"
}
],
"errors": [
{
"field": "string",
"message": "string"
}
],
"valid": true
} Error — 400
{
"code": "InternalServerError",
"message": "string"
} View as Markdown · API reference overview
Spotted something wrong or out of date on this page? Tell us and we'll correct it.