# 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.

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: `structs.ValidateReferralRequest`

**`structs.ValidateReferralRequest`** fields:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `opportunity` | object | no | Opportunity is the mapped opportunity object from debug preview. Shape depends on partner: AceOpportunityV2 (AWS), Opportunity (GCP), CreateReferralRequest (Azure). |
| `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: `structs.ValidateReferralResponse`

**`structs.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<structs.ValidateReferralFieldError> | no |  |
| `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 Suger-side referral ID. |
| `status` | string | no | Status is the unified Suger 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. |

**`structs.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 |  |

---

Interactive API reference: https://doc.suger.io/api/
