SAP Concur Expense · API Governance Rules

SAP Concur Expense API Rules

Spectral linting rules defining API design standards and conventions for SAP Concur Expense.

16 Rules error 2 warn 8 info 1
View Rules File View on GitHub

Rule Categories

concur

Rules

error
concur-operation-id-required
All operations must have an operationId
$.paths[*][get,post,put,patch,delete]
warn
concur-operation-id-camel-case
SAP Concur operation IDs use camelCase (e.g., listExpenseReports, createExpenseEntry, getPaymentBatch)
$.paths[*][get,post,put,patch,delete].operationId
warn
concur-tags-title-case
All tags must use Title Case (e.g., Expense Reports, Quick Expenses)
$.tags[*].name
warn
concur-path-kebab-case
SAP Concur API paths use lowercase kebab-case for multi-word resource names (e.g., /expense/quickexpenses, /expense/receiptimages)
$.paths[*]~
warn
concur-response-200-has-schema
All 200 responses must have a response schema defined
$.paths[*][get,post].responses['200']
hint
concur-pagination-limit-param
Collection endpoints (GET returning arrays) should support limit parameter for pagination (max 100 per SAP Concur convention)
$.paths[*].get.parameters[?(@.name=='limit')]
hint
concur-pagination-offset-param
Collection endpoints should support offset parameter for cursor-based pagination using the NextPage URL pattern
$.paths[*].get
hint
concur-currency-code-format
Currency code fields must be ISO 4217 three-letter uppercase codes. SAP Concur uses CurrencyCode and TransactionCurrencyCode naming.
$.components.schemas[*].properties[?(@property.match(/CurrencyCode$/))]
error
concur-id-field-type-string
SAP Concur uses string identifiers (hex GUIDs) for all resource IDs. ID fields must be typed as string, not integer.
$.components.schemas[*].properties.ID
hint
concur-report-id-references
Expense entry endpoints require reportID as a query parameter when listing entries. The ReportID parameter enables server-side filtering.
$.paths['/expense/entries'].get.parameters[?(@.name=='reportID')]
warn
concur-delete-returns-204
DELETE operations in SAP Concur APIs return 204 No Content on success (not 200). Ensure DELETE responses use 204.
$.paths[*].delete.responses
warn
concur-put-returns-204
PUT update operations in SAP Concur APIs return 204 No Content on success. The full updated resource is retrieved via a subsequent GET.
$.paths[*].put.responses
info
concur-post-create-returns-200
POST create operations return 200 with an ID response body rather than 201. This follows SAP Concur v3 API conventions.
$.paths[*].post.responses
warn
concur-oauth2-security-defined
SAP Concur APIs require OAuth 2.0 authentication. All operations should reference the OAuth2 security scheme.
$.components.securitySchemes
hint
concur-entry-id-path-param
Path parameters for resource IDs should be named 'id' (lowercase) following SAP Concur conventions.
$.paths[*][*].parameters[?(@.in=='path')]
warn
concur-date-fields-iso8601
Date fields should use ISO 8601 format. Transaction dates use date format, datetime fields use date-time format.
$.components.schemas[*].properties[?(@property.match(/Date$/))]

Spectral Ruleset

