Skip to content

Supplier Management Guide

Overview

Suppliers represent the companies and individuals that provide products, raw materials, or services to your business. The Operations module gives you comprehensive tools to onboard suppliers, manage their approval status, track their performance over time, and control their operational state through a well-defined lifecycle.

Every supplier in SynthesQ carries a rich profile: contact details, address, payment terms, lead time expectations, and a quantitative rating score. The system captures purchase-order history automatically, so performance metrics - on-time delivery rate, defect rate, total spend - are always up to date and available without manual data entry.

Supplier Lifecycle

Status Definitions

Suppliers move through eight operational states that control whether they can participate in procurement workflows:

StatusValueDescriptionCan Receive Orders
ProspectiveprospectiveNew supplier, not yet vettedNo
ActiveactiveFully operationalYes
ApprovedapprovedPassed vetting, pre-approved for ordersYes
PreferredpreferredStrategically prioritised supplierYes (fast-tracked)
InactiveinactiveTemporarily not in useNo
SuspendedsuspendedBlocked due to compliance or quality issuesNo
BlacklistedblacklistedPermanently blocked. Terminal state.No
Under Reviewunder_reviewCurrently being evaluated or auditedNo

Status Transitions

Suspension always requires a documented reason. An optional suspended_until date lets the system track when a supplier is eligible for reinstatement review. Blacklisted is a terminal state - no transitions are allowed once a supplier is blacklisted.

Supplier Types

The type field classifies the nature of the supplier relationship:

TypeDescription
manufacturerProduces goods directly
distributorDistributes on behalf of manufacturers
wholesalerSells in bulk at discounted rates
retailerRetail channel supplier
service_providerProvides services, not physical goods
consultantProvides consulting services
individualIndividual supplier or freelancer

Fields Reference

FieldTypeDescription
idULID stringUnique identifier (e.g. 01hwxyz123abc456def789ghi0)
namestringLegal name of the supplier
codestringUnique supplier code for internal reference (e.g. SUP-0042)
emailstringPrimary contact email address
phonestringPrimary contact phone number
statusenumCurrent lifecycle state: prospective, active, approved, preferred, inactive, suspended, blacklisted, under_review
typeenumSupplier classification: manufacturer, distributor, wholesaler, retailer, service_provider, consultant, individual
ratingdecimal (1–5)Aggregated performance rating (SupplierRating value object)
is_approvedbooleanWhether the supplier has passed internal vetting
is_preferredbooleanWhether the supplier is flagged as strategically preferred
addressobjectPhysical address: street, city, state, postal_code, country
payment_termsstringAgreed payment terms (e.g. Net 30, Net 60)
lead_time_daysintegerExpected fulfilment lead time in calendar days
minimum_order_amountdecimalMinimum order value the supplier accepts
created_atISO 8601Record creation timestamp
updated_atISO 8601Last modification timestamp

API Endpoints

All supplier endpoints are under the base path /api/v1/operations/suppliers.

Authentication: All requests require a valid Bearer token in the Authorization header.


List Suppliers

Endpoint: GET /api/v1/operations/suppliers

Retrieves a paginated list of suppliers with optional filtering and sorting.

Query Parameters:

ParameterTypeDescription
statusstringFilter by status: active, inactive, suspended
typestringFilter by supplier type
is_approvedbooleanFilter by approval status
is_preferredbooleanFilter to preferred suppliers only
searchstringFull-text search across name, code, and email
sort_bystringSort field: name, rating, created_at, lead_time_days
sort_directionstringasc or desc (default: asc)
per_pageintegerResults per page (default: 25, max: 100)
pageintegerPage number (default: 1)

Example Request:

bash
GET /api/v1/operations/suppliers?status=active&is_preferred=true&sort_by=rating&sort_direction=desc&per_page=25

Response (200 OK):

