openapi: 3.0.3
info:
  title: Wegopay sandbox simulations
  version: 1.0.0
  description: Isolated platform integration simulations. Never provider-approved fixtures or real payment state.
servers:
  - url: /
paths:
  /v1/sandbox/simulations:
    post:
      operationId: createSandboxSimulation
      summary: createSandboxSimulation
      security:
        - apiKeyBearer: []
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CreateSimulation' }
      responses:
        '201': { $ref: '#/components/responses/SimulationResponse' }
        '400': { $ref: '#/components/responses/ErrorResponse' }
        '401': { $ref: '#/components/responses/ErrorResponse' }
        '403': { $ref: '#/components/responses/ErrorResponse' }
        '404': { $ref: '#/components/responses/ErrorResponse' }
        '409': { $ref: '#/components/responses/ErrorResponse' }
        '422': { $ref: '#/components/responses/ErrorResponse' }
        '429': { $ref: '#/components/responses/ErrorResponse' }
        '503': { $ref: '#/components/responses/ErrorResponse' }
  /v1/sandbox/simulations/{id}:
    get:
      operationId: getSandboxSimulation
      summary: getSandboxSimulation
      security:
        - apiKeyBearer: []
      parameters:
        - $ref: '#/components/parameters/SimulationId'
      responses:
        '200': { $ref: '#/components/responses/SimulationResponse' }
        '400': { $ref: '#/components/responses/ErrorResponse' }
        '401': { $ref: '#/components/responses/ErrorResponse' }
        '403': { $ref: '#/components/responses/ErrorResponse' }
        '404': { $ref: '#/components/responses/ErrorResponse' }
        '409': { $ref: '#/components/responses/ErrorResponse' }
        '422': { $ref: '#/components/responses/ErrorResponse' }
        '429': { $ref: '#/components/responses/ErrorResponse' }
        '503': { $ref: '#/components/responses/ErrorResponse' }
  /v1/sandbox/simulations/{id}/complete:
    post:
      operationId: completeSandboxSimulation
      summary: completeSandboxSimulation
      security:
        - apiKeyBearer: []
      parameters:
        - $ref: '#/components/parameters/SimulationId'
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CompleteSimulation' }
      responses:
        '200': { $ref: '#/components/responses/SimulationResponse' }
        '400': { $ref: '#/components/responses/ErrorResponse' }
        '401': { $ref: '#/components/responses/ErrorResponse' }
        '403': { $ref: '#/components/responses/ErrorResponse' }
        '404': { $ref: '#/components/responses/ErrorResponse' }
        '409': { $ref: '#/components/responses/ErrorResponse' }
        '422': { $ref: '#/components/responses/ErrorResponse' }
        '429': { $ref: '#/components/responses/ErrorResponse' }
        '503': { $ref: '#/components/responses/ErrorResponse' }
  /merchant/sandbox/simulations:
    post:
      operationId: createMerchantSandboxSimulation
      summary: createMerchantSandboxSimulation
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CreateSimulation' }
      responses:
        '201': { $ref: '#/components/responses/SimulationResponse' }
        '400': { $ref: '#/components/responses/ErrorResponse' }
        '401': { $ref: '#/components/responses/ErrorResponse' }
        '403': { $ref: '#/components/responses/ErrorResponse' }
        '404': { $ref: '#/components/responses/ErrorResponse' }
        '409': { $ref: '#/components/responses/ErrorResponse' }
        '422': { $ref: '#/components/responses/ErrorResponse' }
        '429': { $ref: '#/components/responses/ErrorResponse' }
        '503': { $ref: '#/components/responses/ErrorResponse' }
  /merchant/sandbox/simulations/{id}:
    get:
      operationId: getMerchantSandboxSimulation
      summary: getMerchantSandboxSimulation
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/SimulationId'
      responses:
        '200': { $ref: '#/components/responses/SimulationResponse' }
        '400': { $ref: '#/components/responses/ErrorResponse' }
        '401': { $ref: '#/components/responses/ErrorResponse' }
        '403': { $ref: '#/components/responses/ErrorResponse' }
        '404': { $ref: '#/components/responses/ErrorResponse' }
        '409': { $ref: '#/components/responses/ErrorResponse' }
        '422': { $ref: '#/components/responses/ErrorResponse' }
        '429': { $ref: '#/components/responses/ErrorResponse' }
        '503': { $ref: '#/components/responses/ErrorResponse' }
  /merchant/sandbox/simulations/{id}/complete:
    post:
      operationId: completeMerchantSandboxSimulation
      summary: completeMerchantSandboxSimulation
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/SimulationId'
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CompleteSimulation' }
      responses:
        '200': { $ref: '#/components/responses/SimulationResponse' }
        '400': { $ref: '#/components/responses/ErrorResponse' }
        '401': { $ref: '#/components/responses/ErrorResponse' }
        '403': { $ref: '#/components/responses/ErrorResponse' }
        '404': { $ref: '#/components/responses/ErrorResponse' }
        '409': { $ref: '#/components/responses/ErrorResponse' }
        '422': { $ref: '#/components/responses/ErrorResponse' }
        '429': { $ref: '#/components/responses/ErrorResponse' }
        '503': { $ref: '#/components/responses/ErrorResponse' }
  /admin/merchants/{merchantId}/sandbox/simulations:
    post:
      operationId: createAdminSandboxSimulation
      summary: createAdminSandboxSimulation
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/MerchantId'
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CreateSimulation' }
      responses:
        '201': { $ref: '#/components/responses/SimulationResponse' }
        '400': { $ref: '#/components/responses/ErrorResponse' }
        '401': { $ref: '#/components/responses/ErrorResponse' }
        '403': { $ref: '#/components/responses/ErrorResponse' }
        '404': { $ref: '#/components/responses/ErrorResponse' }
        '409': { $ref: '#/components/responses/ErrorResponse' }
        '422': { $ref: '#/components/responses/ErrorResponse' }
        '429': { $ref: '#/components/responses/ErrorResponse' }
        '503': { $ref: '#/components/responses/ErrorResponse' }
  /admin/merchants/{merchantId}/sandbox/simulations/{id}:
    get:
      operationId: getAdminSandboxSimulation
      summary: getAdminSandboxSimulation
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/MerchantId'
        - $ref: '#/components/parameters/SimulationId'
      responses:
        '200': { $ref: '#/components/responses/SimulationResponse' }
        '400': { $ref: '#/components/responses/ErrorResponse' }
        '401': { $ref: '#/components/responses/ErrorResponse' }
        '403': { $ref: '#/components/responses/ErrorResponse' }
        '404': { $ref: '#/components/responses/ErrorResponse' }
        '409': { $ref: '#/components/responses/ErrorResponse' }
        '422': { $ref: '#/components/responses/ErrorResponse' }
        '429': { $ref: '#/components/responses/ErrorResponse' }
        '503': { $ref: '#/components/responses/ErrorResponse' }
  /admin/merchants/{merchantId}/sandbox/simulations/{id}/complete:
    post:
      operationId: completeAdminSandboxSimulation
      summary: completeAdminSandboxSimulation
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/MerchantId'
        - $ref: '#/components/parameters/SimulationId'
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CompleteSimulation' }
      responses:
        '200': { $ref: '#/components/responses/SimulationResponse' }
        '400': { $ref: '#/components/responses/ErrorResponse' }
        '401': { $ref: '#/components/responses/ErrorResponse' }
        '403': { $ref: '#/components/responses/ErrorResponse' }
        '404': { $ref: '#/components/responses/ErrorResponse' }
        '409': { $ref: '#/components/responses/ErrorResponse' }
        '422': { $ref: '#/components/responses/ErrorResponse' }
        '429': { $ref: '#/components/responses/ErrorResponse' }
        '503': { $ref: '#/components/responses/ErrorResponse' }
