Supplier invoice API does not detect duplicates, leading to double payments

We’re processing supplier invoices via the Workday REST API and discovered the duplicate detection isn’t working. Multiple invoices with identical invoice numbers from the same supplier are being created, causing duplicate payments.

API call that creates duplicates:


POST /supplierInvoices
{
  "supplierId": "SUP-1001",
  "invoiceNumber": "INV-2025-0603",
  "invoiceDate": "2025-06-01",
  "amount": 5000.00
}

When we submit this request multiple times (due to retry logic), Workday creates separate invoice records instead of rejecting duplicates. The UI prevents duplicate invoice numbers for the same supplier, but the API allows them. Is duplicate detection disabled for API submissions? Do we need to implement client-side checking before posting invoices?

Your duplicate payment issue stems from how Workday’s API handles duplicate detection versus UI validation. Here’s the comprehensive solution:

Supplier Invoice API Behavior:

The REST API in R2-2023 uses a multi-layered approach to duplicate prevention:

  1. Request-Level Deduplication (Idempotency)
  2. Business-Level Duplicate Detection (Invoice Number Validation)
  3. Race Condition Protection (Database Constraints)

Your current implementation only addresses layer 1, which is insufficient.

Duplicate Detection Logic:

Workday’s duplicate validation checks three criteria:

  • Supplier ID match
  • Invoice number match
  • Invoice date within tolerance window (default 30 days)

However, this validation must be explicitly requested in the API call:


POST /supplierInvoices
X-Idempotency-Key: unique-request-id-12345
Content-Type: application/json

{
  "supplierId": "SUP-1001",
  "invoiceNumber": "INV-2025-0603",
  "invoiceDate": "2025-06-01",
  "amount": 5000.00,
  "currency": "USD",
  "validationOptions": {
    "checkDuplicates": true,
    "duplicateWindow": 30,
    "strictMatching": true
  }
}

Key additions:

  • checkDuplicates: Enables business-level duplicate validation
  • duplicateWindow: Days to search for existing invoices (default 30)
  • strictMatching: Requires exact invoice number match (vs fuzzy matching)

Without the validationOptions object, the API assumes you’re handling duplicate detection client-side and will create the invoice regardless of existing records.

Response for Duplicate Detection:

When a duplicate is detected:


HTTP 409 Conflict
{
  "error": "DUPLICATE_INVOICE",
  "message": "Invoice INV-2025-0603 already exists for supplier SUP-1001",
  "existingInvoice": {
    "invoiceId": "SI-2025-06-001",
    "status": "APPROVED",
    "createdDate": "2025-06-01T10:30:00Z"
  },
  "validationFailures": [
    {
      "field": "invoiceNumber",
      "reason": "DUPLICATE_DETECTED",
      "existingValue": "INV-2025-0603"
    }
  ]
}

This response allows your application to handle duplicates appropriately (log, alert, skip, etc.).

Client-Side Validation:

While API-level validation is essential, implement client-side checking as a first line of defense:


// Pseudocode - Pre-submission validation:
1. Before posting invoice, query existing invoices:
   GET /supplierInvoices?supplier=SUP-1001&invoiceNumber=INV-2025-0603

2. If results returned:
   a. Check invoice status (DRAFT, PENDING, APPROVED, PAID)
   b. If status is DRAFT, update existing instead of creating new
   c. If status is PENDING/APPROVED/PAID, reject as duplicate

3. If no results, proceed with POST request
   Include validationOptions with checkDuplicates=true

4. Handle 409 Conflict response:
   Log duplicate attempt with existing invoice reference
   Do not retry - mark as duplicate in source system

This two-phase approach (client check + API validation) provides robust duplicate prevention.

Idempotency Key Strategy:

Idempotency keys prevent duplicate submissions of the same request but don’t detect business-level duplicates:


Idempotency Key Format:
{source_system}:{supplier_id}:{invoice_number}:{timestamp}

Example:
ERP_SYSTEM_A:SUP-1001:INV-2025-0603:1717416000

Use a deterministic key based on invoice attributes, not a random UUID. This ensures:

  • Same invoice from same source generates same key
  • Different sources for same invoice generate different keys (allowing detection)
  • Timestamp component handles legitimate resubmissions after corrections