json
{
  "success": true,
  "message": "Suppliers retrieved successfully",
  "data": [
    {
      "id": "01hwxyz123abc456def789ghi0",
      "name": "Apex Components Ltd",
      "code": "SUP-0012",
      "email": "procurement@apexcomponents.com",
      "phone": "+1-555-0200",
      "status": "active",
      "type": "manufacturer",
      "rating": 4.7,
      "is_approved": true,
      "is_preferred": true,
      "payment_terms": "Net 30",
      "lead_time_days": 7,
      "minimum_order_amount": 500.00,
      "created_at": "2025-03-01T08:00:00Z",
      "updated_at": "2025-11-10T14:22:00Z"
    }
  ],
  "meta": {
    "current_page": 1,
    "per_page": 25,
    "total": 64,
    "last_page": 3
  },
  "links": {
    "first": "/api/v1/operations/suppliers?page=1",
    "last": "/api/v1/operations/suppliers?page=3",
    "prev": null,
    "next": "/api/v1/operations/suppliers?page=2"
  }
}

Create Supplier

Endpoint: POST /api/v1/operations/suppliers

Creates a new supplier record. New suppliers are created with status: inactive by default and must be explicitly activated.

Required Fields:

  • name - Legal name of the supplier
  • code - Unique supplier code (must be unique across the tenant)
  • email - Valid email address

Request Body:

json
{
  "name": "Vertex Materials Inc",
  "code": "SUP-0099",
  "email": "orders@vertexmaterials.com",
  "phone": "+1-555-0381",
  "type": "distributor",
  "is_approved": false,
  "is_preferred": false,
  "address": {
    "street": "440 Industrial Parkway",
    "city": "Detroit",
    "state": "MI",
    "postal_code": "48201",
    "country": "USA"
  },
  "payment_terms": "Net 45",
  "lead_time_days": 14,
  "minimum_order_amount": 1000.00
}

Response (201 Created):

json
{
  "success": true,
  "message": "Supplier created successfully",
  "data": {
    "id": "01hwxyz789def123abc456ghi0",
    "name": "Vertex Materials Inc",
    "code": "SUP-0099",
    "email": "orders@vertexmaterials.com",
    "phone": "+1-555-0381",
    "status": "inactive",
    "type": "distributor",
    "rating": null,
    "is_approved": false,
    "is_preferred": false,
    "address": {
      "street": "440 Industrial Parkway",
      "city": "Detroit",
      "state": "MI",
      "postal_code": "48201",
      "country": "USA"
    },
    "payment_terms": "Net 45",
    "lead_time_days": 14,
    "minimum_order_amount": 1000.00,
    "created_at": "2026-03-11T09:00:00Z",
    "updated_at": "2026-03-11T09:00:00Z"
  },
  "meta": {}
}

Error Response (422 Unprocessable Entity):

json
{
  "success": false,
  "message": "The given data was invalid.",
  "errors": {
    "code": ["The supplier code SUP-0099 is already in use."],
    "email": ["The email field must be a valid email address."]
  }
}

Get Supplier Details

Endpoint: GET /api/v1/operations/suppliers/{id}

Returns the full supplier record including address and all flags.

Response (200 OK):

json
{
  "success": true,
  "message": "Supplier retrieved successfully",
  "data": {
    "id": "01hwxyz789def123abc456ghi0",
    "name": "Vertex Materials Inc",
    "code": "SUP-0099",
    "email": "orders@vertexmaterials.com",
    "phone": "+1-555-0381",
    "status": "active",
    "type": "distributor",
    "rating": 4.2,
    "is_approved": true,
    "is_preferred": false,
    "address": {
      "street": "440 Industrial Parkway",
      "city": "Detroit",
      "state": "MI",
      "postal_code": "48201",
      "country": "USA"
    },
    "payment_terms": "Net 45",
    "lead_time_days": 14,
    "minimum_order_amount": 1000.00,
    "created_at": "2026-03-11T09:00:00Z",
    "updated_at": "2026-03-11T11:30:00Z"
  },
  "meta": {}
}

Update Supplier

Endpoint: PUT /api/v1/operations/suppliers/{id}

Updates supplier details. The code field must remain unique. Status changes (activate, deactivate, suspend) use their dedicated endpoints - the update endpoint does not accept a status field.

Request Body (partial update allowed):

json
{
  "payment_terms": "Net 60",
  "lead_time_days": 10,
  "is_preferred": true,
  "address": {
    "street": "440 Industrial Parkway",
    "city": "Detroit",
    "state": "MI",
    "postal_code": "48201",
    "country": "USA"
  }
}

Response (200 OK):