Raw ↑
extends: spectral:oas
rules:
  # SAP Concur Expense API Naming Conventions
  concur-operation-id-required:
    description: All operations must have an operationId
    severity: error
    given: "$.paths[*][get,post,put,patch,delete]"
    then:
      field: operationId
      function: defined

  concur-operation-id-camel-case:
    description: >-
      SAP Concur operation IDs use camelCase (e.g., listExpenseReports,
      createExpenseEntry, getPaymentBatch)
    severity: warn
    given: "$.paths[*][get,post,put,patch,delete].operationId"
    then:
      function: pattern
      functionOptions:
        match: "^[a-z][a-zA-Z0-9]*$"

  concur-tags-title-case:
    description: All tags must use Title Case (e.g., Expense Reports, Quick Expenses)
    severity: warn
    given: "$.tags[*].name"
    then:
      function: pattern
      functionOptions:
        match: "^[A-Z][a-zA-Z ]*$"

  concur-path-kebab-case:
    description: >-
      SAP Concur API paths use lowercase kebab-case for multi-word resource names
      (e.g., /expense/quickexpenses, /expense/receiptimages)
    severity: warn
    given: "$.paths[*]~"
    then:
      function: pattern
      functionOptions:
        match: "^(/[a-z0-9{}-]+)+$"

  concur-response-200-has-schema:
    description: All 200 responses must have a response schema defined
    severity: warn
    given: "$.paths[*][get,post].responses['200']"
    then:
      field: content
      function: defined

  concur-pagination-limit-param:
    description: >-
      Collection endpoints (GET returning arrays) should support limit parameter
      for pagination (max 100 per SAP Concur convention)
    severity: hint
    given: "$.paths[*].get.parameters[?(@.name=='limit')]"
    then:
      field: schema.maximum
      function: defined

  concur-pagination-offset-param:
    description: >-
      Collection endpoints should support offset parameter for cursor-based
      pagination using the NextPage URL pattern
    severity: hint
    given: "$.paths[*].get"
    then:
      function: schema
      functionOptions:
        schema:
          type: object
          properties:
            parameters:
              type: array

  concur-currency-code-format:
    description: >-
      Currency code fields must be ISO 4217 three-letter uppercase codes.
      SAP Concur uses CurrencyCode and TransactionCurrencyCode naming.
    severity: hint
    given: "$.components.schemas[*].properties[?(@property.match(/CurrencyCode$/))]"
    then:
      field: pattern
      function: defined

  concur-id-field-type-string:
    description: >-
      SAP Concur uses string identifiers (hex GUIDs) for all resource IDs.
      ID fields must be typed as string, not integer.
    severity: error
    given: "$.components.schemas[*].properties.ID"
    then:
      field: type
      function: enumeration
      functionOptions:
        values:
          - string

  concur-report-id-references:
    description: >-
      Expense entry endpoints require reportID as a query parameter when
      listing entries. The ReportID parameter enables server-side filtering.
    severity: hint
    given: "$.paths['/expense/entries'].get.parameters[?(@.name=='reportID')]"
    then:
      field: required
      function: truthy

  concur-delete-returns-204:
    description: >-
      DELETE operations in SAP Concur APIs return 204 No Content on success
      (not 200). Ensure DELETE responses use 204.
    severity: warn
    given: "$.paths[*].delete.responses"
    then:
      field: "204"
      function: defined

  concur-put-returns-204:
    description: >-
      PUT update operations in SAP Concur APIs return 204 No Content on success.
      The full updated resource is retrieved via a subsequent GET.
    severity: warn
    given: "$.paths[*].put.responses"
    then:
      field: "204"
      function: defined

  concur-post-create-returns-200:
    description: >-
      POST create operations return 200 with an ID response body rather than 201.
      This follows SAP Concur v3 API conventions.
    severity: info
    given: "$.paths[*].post.responses"
    then:
      field: "200"
      function: defined

  concur-oauth2-security-defined:
    description: >-
      SAP Concur APIs require OAuth 2.0 authentication. All operations should
      reference the OAuth2 security scheme.
    severity: warn
    given: "$.components.securitySchemes"
    then:
      field: OAuth2
      function: defined

  concur-entry-id-path-param:
    description: >-
      Path parameters for resource IDs should be named 'id' (lowercase)
      following SAP Concur conventions.
    severity: hint
    given: "$.paths[*][*].parameters[?(@.in=='path')]"
    then:
      field: name
      function: enumeration
      functionOptions:
        values:
          - id

  concur-date-fields-iso8601:
    description: >-
      Date fields should use ISO 8601 format. Transaction dates use date format,
      datetime fields use date-time format.
    severity: warn
    given: "$.components.schemas[*].properties[?(@property.match(/Date$/))]"
    then:
      field: format
      function: defined