Configuration Requirements:

Enable API duplicate detection in tenant configuration:


Workday Admin:
Setup > Accounts Payable > Supplier Invoice Settings

API Configuration:
☑ Enable API Duplicate Detection
☑ Enforce Supplier + Invoice Number Uniqueness
☑ Apply Date Window for Duplicate Search
  Window: 30 days (configurable 1-90)
☑ Return Detailed Validation Errors

Exception Handling:
☐ Allow Override with Justification Code
  (Uncheck - prevents API from bypassing validation)

Without these settings enabled, the validationOptions in your API request will be ignored.

Race Condition Prevention:

For high-volume integrations with multiple concurrent processes, implement application-level locking:


// Pseudocode - Distributed lock pattern:
1. Acquire lock: LOCK key="invoice:{supplier}:{invoiceNum}" timeout=30s
2. If lock acquired:
   a. Query for existing invoice
   b. If not exists, POST new invoice with validation
   c. Store invoice ID in cache with lock key
   d. Release lock
3. If lock not acquired:
   a. Wait for lock release (max 30s)
   b. Check cache for invoice ID from other process
   c. If found, return existing invoice reference
   d. If not found, retry lock acquisition

This prevents the scenario where two API calls pass duplicate validation simultaneously because neither invoice exists in the database yet.

Testing Duplicate Detection:

Validate your implementation:


Test Scenario 1 - Same Request Twice:
1. POST invoice with idempotency key "KEY-001"
2. POST same invoice with same key "KEY-001"
Expected: Second request returns original response, no duplicate created

Test Scenario 2 - Same Invoice Different Key:
1. POST invoice with idempotency key "KEY-001"
2. POST same invoice details with different key "KEY-002" and checkDuplicates=true
Expected: Second request returns 409 Conflict

Test Scenario 3 - Concurrent Submissions:
1. POST invoice from Process A
2. Simultaneously POST same invoice from Process B
Expected: One succeeds, one returns 409 Conflict (with application locking)

All three scenarios must pass to ensure comprehensive duplicate prevention.

Implementing these layers - API validation options, client-side checking, proper idempotency keys, and application locking - will eliminate duplicate invoice creation and prevent double payments in your AP automation.


This draft is based on general Workday knowledge. It has not been verified against your specific version and environment. Practitioners: verify the steps and share your experience below.

The API duplicate detection relies on idempotency keys, which aren’t in your request. Add a unique idempotency key header to each submission: X-Idempotency-Key: {unique-value}. When you retry the same request with the same idempotency key, Workday returns the original response instead of creating a duplicate. This is the recommended approach for handling retries and preventing duplicate submissions through the API.

I ran into this same issue last year. The problem is that the API’s duplicate detection logic is different from the UI’s. The UI checks supplier + invoice number combination, but the API requires you to explicitly enable duplicate checking by setting a flag in the request body. Try adding “checkForDuplicates”: true to your payload. Without this flag, the API assumes you’ve already validated uniqueness client-side.

Added X-Idempotency-Key header to our requests but still seeing duplicates when invoices are submitted from different systems or with different idempotency keys. The idempotency approach only prevents duplicate submissions of the exact same request, not duplicate invoice numbers from different sources. We need business-level duplicate detection based on supplier + invoice number, not just request-level deduplication. Is there a setting to enable this?

Tested this on R2-2023 REST API and implementing all three layers—idempotency keys, invoice number validation, and database constraints—eliminated our duplicate payment problem completely.

Check your tenant’s supplier invoice configuration. Under Setup > Accounts Payable > Invoice Processing, there’s a setting for “API Duplicate Detection” that controls whether the API enforces business rules for duplicates. It might be disabled in your environment. Also verify that the invoiceNumber field is mapped correctly - if it’s going to a different field than what the UI uses for duplicate checking, the validation won’t work.

Beyond configuration, consider the timing aspect. If two API calls hit the server simultaneously before either invoice is committed to the database, both will pass duplicate validation. This is a race condition that requires application-level locking. Implement a distributed lock using the supplier+invoice number as the key before calling the API. This ensures only one process can submit an invoice for that combination at a time, preventing the race condition that leads to duplicates.

I ran into this same issue last year.