json
{
  "success": true,
  "message": "Supplier updated successfully",
  "data": {
    "id": "01hwxyz789def123abc456ghi0",
    "name": "Vertex Materials Inc",
    "code": "SUP-0099",
    "payment_terms": "Net 60",
    "lead_time_days": 10,
    "is_preferred": true,
    "updated_at": "2026-03-11T13:45:00Z"
  },
  "meta": {}
}

Delete Supplier

Endpoint: DELETE /api/v1/operations/suppliers/{id}

Soft-deletes the supplier. The record is retained for historical reporting and audit purposes but will no longer appear in standard list queries.

Response (200 OK):

json
{
  "success": true,
  "message": "Supplier deleted successfully",
  "data": null,
  "meta": {}
}

Soft Delete Behaviour

Deleting a supplier does not remove purchase-order history. Historical orders remain intact and reference the supplier by ID. Consider deactivating (POST /suppliers/{id}/deactivate) rather than deleting if you may need to reinstate the supplier later.


Activate Supplier

Endpoint: POST /api/v1/operations/suppliers/{id}/activate

Transitions a supplier from inactive or suspended to active. Once active, the supplier can be selected on new purchase orders.

Request Body: None required.

Response (200 OK):

json
{
  "success": true,
  "message": "Supplier activated successfully",
  "data": {
    "id": "01hwxyz789def123abc456ghi0",
    "status": "active",
    "updated_at": "2026-03-11T14:00:00Z"
  },
  "meta": {}
}

Deactivate Supplier

Endpoint: POST /api/v1/operations/suppliers/{id}/deactivate

Transitions an active supplier to inactive. Use this to temporarily pause a supplier without triggering a compliance event.

Request Body: None required.

Response (200 OK):

json
{
  "success": true,
  "message": "Supplier deactivated successfully",
  "data": {
    "id": "01hwxyz789def123abc456ghi0",
    "status": "inactive",
    "updated_at": "2026-03-11T14:05:00Z"
  },
  "meta": {}
}

Suspend Supplier

Endpoint: POST /api/v1/operations/suppliers/{id}/suspend

Suspends a supplier and records the reason for the block. An optional suspended_until date sets an automatic review target.

Request Body:

json
{
  "reason": "Failed third-party quality audit. Defect rate exceeded threshold.",
  "suspended_until": "2026-06-01"
}
FieldTypeRequiredDescription
reasonstringYesExplanation for the suspension
suspended_untildate (YYYY-MM-DD)NoDate after which the supplier is eligible for reinstatement review

Response (200 OK):

json
{
  "success": true,
  "message": "Supplier suspended successfully",
  "data": {
    "id": "01hwxyz789def123abc456ghi0",
    "status": "suspended",
    "suspension_reason": "Failed third-party quality audit. Defect rate exceeded threshold.",
    "suspended_until": "2026-06-01",
    "updated_at": "2026-03-11T14:10:00Z"
  },
  "meta": {}
}

Rate Supplier

Endpoint: POST /api/v1/operations/suppliers/{id}/rate

Submits a rating for the supplier. Ratings are averaged into the supplier's rating field using the SupplierRating value object. Values must be between 1.0 and 5.0.

Request Body:

json
{
  "rating": 4.5,
  "notes": "Delivered two days ahead of schedule. Packaging quality excellent."
}
FieldTypeRequiredDescription
ratingdecimal (1.0–5.0)YesNumeric rating score
notesstringNoContext or justification for the rating

Response (200 OK):

json
{
  "success": true,
  "message": "Supplier rated successfully",
  "data": {
    "id": "01hwxyz789def123abc456ghi0",
    "rating": 4.5,
    "updated_at": "2026-03-11T15:00:00Z"
  },
  "meta": {}
}

Get Performance Metrics

Endpoint: GET /api/v1/operations/suppliers/{id}/performance

Returns aggregated performance data derived from the supplier's purchase-order history. All metrics are computed at request time from live data.

Response (200 OK):