components:
  securitySchemes:
    apiKeyBearer:
      type: http
      scheme: bearer
      description: Sandbox merchant API key only.
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
  parameters:
    MerchantId:
      name: merchantId
      in: path
      required: true
      schema: { type: string, format: uuid }
    SimulationId:
      name: id
      in: path
      required: true
      schema: { type: string, format: uuid }
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: true
      schema: { type: string, minLength: 16, maxLength: 128, pattern: '^[!-~]+$' }
  schemas:
    CreateSimulation:
      type: object
      additionalProperties: false
      required: [scenario, reference, amountCents, currency]
      properties:
        scenario: { type: string, enum: [paid, declined, requiresAction, expired] }
        method: { type: string, enum: [card, wallet], default: wallet }
        reference: { type: string, minLength: 1, maxLength: 255, pattern: '.*\S.*' }
        amountCents: { type: integer, format: int64, minimum: 500, maximum: 100000000 }
        currency: { type: string, enum: [USD] }
    CompleteSimulation:
      type: object
      additionalProperties: false
      required: [outcome]
      properties:
        outcome: { type: string, enum: [paid, declined] }
    Simulation:
      type: object
      additionalProperties: false
      required: [id, environment, simulation, status, scenario, method, reference, amountCents, currency, createdAt, expiresAt, failureCode, failureMessage, webhookStatus]
      properties:
        id: { type: string, format: uuid }
        environment: { type: string, enum: [sandbox] }
        simulation: { type: boolean, enum: [true] }
        status: { type: string, enum: [paid, failed, requiresAction, expired] }
        scenario: { type: string, enum: [paid, declined, requiresAction, expired] }
        method: { type: string, enum: [card, wallet] }
        reference: { type: string }
        amountCents: { type: integer, format: int64 }
        currency: { type: string, enum: [USD] }
        createdAt: { type: string, format: date-time }
        expiresAt: { type: string, format: date-time }
        failureCode: { type: string, nullable: true }
        failureMessage: { type: string, nullable: true }
        webhookStatus: { type: string, enum: [pending, processing, delivered, dead] }
    SimulationEnvelope:
      type: object
      additionalProperties: false
      required: [data]
      properties:
        data: { $ref: '#/components/schemas/Simulation' }
    ErrorEnvelope:
      type: object
      additionalProperties: false
      required: [error]
      properties:
        error:
          type: object
          additionalProperties: false
          required: [code, message]
          properties:
            code: { type: string, enum: [invalid_request, unauthorized, sandbox_required, merchant_required, not_found, idempotency_key_reused, simulation_not_actionable, webhook_not_configured, validation_failed, rate_limited, service_unavailable] }
            message: { type: string }
  responses:
    SimulationResponse:
      description: Isolated simulation resource; do not use for real fulfillment.
      headers:
        Cache-Control:
          schema: { type: string, enum: [no-store] }
      content:
        application/json:
          schema: { $ref: '#/components/schemas/SimulationEnvelope' }
    ErrorResponse:
      description: Sanitized error.
      headers:
        Cache-Control:
          schema: { type: string, enum: [no-store] }
      content:
        application/json:
          schema: { $ref: '#/components/schemas/ErrorEnvelope' }