json
{
  "success": true,
  "message": "Performance metrics retrieved successfully",
  "data": {
    "orders": {
      "total": 45,
      "on_time": 38,
      "late": 7,
      "on_time_rate": 0.844
    },
    "delivery": {
      "average_lead_time_days": 8.3,
      "promised_vs_actual": 0.94
    },
    "quality": {
      "return_rate": 0.02,
      "defect_rate": 0.008
    },
    "financial": {
      "total_spend": 284500.00,
      "average_order_value": 6322.22
    },
    "compliance": {
      "approved": true,
      "last_audit_date": "2025-09-15"
    },
    "activity": {
      "last_order_date": "2025-11-02",
      "orders_last_90_days": 12
    }
  },
  "meta": {}
}

Metrics Explained:

MetricDescription
on_time_rateProportion of orders delivered on or before promised date (0–1)
promised_vs_actualRatio of promised lead time to actual lead time - values above 1.0 mean faster than promised
return_rateProportion of delivered items returned (0–1)
defect_rateProportion of delivered items with quality defects (0–1)
total_spendCumulative value of all purchase orders with this supplier
average_order_valueMean value per purchase order
orders_last_90_daysPurchase orders placed in the trailing 90-day window

Business Scenarios

Scenario 1: Onboarding a New Supplier

Context: Your procurement team has negotiated terms with a new manufacturer. You need to create their profile, complete the vetting process, and activate them for use.

Workflow:

  1. Create the supplier record with initial details
  2. Procurement team completes compliance review
  3. Mark the supplier as approved
  4. Activate the supplier so purchase orders can be raised

API Calls:

bash
# Step 1 - Create supplier (starts as inactive)
POST /api/v1/operations/suppliers
{
  "name": "Crestwood Fabrications",
  "code": "SUP-0101",
  "email": "supply@crestwoodfab.com",
  "type": "manufacturer",
  "payment_terms": "Net 30",
  "lead_time_days": 12,
  "minimum_order_amount": 2500.00,
  "address": {
    "street": "88 Factory Road",
    "city": "Cleveland",
    "state": "OH",
    "postal_code": "44101",
    "country": "USA"
  }
}

# Step 2 - After compliance review passes, mark approved
PUT /api/v1/operations/suppliers/01hwxyz789def123abc456ghi0
{
  "is_approved": true
}

# Step 3 - Activate the supplier
POST /api/v1/operations/suppliers/01hwxyz789def123abc456ghi0/activate

Scenario 2: Managing a Quality Incident

Context: A supplier's recent deliveries have shown an elevated defect rate. You need to suspend them, investigate, and reinstate them once corrective action is confirmed.

Workflow:

  1. Review performance metrics to confirm the problem
  2. Suspend the supplier with a documented reason and review date
  3. Run internal investigation (off-system)
  4. Once corrective action is verified, reactivate

API Calls:

bash
# Step 1 - Check current metrics
GET /api/v1/operations/suppliers/01hwxyz789def123abc456ghi0/performance

# Step 2 - Suspend with reason and review date
POST /api/v1/operations/suppliers/01hwxyz789def123abc456ghi0/suspend
{
  "reason": "Defect rate at 4.2% over last 90 days, exceeding 2% threshold. Quality corrective action required.",
  "suspended_until": "2026-06-01"
}

# Step 3 - After corrective action confirmed, reactivate
POST /api/v1/operations/suppliers/01hwxyz789def123abc456ghi0/activate

# Step 4 - Submit updated rating reflecting improvement
POST /api/v1/operations/suppliers/01hwxyz789def123abc456ghi0/rate
{
  "rating": 3.5,
  "notes": "Reinstated after corrective action. Monitoring period begins."
}

Scenario 3: Quarterly Supplier Review

Context: Your procurement team conducts quarterly reviews to update preferred supplier designations, adjust ratings, and deactivate suppliers no longer in use.

Workflow:

  1. Retrieve the full list of active suppliers sorted by rating
  2. Pull performance metrics for low-rated suppliers
  3. Update preferred flags based on review outcomes
  4. Deactivate suppliers with no orders in the last 90 days

API Calls:

bash
# Step 1 - List active suppliers by rating (ascending to find underperformers)
GET /api/v1/operations/suppliers?status=active&sort_by=rating&sort_direction=asc&per_page=100

# Step 2 - Pull metrics for a specific low-rated supplier
GET /api/v1/operations/suppliers/01hwXXXXXXXXXXXXXXXXXXXXXX/performance

# Step 3 - Promote a high-performing supplier to preferred
PUT /api/v1/operations/suppliers/01hwxyz123abc789def456ghi0
{
  "is_preferred": true
}

# Step 4 - Submit post-review rating
POST /api/v1/operations/suppliers/01hwxyz123abc789def456ghi0/rate
{
  "rating": 4.8,
  "notes": "Q1 2026 review: consistent on-time delivery, zero defects last quarter."
}

# Step 5 - Deactivate a supplier with no recent activity
POST /api/v1/operations/suppliers/01hwxyz000aaa111bbb222ccc3/deactivate

Best Practices

1. Use Supplier Codes Consistently

Assign a structured supplier code (e.g. SUP-0001) at creation and never change it. The code is your stable internal reference across purchase orders, ERP integrations, and financial exports. Treat the name as display-only - it can change after rebrandings; the code must not.

2. Document Every Status Change

Use the suspension reason field even for borderline cases. Audit trails matter: if a supplier challenges a suspension or your compliance team needs to trace a decision six months later, the documented reason is your record. For deactivations, leave a note in an external system or ticket linking back to the supplier ID.

3. Rate After Every Significant Order

Build a practice of rating suppliers after each purchase-order cycle rather than waiting for quarterly reviews. Frequent, incremental ratings produce a more accurate rating value and make problems visible early. Target at least one rating per month for high-volume suppliers.

4. Separate Approval from Activation

The is_approved flag and the active status serve different purposes. A supplier can be active (operationally enabled) but is_approved: false if they are on a trial. A supplier can be is_approved: true but inactive if they are seasonally paused. Use both fields intentionally - do not conflate them.

5. Leverage Performance Metrics Before Raising Orders

Before placing a high-value purchase order, retrieve the supplier's performance metrics and check their on_time_rate and defect_rate. If either metric has deteriorated since the last order, escalate internally before committing. This is especially important for suppliers with orders_last_90_days of zero, as their metrics may be stale.


Integration Points

With Purchase Orders

Suppliers are the primary foreign key on all purchase orders in the Operations module. Only active suppliers can be selected when raising a new purchase order. The supplier's lead_time_days and minimum_order_amount are surfaced in the purchase-order creation flow as defaults that purchasing staff can override with justification.

With Inventory and Stock Movements

Goods receipts that close purchase orders feed directly into stock-movement records linked to the originating supplier. This data drives the on_time_rate, defect_rate, and total_spend shown in the performance-metrics endpoint. Accurate goods-receipt processing is a prerequisite for meaningful supplier performance data.

With the Integrations Module

If your tenant has a payment-gateway or ERP integration active, approved supplier records can be synchronised outbound to your accounting system. Supplier codes serve as the cross-system key. Refer to the Integrations Module Guide for configuration details.


Troubleshooting

Cannot Activate a Supplier

Error: "Supplier cannot be activated from its current state."

Cause: You may be attempting to activate a supplier that is already active, or there is a missing required field (e.g. email was never set) that the system requires before activation.

Solution:

  1. Retrieve the current supplier record: GET /api/v1/operations/suppliers/{id}
  2. Confirm the current status is inactive or suspended
  3. Check that email and name are populated
  4. If the supplier is already active, no action is needed

Supplier Code Conflict on Creation

Error: "The supplier code SUP-0099 is already in use."

Cause: Supplier codes must be unique across all suppliers in the tenant, including soft-deleted ones. A deleted supplier may be holding the code.

Solution:

  1. Search for the conflicting code: GET /api/v1/operations/suppliers?search=SUP-0099
  2. If no result is returned, the holder is soft-deleted - choose a different code
  3. If a result is returned, check whether the existing supplier should be updated rather than a new one created

Performance Metrics Show No Data

Issue: The performance-metrics endpoint returns zeros or nulls across all fields for an established supplier.

Cause: Performance data is derived from closed purchase orders. If purchase orders have not been fully received and closed in the system, the metrics will not populate.

Solution:

  1. Confirm that purchase orders for this supplier have been fully processed through goods receipt
  2. Check that order statuses are marked as completed in the purchase-orders module
  3. For brand-new suppliers, metrics will be empty until at least one purchase order completes - this is expected behaviour

Documentation for SynthesQ CRM/ERP Platform