{
  "openapi": "3.0.1",
  "info": {
    "title": "RealPayment External API",
    "description": "RealPayment integration API for payments, payment status, documents, business branding, customers, products, recurring payments, and sales flows. Intended for CRM, commerce, and other external systems. Explicitly marked internal management operations require the signed-in owner's Firebase Bearer token. External document-provider access requires owner-granted documents.providers.read or documents.providers.write scopes in addition to X-API-Key. Ordinary external webhooks support an explicitly provisioned and owner-enabled V2 signing contract. Existing clients retain legacy compatibility until migrated. Internal webhook-signing management uses the owner Firebase Bearer token, not an external API key. CardCom quotes retain their original provider PDF. Customer approval uses a separate linked acknowledgment; it is not an invoice, receipt or payment confirmation. Readiness is stored policy/binding evidence, not proof of live provider acceptance.",
    "version": "0.13.7",
    "x-release-status": "release_contract",
    "contact": {
      "name": "RealPayment",
      "url": "https://realpayment.co.il"
    },
    "x-release-cycle": "CP20"
  },
  "servers": [
    {
      "url": "https://us-central1-yakirvakninpayment.cloudfunctions.net/api",
      "description": "Cloud Functions (recommended)"
    },
    {
      "url": "https://realpayment.co.il/api",
      "description": "Firebase Hosting"
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "API Key from RealPayment settings (format: rp_live_...)"
      },
      "firebaseAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "Firebase ID token",
        "description": "Authorization: Bearer <Firebase ID token> for internal operations in the management interface."
      }
    },
    "parameters": {
      "DocumentProviderSelectionIdempotencyKey": {
        "name": "X-Idempotency-Key",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string",
          "minLength": 16,
          "maxLength": 160,
          "pattern": "^[A-Za-z0-9_.:-]+$"
        },
        "example": "provider-selection-20261004-001",
        "description": "Stable identity for one external provider-selection request. Reuse the same key and provider/expectedVersion payload for retries. The successful result is replayed without another switch. Reusing a key with a different payload returns 409. This identity is separate from document issuance and payment-link identities."
      },
      "DocumentIdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 180,
          "pattern": "^[A-Za-z0-9_.:-]+$"
        },
        "description": "Stable document issuance identity. Required for a CardCom accounting document without paymentId, or any new CardCom quote. Idempotency-Key, X-Idempotency-Key and body.requestId are aliases; all supplied values must match. Reuse the same identity and payload. This does not make the legacy internal-document branch replay-safe."
      },
      "DocumentXIdempotencyKey": {
        "name": "X-Idempotency-Key",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 180,
          "pattern": "^[A-Za-z0-9_.:-]+$"
        },
        "description": "Stable document issuance identity. Required for a CardCom accounting document without paymentId, or any new CardCom quote. Idempotency-Key, X-Idempotency-Key and body.requestId are aliases; all supplied values must match. Reuse the same identity and payload. This does not make the legacy internal-document branch replay-safe."
      },
      "BillingEnrollmentIdempotencyKey": {
        "name": "X-Idempotency-Key",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string",
          "minLength": 16,
          "maxLength": 128,
          "pattern": "^[A-Za-z0-9_-]{16,128}$"
        },
        "description": "Stable identity for this immutable operation. Reuse exactly the same key and request after network loss. Never retry an unknown debit as a new operation."
      }
    },
    "schemas": {
      "CustomerObligationEditorResolution": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "action",
          "operation",
          "command"
        ],
        "properties": {
          "action": {
            "type": "string",
            "enum": [
              "retire_if_uncommitted"
            ]
          },
          "operation": {
            "type": "string",
            "enum": [
              "declare",
              "adjust",
              "legacy"
            ]
          },
          "obligationId": {
            "type": "string"
          },
          "command": {
            "type": "object"
          }
        },
        "oneOf": [
          {
            "properties": {
              "operation": {
                "enum": [
                  "declare"
                ]
              },
              "command": {
                "$ref": "#/components/schemas/CustomerObligationDeclaration"
              }
            },
            "not": {
              "required": [
                "obligationId"
              ]
            }
          },
          {
            "required": [
              "obligationId"
            ],
            "properties": {
              "operation": {
                "enum": [
                  "adjust"
                ]
              },
              "command": {
                "$ref": "#/components/schemas/CustomerObligationAdjustment"
              }
            }
          },
          {
            "properties": {
              "operation": {
                "enum": [
                  "legacy"
                ]
              },
              "command": {
                "$ref": "#/components/schemas/LegacyDebtUpdate"
              }
            },
            "not": {
              "required": [
                "obligationId"
              ]
            }
          }
        ],
        "description": "Exact frozen editor operation/body/key. Private command transaction returns saved evidence, or permanently retires an uncommitted new-generation attempt. Retirement does not write a customer balance, obligation or entry. HTTP status alone never permits a new key."
      },
      "CustomerObligationEditorResolutionAck": {
        "type": "object",
        "required": [
          "success",
          "state",
          "operation",
          "idempotencyKey",
          "commandId",
          "requestFingerprint",
          "fencedContractVersion",
          "legacyGenerationFenced"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "state": {
            "type": "string",
            "enum": [
              "saved",
              "retired"
            ]
          },
          "operation": {
            "type": "string",
            "enum": [
              "declare",
              "adjust",
              "legacy"
            ]
          },
          "idempotencyKey": {
            "type": "string"
          },
          "commandId": {
            "type": "string"
          },
          "requestFingerprint": {
            "type": "string",
            "pattern": "^[a-f0-9]{64}$"
          },
          "fencedContractVersion": {
            "type": "integer",
            "enum": [
              2
            ]
          },
          "legacyGenerationFenced": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "idempotentReplay": {
            "type": "boolean"
          },
          "ack": {
            "type": "object",
            "required": [
              "success",
              "idempotentReplay"
            ],
            "properties": {
              "success": {
                "type": "boolean",
                "enum": [
                  true
                ]
              },
              "id": {
                "type": "string"
              },
              "remainsUntyped": {
                "type": "boolean"
              },
              "idempotentReplay": {
                "type": "boolean",
                "enum": [
                  true
                ]
              }
            }
          }
        },
        "oneOf": [
          {
            "properties": {
              "state": {
                "enum": [
                  "saved"
                ]
              }
            },
            "required": [
              "ack"
            ]
          },
          {
            "properties": {
              "state": {
                "enum": [
                  "retired"
                ]
              }
            },
            "not": {
              "required": [
                "ack"
              ]
            }
          }
        ],
        "description": "Saved declare/adjust ACK includes id; saved legacy ACK includes remainsUntyped:true. Only matching retired ACK plus explicit current-owner refresh/review permits discarding frozen body. Older/unversioned/orphan outcomes are retained for review."
      },
      "ManualPaymentAttemptResolution": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "action",
          "command"
        ],
        "properties": {
          "action": {
            "type": "string",
            "enum": [
              "retire_if_uncommitted"
            ]
          },
          "command": {
            "$ref": "#/components/schemas/ManualPaymentCreateV2"
          }
        },
        "description": "Send the exact original frozen v2 body. Explicit owner/key namespace transaction returns its consistent saved ACK, or creates an immutable terminal uncommitted marker. No expiry or reuse of retired keys. No v1/old-generation outcome may be claimed, deleted or retired."
      },
      "ManualPaymentAttemptResolutionAck": {
        "type": "object",
        "required": [
          "success",
          "state",
          "idempotencyKey",
          "commandId",
          "requestFingerprint",
          "fencedContractVersion",
          "legacyGenerationFenced"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "state": {
            "type": "string",
            "enum": [
              "saved",
              "retired"
            ]
          },
          "idempotencyKey": {
            "type": "string"
          },
          "commandId": {
            "type": "string"
          },
          "requestFingerprint": {
            "type": "string",
            "pattern": "^[a-f0-9]{64}$"
          },
          "fencedContractVersion": {
            "type": "integer",
            "enum": [
              2
            ]
          },
          "legacyGenerationFenced": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "idempotentReplay": {
            "type": "boolean"
          },
          "ack": {
            "$ref": "#/components/schemas/ManualPaymentAck"
          }
        },
        "oneOf": [
          {
            "properties": {
              "state": {
                "enum": [
                  "saved"
                ]
              }
            },
            "required": [
              "ack"
            ]
          },
          {
            "properties": {
              "state": {
                "enum": [
                  "retired"
                ]
              }
            },
            "not": {
              "required": [
                "ack"
              ]
            }
          }
        ],
        "description": "Only a matching retired ACK plus explicit user refresh/review permits a fresh attempt. HTTP409, timeout, missing ACK or an absent-at-read status never permits a new key. Fence covers v2 and the new adapter only; no guarantee for independently running old-generation writes."
      },
      "CustomerObligationSummary": {
        "type": "object",
        "required": [
          "version",
          "quality",
          "amount",
          "knownAmount",
          "currency",
          "codes"
        ],
        "properties": {
          "version": {
            "type": "integer",
            "enum": [
              1
            ]
          },
          "quality": {
            "type": "string",
            "enum": [
              "complete",
              "unknown"
            ]
          },
          "amount": {
            "type": "number",
            "minimum": 0,
            "multipleOf": 0.01,
            "nullable": true
          },
          "knownAmount": {
            "type": "number",
            "minimum": 0,
            "multipleOf": 0.01,
            "nullable": true,
            "description": "Verified subtotal only. It is not a grand total when quality is unknown."
          },
          "currency": {
            "type": "string",
            "enum": [
              "ILS"
            ]
          },
          "debtCount": {
            "type": "integer",
            "minimum": 0
          },
          "pendingCount": {
            "type": "integer",
            "minimum": 0
          },
          "unknownCount": {
            "type": "integer",
            "minimum": 0
          },
          "codes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "description": "Only complete amount is a reconciled receivable. Unknown historical currency/link, partial/unacknowledged/stale legacy source, broken FK or incomplete source load returns null grand amount. Never replace null with0 or scalar+pending.",
        "oneOf": [
          {
            "properties": {
              "quality": {
                "enum": [
                  "complete"
                ]
              },
              "amount": {
                "type": "number",
                "minimum": 0
              },
              "knownAmount": {
                "type": "number",
                "minimum": 0
              }
            }
          },
          {
            "properties": {
              "quality": {
                "enum": [
                  "unknown"
                ]
              },
              "amount": {
                "type": "number",
                "nullable": true,
                "enum": [
                  null
                ]
              }
            }
          }
        ]
      },
      "CustomerObligation": {
        "type": "object",
        "required": [
          "id",
          "customerId",
          "currency",
          "origin",
          "revision",
          "principal",
          "outstanding",
          "reserved",
          "available"
        ],
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1500,
            "description": "Exact Firestore UTF-8 document ID (1500 bytes maximum); no slash, dot/dotdot, reserved __.*__ or malformed Unicode. Never normalize an ID as a phone."
          },
          "customerId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1500,
            "description": "Exact Firestore UTF-8 document ID (1500 bytes maximum); no slash, dot/dotdot, reserved __.*__ or malformed Unicode. Never normalize an ID as a phone."
          },
          "currency": {
            "type": "string",
            "enum": [
              "ILS"
            ]
          },
          "origin": {
            "type": "string",
            "enum": [
              "additional_plan",
              "explicit_existing_declaration"
            ]
          },
          "revision": {
            "type": "integer",
            "minimum": 1,
            "nullable": true
          },
          "principal": {
            "type": "number",
            "minimum": 0,
            "multipleOf": 0.01,
            "nullable": true
          },
          "outstanding": {
            "type": "number",
            "minimum": 0,
            "multipleOf": 0.01,
            "nullable": true
          },
          "reserved": {
            "type": "number",
            "minimum": 0,
            "multipleOf": 0.01,
            "nullable": true
          },
          "available": {
            "type": "number",
            "minimum": 0,
            "multipleOf": 0.01,
            "nullable": true
          },
          "originalPrincipal": {
            "type": "number",
            "minimum": 0,
            "nullable": true,
            "description": "Immutable original declaration; principal is the current immutable-entry projection including explicit adjustments."
          },
          "quality": {
            "type": "string",
            "enum": [
              "available",
              "invalid"
            ]
          },
          "selectable": {
            "type": "boolean",
            "description": "Malformed stored counters are unavailable, never silently zero. Server revalidates owner, currency, FK and revision in the write transaction."
          }
        }
      },
      "CustomerObligationRead": {
        "type": "object",
        "required": [
          "success",
          "customerId",
          "currency",
          "legacyEditable",
          "legacyEvidence",
          "obligations",
          "summary"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "customerId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1500,
            "description": "Exact Firestore UTF-8 document ID (1500 bytes maximum); no slash, dot/dotdot, reserved __.*__ or malformed Unicode. Never normalize an ID as a phone."
          },
          "currency": {
            "type": "string",
            "enum": [
              "ILS"
            ]
          },
          "legacyEditable": {
            "type": "boolean"
          },
          "legacyEvidence": {
            "type": "object",
            "required": [
              "sourceFingerprint",
              "amount",
              "state",
              "acknowledgedAmount"
            ],
            "properties": {
              "sourceFingerprint": {
                "type": "string"
              },
              "amount": {
                "type": "number",
                "minimum": 0,
                "multipleOf": 0.01,
                "nullable": true,
                "description": "Historical untyped source value, not inferred historical ILS."
              },
              "state": {
                "type": "string",
                "enum": [
                  "absent",
                  "untyped"
                ]
              },
              "acknowledgedAmount": {
                "type": "number",
                "minimum": 0,
                "multipleOf": 0.01
              }
            }
          },
          "obligations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomerObligation"
            }
          },
          "summary": {
            "$ref": "#/components/schemas/CustomerObligationSummary"
          }
        }
      },
      "CustomerObligationDeclaration": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "idempotencyKey",
          "amount",
          "currency",
          "reference"
        ],
        "properties": {
          "idempotencyKey": {
            "type": "string",
            "minLength": 16,
            "maxLength": 160,
            "pattern": "^[A-Za-z0-9_-]+$"
          },
          "amount": {
            "type": "number",
            "minimum": 0,
            "multipleOf": 0.01,
            "exclusiveMinimum": true
          },
          "currency": {
            "type": "string",
            "enum": [
              "ILS"
            ]
          },
          "reference": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300
          },
          "legacyAcknowledgement": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "sourceFingerprint",
              "amount",
              "acknowledged"
            ],
            "properties": {
              "sourceFingerprint": {
                "type": "string"
              },
              "amount": {
                "type": "number",
                "minimum": 0,
                "multipleOf": 0.01,
                "exclusiveMinimum": true
              },
              "acknowledged": {
                "type": "boolean",
                "enum": [
                  true
                ]
              }
            },
            "description": "Explicit current-owner acknowledgement of which current legacy snapshot this obligation covers, and present ILS declaration. Full covered source counts once. No historical currency/date/link inference; partial or later drift remains unknown."
          }
        }
      },
      "CustomerObligationAdjustment": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "idempotencyKey",
          "expectedRevision",
          "outstanding",
          "reason"
        ],
        "properties": {
          "idempotencyKey": {
            "type": "string",
            "minLength": 16,
            "maxLength": 160,
            "pattern": "^[A-Za-z0-9_-]+$"
          },
          "expectedRevision": {
            "type": "integer",
            "minimum": 1
          },
          "outstanding": {
            "type": "number",
            "minimum": 0,
            "multipleOf": 0.01
          },
          "reason": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300
          }
        },
        "description": "Explicit immutable adjustment, current revision required. Cannot reduce below active reservations; cancel/change schedule separately. Received money and issued accounting records are unchanged."
      },
      "LegacyDebtUpdate": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "idempotencyKey",
          "expectedSourceFingerprint",
          "debts"
        ],
        "properties": {
          "customerId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1500,
            "description": "Exact Firestore UTF-8 document ID (1500 bytes maximum); no slash, dot/dotdot, reserved __.*__ or malformed Unicode. Never normalize an ID as a phone."
          },
          "phone": {
            "type": "string"
          },
          "idempotencyKey": {
            "type": "string",
            "minLength": 16,
            "maxLength": 160,
            "pattern": "^[A-Za-z0-9_-]+$"
          },
          "expectedSourceFingerprint": {
            "type": "string"
          },
          "debts": {
            "type": "number",
            "minimum": 0,
            "multipleOf": 0.01
          }
        },
        "anyOf": [
          {
            "required": [
              "customerId"
            ]
          },
          {
            "required": [
              "phone"
            ]
          }
        ],
        "description": "Compatibility scalar update only, remains untyped. Transactional owner/source-revision guard; blocked for a typed/allocated context. No reset of typed balances."
      },
      "ManualPaymentUpdateAck": {
        "type": "object",
        "required": [
          "success",
          "id",
          "scheduledPaymentId",
          "partialReceipt",
          "idempotentReplay",
          "manualRevision"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1500,
            "description": "Exact Firestore UTF-8 document ID (1500 bytes maximum); no slash, dot/dotdot, reserved __.*__ or malformed Unicode. Never normalize an ID as a phone."
          },
          "scheduledPaymentId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1500,
            "description": "Exact Firestore UTF-8 document ID (1500 bytes maximum); no slash, dot/dotdot, reserved __.*__ or malformed Unicode. Never normalize an ID as a phone.",
            "nullable": true
          },
          "partialReceipt": {
            "type": "boolean"
          },
          "idempotentReplay": {
            "type": "boolean"
          },
          "manualRevision": {
            "type": "integer",
            "minimum": 1
          },
          "message": {
            "type": "string"
          }
        }
      },
      "ManualPaymentReceivedLocal": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "date",
          "time",
          "timeZone"
        ],
        "properties": {
          "date": {
            "type": "string",
            "format": "date"
          },
          "time": {
            "type": "string",
            "pattern": "^(?:[01]\\d|2[0-3]):[0-5]\\d$"
          },
          "timeZone": {
            "type": "string",
            "description": "Explicit IANA zone. Received UI preserves the device zone."
          },
          "utcOffsetMinutes": {
            "type": "number",
            "description": "East-of-UTC offset chosen explicitly when the local time occurs twice; preview returns choices."
          }
        }
      },
      "ManualPaymentSchedule": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "startDate",
          "time",
          "timeZone",
          "months",
          "type"
        ],
        "properties": {
          "startDate": {
            "type": "string",
            "format": "date"
          },
          "time": {
            "type": "string",
            "pattern": "^(?:[01]\\d|2[0-3]):[0-5]\\d$"
          },
          "timeZone": {
            "type": "string",
            "enum": [
              "Asia/Jerusalem"
            ]
          },
          "months": {
            "type": "integer",
            "minimum": 2,
            "maximum": 12
          },
          "type": {
            "type": "string",
            "enum": [
              "equal",
              "full"
            ],
            "description": "equal: entered amount/cost is divided exactly in cents; full: entered amount/cost repeats each month."
          }
        }
      },
      "ManualPaymentCreateV2": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "manualContractVersion",
          "intent",
          "amount",
          "customerName",
          "customerPhone",
          "paymentMethod",
          "idempotencyKey"
        ],
        "properties": {
          "manualContractVersion": {
            "type": "integer",
            "enum": [
              2
            ]
          },
          "intent": {
            "type": "string",
            "enum": [
              "received",
              "planned"
            ]
          },
          "idempotencyKey": {
            "type": "string",
            "minLength": 16,
            "maxLength": 160,
            "pattern": "^[A-Za-z0-9_-]+$",
            "description": "Owner-bound stable attempt key. Freeze the exact body and retain it when the outcome is unknown; never replace the key to retry."
          },
          "amount": {
            "type": "number",
            "exclusiveMinimum": true,
            "minimum": 0,
            "multipleOf": 0.01
          },
          "expectedCost": {
            "type": "number",
            "minimum": 0,
            "multipleOf": 0.01
          },
          "customerName": {
            "type": "string",
            "minLength": 2,
            "maxLength": 160
          },
          "customerPhone": {
            "type": "string"
          },
          "customerEmail": {
            "type": "string",
            "nullable": true
          },
          "paymentMethod": {
            "type": "string",
            "enum": [
              "cash",
              "bank_transfer",
              "check",
              "credit_card",
              "other"
            ]
          },
          "description": {
            "type": "string",
            "nullable": true,
            "maxLength": 2000
          },
          "transactionNumber": {
            "type": "string",
            "nullable": true
          },
          "transactionTotal": {
            "type": "number",
            "exclusiveMinimum": true,
            "minimum": 0,
            "multipleOf": 0.01,
            "description": "Complete original transaction/series context; never a smaller per-installment substitute."
          },
          "cashAmount": {
            "type": "number",
            "minimum": 0,
            "multipleOf": 0.01
          },
          "receivedAt": {
            "type": "string",
            "format": "date-time",
            "description": "Explicit actual receipt instant with zone; no date-only, createdAt fallback or future cash receipt."
          },
          "receivedLocal": {
            "$ref": "#/components/schemas/ManualPaymentReceivedLocal"
          },
          "schedule": {
            "$ref": "#/components/schemas/ManualPaymentSchedule"
          },
          "scheduledAt": {
            "type": "string",
            "format": "date-time"
          },
          "scheduledDate": {
            "type": "string",
            "format": "date",
            "description": "Explicit day-precision planned date; never an actual receipt timestamp."
          },
          "customerId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1500,
            "description": "Exact Firestore UTF-8 document ID (1500 bytes maximum); no slash, dot/dotdot, reserved __.*__ or malformed Unicode. Never normalize an ID as a phone."
          },
          "debtIntent": {
            "type": "string",
            "enum": [
              "existing",
              "additional"
            ]
          },
          "obligationId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1500,
            "description": "Exact Firestore UTF-8 document ID (1500 bytes maximum); no slash, dot/dotdot, reserved __.*__ or malformed Unicode. Never normalize an ID as a phone."
          },
          "expectedObligationRevision": {
            "type": "integer",
            "minimum": 1
          }
        },
        "oneOf": [
          {
            "properties": {
              "intent": {
                "enum": [
                  "received"
                ]
              }
            },
            "description": "When both receivedAt and receivedLocal are supplied, they must resolve to exactly the same instant.",
            "anyOf": [
              {
                "required": [
                  "receivedAt"
                ]
              },
              {
                "required": [
                  "receivedLocal"
                ]
              }
            ],
            "not": {
              "anyOf": [
                {
                  "required": [
                    "schedule"
                  ]
                },
                {
                  "required": [
                    "scheduledAt"
                  ]
                },
                {
                  "required": [
                    "scheduledDate"
                  ]
                },
                {
                  "required": [
                    "customerId"
                  ]
                },
                {
                  "required": [
                    "debtIntent"
                  ]
                },
                {
                  "required": [
                    "obligationId"
                  ]
                },
                {
                  "required": [
                    "expectedObligationRevision"
                  ]
                }
              ]
            }
          },
          {
            "properties": {
              "intent": {
                "enum": [
                  "planned"
                ]
              }
            },
            "oneOf": [
              {
                "required": [
                  "schedule"
                ]
              },
              {
                "required": [
                  "scheduledAt"
                ]
              },
              {
                "required": [
                  "scheduledDate"
                ]
              }
            ],
            "not": {
              "anyOf": [
                {
                  "required": [
                    "receivedAt"
                  ]
                },
                {
                  "required": [
                    "receivedLocal"
                  ]
                }
              ]
            },
            "required": [
              "customerId",
              "debtIntent"
            ],
            "allOf": [
              {
                "oneOf": [
                  {
                    "properties": {
                      "debtIntent": {
                        "enum": [
                          "existing"
                        ]
                      }
                    },
                    "required": [
                      "obligationId",
                      "expectedObligationRevision"
                    ]
                  },
                  {
                    "properties": {
                      "debtIntent": {
                        "enum": [
                          "additional"
                        ]
                      }
                    },
                    "not": {
                      "anyOf": [
                        {
                          "required": [
                            "obligationId"
                          ]
                        },
                        {
                          "required": [
                            "expectedObligationRevision"
                          ]
                        }
                      ]
                    }
                  }
                ]
              }
            ]
          }
        ]
      },
      "ManualPaymentPreviewRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "manualContractVersion",
          "intent",
          "amount",
          "customerName",
          "customerPhone",
          "paymentMethod"
        ],
        "properties": {
          "manualContractVersion": {
            "type": "integer",
            "enum": [
              2
            ]
          },
          "intent": {
            "type": "string",
            "enum": [
              "received",
              "planned"
            ]
          },
          "idempotencyKey": {
            "type": "string",
            "minLength": 16,
            "maxLength": 160,
            "pattern": "^[A-Za-z0-9_-]+$",
            "description": "Owner-bound stable attempt key. Freeze the exact body and retain it when the outcome is unknown; never replace the key to retry."
          },
          "amount": {
            "type": "number",
            "exclusiveMinimum": true,
            "minimum": 0,
            "multipleOf": 0.01
          },
          "expectedCost": {
            "type": "number",
            "minimum": 0,
            "multipleOf": 0.01
          },
          "customerName": {
            "type": "string",
            "minLength": 2,
            "maxLength": 160
          },
          "customerPhone": {
            "type": "string"
          },
          "customerEmail": {
            "type": "string",
            "nullable": true
          },
          "paymentMethod": {
            "type": "string",
            "enum": [
              "cash",
              "bank_transfer",
              "check",
              "credit_card",
              "other"
            ]
          },
          "description": {
            "type": "string",
            "nullable": true,
            "maxLength": 2000
          },
          "transactionNumber": {
            "type": "string",
            "nullable": true
          },
          "transactionTotal": {
            "type": "number",
            "exclusiveMinimum": true,
            "minimum": 0,
            "multipleOf": 0.01,
            "description": "Complete original transaction/series context; never a smaller per-installment substitute."
          },
          "cashAmount": {
            "type": "number",
            "minimum": 0,
            "multipleOf": 0.01
          },
          "receivedAt": {
            "type": "string",
            "format": "date-time",
            "description": "Explicit actual receipt instant with zone; no date-only, createdAt fallback or future cash receipt."
          },
          "receivedLocal": {
            "$ref": "#/components/schemas/ManualPaymentReceivedLocal"
          },
          "schedule": {
            "$ref": "#/components/schemas/ManualPaymentSchedule"
          },
          "scheduledAt": {
            "type": "string",
            "format": "date-time"
          },
          "scheduledDate": {
            "type": "string",
            "format": "date",
            "description": "Explicit day-precision planned date; never an actual receipt timestamp."
          },
          "customerId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1500,
            "description": "Exact Firestore UTF-8 document ID (1500 bytes maximum); no slash, dot/dotdot, reserved __.*__ or malformed Unicode. Never normalize an ID as a phone."
          },
          "debtIntent": {
            "type": "string",
            "enum": [
              "existing",
              "additional"
            ]
          },
          "obligationId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1500,
            "description": "Exact Firestore UTF-8 document ID (1500 bytes maximum); no slash, dot/dotdot, reserved __.*__ or malformed Unicode. Never normalize an ID as a phone."
          },
          "expectedObligationRevision": {
            "type": "integer",
            "minimum": 1
          }
        },
        "oneOf": [
          {
            "properties": {
              "intent": {
                "enum": [
                  "received"
                ]
              }
            },
            "description": "When both receivedAt and receivedLocal are supplied, they must resolve to exactly the same instant.",
            "anyOf": [
              {
                "required": [
                  "receivedAt"
                ]
              },
              {
                "required": [
                  "receivedLocal"
                ]
              }
            ],
            "not": {
              "anyOf": [
                {
                  "required": [
                    "schedule"
                  ]
                },
                {
                  "required": [
                    "scheduledAt"
                  ]
                },
                {
                  "required": [
                    "scheduledDate"
                  ]
                },
                {
                  "required": [
                    "customerId"
                  ]
                },
                {
                  "required": [
                    "debtIntent"
                  ]
                },
                {
                  "required": [
                    "obligationId"
                  ]
                },
                {
                  "required": [
                    "expectedObligationRevision"
                  ]
                }
              ]
            }
          },
          {
            "properties": {
              "intent": {
                "enum": [
                  "planned"
                ]
              }
            },
            "oneOf": [
              {
                "required": [
                  "schedule"
                ]
              },
              {
                "required": [
                  "scheduledAt"
                ]
              },
              {
                "required": [
                  "scheduledDate"
                ]
              }
            ],
            "not": {
              "anyOf": [
                {
                  "required": [
                    "receivedAt"
                  ]
                },
                {
                  "required": [
                    "receivedLocal"
                  ]
                }
              ]
            },
            "required": [
              "customerId",
              "debtIntent"
            ],
            "allOf": [
              {
                "oneOf": [
                  {
                    "properties": {
                      "debtIntent": {
                        "enum": [
                          "existing"
                        ]
                      }
                    },
                    "required": [
                      "obligationId",
                      "expectedObligationRevision"
                    ]
                  },
                  {
                    "properties": {
                      "debtIntent": {
                        "enum": [
                          "additional"
                        ]
                      }
                    },
                    "not": {
                      "anyOf": [
                        {
                          "required": [
                            "obligationId"
                          ]
                        },
                        {
                          "required": [
                            "expectedObligationRevision"
                          ]
                        }
                      ]
                    }
                  }
                ]
              }
            ]
          }
        ]
      },
      "ManualPaymentReceiptPatch": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "amount": {
            "type": "number",
            "exclusiveMinimum": true,
            "minimum": 0,
            "multipleOf": 0.01
          },
          "expectedCost": {
            "type": "number",
            "minimum": 0,
            "multipleOf": 0.01
          },
          "customerName": {
            "type": "string",
            "minLength": 2,
            "maxLength": 160
          },
          "customerPhone": {
            "type": "string"
          },
          "customerEmail": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true,
            "maxLength": 2000
          },
          "paymentMethod": {
            "type": "string",
            "enum": [
              "cash",
              "bank_transfer",
              "check",
              "credit_card",
              "other"
            ]
          },
          "receivedAt": {
            "type": "string",
            "format": "date-time",
            "description": "Explicit actual receipt instant with zone; no date-only, createdAt fallback or future cash receipt."
          },
          "receivedLocal": {
            "$ref": "#/components/schemas/ManualPaymentReceivedLocal"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "completed",
              "failed",
              "cancelled",
              "expired"
            ]
          },
          "archived": {
            "type": "boolean"
          },
          "expectedManualRevision": {
            "type": "integer",
            "minimum": 0,
            "description": "Required for a receipt and financial/metadata edits on a v2 pending row; use the loaded manualRevision."
          },
          "manualReceiptKey": {
            "type": "string",
            "minLength": 16,
            "maxLength": 160,
            "pattern": "^[A-Za-z0-9_-]+$",
            "description": "Owner-bound stable attempt key. Freeze the exact body and retain it when the outcome is unknown; never replace the key to retry."
          },
          "receivedAmount": {
            "type": "number",
            "minimum": 0,
            "multipleOf": 0.01,
            "exclusiveMinimum": true,
            "description": "Optional actual partial receipt against a typed allocation, bounded by remaining amount. Omitted means full remaining receipt. A partial receipt creates one deterministic completed cash child; original scheduled row remains pending remainder. Freeze exact body/key across unknown responses."
          }
        },
        "description": "Full actual receipt completes the same manual row. Typed partial receipt settles exactly the cash child and leaves original pending remainder, with exact cent/cost allocation. Server selects none for linked debt projection; immutable FK and accounting locks remain. Cancellation releases collection reservation and does not forgive debt or undo received cash.",
        "oneOf": [
          {
            "required": [
              "status",
              "manualReceiptKey",
              "expectedManualRevision"
            ],
            "properties": {
              "status": {
                "enum": [
                  "completed"
                ]
              }
            },
            "anyOf": [
              {
                "required": [
                  "receivedAt"
                ]
              },
              {
                "required": [
                  "receivedLocal"
                ]
              }
            ]
          },
          {
            "allOf": [
              {
                "not": {
                  "required": [
                    "status"
                  ],
                  "properties": {
                    "status": {
                      "enum": [
                        "completed"
                      ]
                    }
                  }
                }
              },
              {
                "not": {
                  "anyOf": [
                    {
                      "required": [
                        "receivedAt"
                      ]
                    },
                    {
                      "required": [
                        "receivedLocal"
                      ]
                    },
                    {
                      "required": [
                        "manualReceiptKey"
                      ]
                    },
                    {
                      "required": [
                        "receivedAmount"
                      ]
                    }
                  ]
                }
              }
            ]
          }
        ]
      },
      "ManualPaymentAck": {
        "type": "object",
        "required": [
          "success",
          "kind",
          "ids",
          "count",
          "idempotentReplay",
          "idempotencyProtected"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "kind": {
            "type": "string",
            "enum": [
              "received",
              "planned_single",
              "planned_group"
            ]
          },
          "id": {
            "type": "string",
            "nullable": true
          },
          "ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "commandId": {
            "type": "string",
            "nullable": true
          },
          "count": {
            "type": "integer",
            "minimum": 1,
            "maximum": 12
          },
          "idempotentReplay": {
            "type": "boolean"
          },
          "idempotencyProtected": {
            "type": "boolean"
          },
          "message": {
            "type": "string"
          }
        }
      },
      "ManualPaymentError": {
        "type": "object",
        "required": [
          "success",
          "error"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "errorCode": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "error": {
            "type": "string"
          },
          "field": {
            "type": "string"
          },
          "choices": {
            "type": "array",
            "maxItems": 2,
            "items": {
              "type": "object",
              "properties": {
                "utcOffsetMinutes": {
                  "type": "number"
                },
                "receivedAt": {
                  "type": "string",
                  "format": "date-time"
                },
                "label": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "ExternalDocumentProviderSettings": {
        "type": "object",
        "required": [
          "activeProvider",
          "configVersion",
          "readinessSource",
          "cardcom",
          "capabilities"
        ],
        "additionalProperties": false,
        "description": "Safe summary for the business owner resolved from the API key. Contains selection and recorded readiness only; no credentials, binding identity, evidence references, or provider provisioning result.",
        "properties": {
          "activeProvider": {
            "type": "string",
            "enum": [
              "internal",
              "cardcom"
            ]
          },
          "configVersion": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Read this version before changing the provider. Send it as expectedVersion."
          },
          "readinessSource": {
            "type": "string",
            "enum": [
              "stored_evidence"
            ],
            "description": "The endpoint reads stored readiness evidence; it does not contact CardCom."
          },
          "cardcom": {
            "type": "object",
            "required": [
              "configured",
              "canSelect",
              "readiness",
              "blockers"
            ],
            "additionalProperties": false,
            "properties": {
              "configured": {
                "type": "boolean"
              },
              "canSelect": {
                "type": "boolean",
                "description": "Current release and readiness gates allow selection. Recheck when acting; this is not a provider provisioning result."
              },
              "readiness": {
                "type": "string",
                "enum": [
                  "ready",
                  "read_verified",
                  "not_verified"
                ]
              },
              "blockers": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "capabilities": {
            "type": "object",
            "additionalProperties": false,
            "description": "Safe recorded capabilities for the existing provider binding. Optional arrays only. These do not grant API scopes or prove provider acceptance.",
            "properties": {
              "currencies": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "paymentMethods": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "issuanceTypes": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "correctionTypes": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "ExternalDocumentProviderSettingsResponse": {
        "type": "object",
        "required": [
          "success",
          "settings"
        ],
        "additionalProperties": false,
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "settings": {
            "$ref": "#/components/schemas/ExternalDocumentProviderSettings"
          }
        }
      },
      "ExternalDocumentProviderSelectionRequest": {
        "type": "object",
        "required": [
          "provider",
          "expectedVersion"
        ],
        "additionalProperties": false,
        "properties": {
          "provider": {
            "type": "string",
            "enum": [
              "internal",
              "cardcom"
            ]
          },
          "expectedVersion": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Current configVersion from GET /external/document-provider. A stale version returns 409."
          }
        }
      },
      "ExternalDocumentProviderSelectionResponse": {
        "type": "object",
        "required": [
          "success",
          "settings",
          "operationId",
          "replayed",
          "selection"
        ],
        "additionalProperties": false,
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "settings": {
            "$ref": "#/components/schemas/ExternalDocumentProviderSettings"
          },
          "operationId": {
            "type": "string",
            "minLength": 1,
            "description": "Stable identity of the selection operation; not a document-issuance operation."
          },
          "replayed": {
            "type": "boolean",
            "description": "true when the same completed key and payload return the original selection without another provider switch. settings contains current settings, which can differ after a later change."
          },
          "selection": {
            "type": "object",
            "required": [
              "activeProvider",
              "configVersion"
            ],
            "additionalProperties": false,
            "description": "The selection recorded by the original successful operation, even if the current settings changed later.",
            "properties": {
              "activeProvider": {
                "type": "string",
                "enum": [
                  "internal",
                  "cardcom"
                ]
              },
              "configVersion": {
                "type": "integer",
                "minimum": 0,
                "maximum": 9007199254740991
              }
            }
          }
        }
      },
      "DocumentProviderScopesRequest": {
        "type": "object",
        "required": [
          "scopes",
          "expectedVersion"
        ],
        "additionalProperties": false,
        "properties": {
          "scopes": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "documents.providers.read",
                "documents.providers.write"
              ]
            },
            "description": "Replacement for this client's document-provider scope subset. [] revokes both provider scopes. Other scopes are retained. Write does not implicitly grant read. Duplicate provider scopes are normalized."
          },
          "expectedVersion": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Current documentProviderScopesVersion for this client; use 0 when no provider-scope version has been recorded. A stale version returns 409."
          }
        }
      },
      "OwnerApiClientCreateRequest": {
        "type": "object",
        "required": [
          "clientName"
        ],
        "additionalProperties": true,
        "description": "Existing owner API-key creation body with an optional explicit document-provider scope subset. Other existing client fields retain their usual form semantics. Omitting documentProviderScopes grants no provider permissions.",
        "properties": {
          "clientName": {
            "type": "string",
            "minLength": 1
          },
          "documentProviderScopes": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "documents.providers.read",
                "documents.providers.write"
              ]
            },
            "description": "Explicit optional provider permissions for this ordinary client. Omitted or [] means no provider permissions."
          }
        }
      },
      "OwnerApiClientUpdateRequest": {
        "type": "object",
        "required": [
          "clientName"
        ],
        "additionalProperties": true,
        "description": "Existing owner API-key editing body. Preserve the current editable client fields when saving the form. documentProviderScopes replaces only the provider subset; expectedProviderScopesVersion is required when that subset is supplied. Omitting documentProviderScopes leaves the provider subset unchanged. Use the dedicated scope route when changing only permissions.",
        "properties": {
          "clientName": {
            "type": "string",
            "minLength": 1
          },
          "documentProviderScopes": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "documents.providers.read",
                "documents.providers.write"
              ]
            }
          },
          "expectedProviderScopesVersion": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Required when documentProviderScopes is included. Current client.documentProviderScopesVersion."
          }
        },
        "oneOf": [
          {
            "required": [
              "documentProviderScopes",
              "expectedProviderScopesVersion"
            ]
          },
          {
            "not": {
              "required": [
                "documentProviderScopes"
              ]
            }
          }
        ]
      },
      "OwnerApiClientCreateResponse": {
        "type": "object",
        "required": [
          "success",
          "clientId",
          "apiKey",
          "client"
        ],
        "description": "Returned only to the authenticated owner. apiKey is the new secret and is revealed once; keep it server-side and do not expose it in payment pages or logs.",
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "clientId": {
            "type": "string"
          },
          "apiKey": {
            "type": "string",
            "writeOnly": false,
            "description": "One-time owner-only API-key creation result."
          },
          "client": {
            "$ref": "#/components/schemas/DocumentProviderScopeClient"
          }
        }
      },
      "DocumentProviderScopeClient": {
        "type": "object",
        "required": [
          "documentProviderScopesVersion"
        ],
        "additionalProperties": true,
        "description": "The updated owner-visible API client. Existing safe client fields are retained; API credentials are not returned by this operation.",
        "properties": {
          "id": {
            "type": "string"
          },
          "allowedScopes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "All retained client scopes, including its updated provider-scope subset."
          },
          "documentProviderScopesVersion": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991
          }
        }
      },
      "DocumentProviderScopesResponse": {
        "type": "object",
        "required": [
          "success",
          "client"
        ],
        "additionalProperties": false,
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "client": {
            "$ref": "#/components/schemas/DocumentProviderScopeClient"
          }
        }
      },
      "DocumentProviderApiError": {
        "type": "object",
        "required": [
          "success",
          "error"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "error": {
            "type": "string"
          },
          "errorCode": {
            "type": "string"
          },
          "code": {
            "type": "string",
            "description": "May be returned by the existing authentication guard."
          },
          "safeToEdit": {
            "type": "boolean"
          },
          "operationId": {
            "type": "string"
          }
        }
      },
      "BusinessProfileResponse": {
        "type": "object",
        "required": [
          "success",
          "businessProfile"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "businessProfile": {
            "$ref": "#/components/schemas/BusinessProfile"
          }
        }
      },
      "DocumentProviderSettings": {
        "type": "object",
        "required": [
          "activeProvider",
          "configVersion",
          "bindingId",
          "releaseEnabled",
          "connection",
          "capabilities",
          "cardcom"
        ],
        "description": "Current document-issuer selection and assessed readiness. Credentials, contract hashes and evidence references are not returned. releaseEnabled and readiness both constrain CardCom selection.",
        "properties": {
          "activeProvider": {
            "type": "string",
            "enum": [
              "internal",
              "cardcom"
            ]
          },
          "configVersion": {
            "type": "integer",
            "minimum": 0,
            "description": "Use this current version as expectedVersion when changing the selection."
          },
          "bindingId": {
            "type": "string",
            "nullable": true,
            "description": "Current binding identifier; null for the default internal selection."
          },
          "releaseEnabled": {
            "type": "boolean",
            "description": "Server release gate; configured credentials alone do not enable CardCom issuance."
          },
          "connection": {
            "type": "object",
            "required": [
              "configured",
              "readVerified",
              "issuanceReady",
              "blockers",
              "capabilities"
            ],
            "properties": {
              "configured": {
                "type": "boolean"
              },
              "readVerified": {
                "type": "boolean",
                "description": "A successful read check matched the current credential identity and environment."
              },
              "issuanceReady": {
                "type": "boolean",
                "description": "The binding passed the required activation checks; a successful read check alone is insufficient."
              },
              "blockers": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "capabilities": {
                "type": "object",
                "description": "Recorded provider capabilities for this binding; not credentials or a provisioning result. The fields depend on its verified contract.",
                "additionalProperties": true
              },
              "readinessScope": {
                "type": "string",
                "description": "Present for an assessed binding; currently activation."
              }
            }
          },
          "capabilities": {
            "type": "object",
            "description": "Recorded provider capabilities for this binding; not credentials or a provisioning result. The fields depend on its verified contract.",
            "additionalProperties": true
          },
          "cardcom": {
            "type": "object",
            "required": [
              "configured",
              "canSelect",
              "readiness",
              "blockers"
            ],
            "properties": {
              "configured": {
                "type": "boolean"
              },
              "canSelect": {
                "type": "boolean"
              },
              "readiness": {
                "type": "string",
                "enum": [
                  "ready",
                  "read_verified",
                  "not_verified"
                ]
              },
              "blockers": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "DocumentProviderSettingsResponse": {
        "type": "object",
        "required": [
          "success",
          "settings"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "settings": {
            "$ref": "#/components/schemas/DocumentProviderSettings"
          }
        }
      },
      "DocumentProviderSelectionRequest": {
        "type": "object",
        "required": [
          "provider",
          "expectedVersion"
        ],
        "properties": {
          "provider": {
            "type": "string",
            "enum": [
              "internal",
              "cardcom"
            ]
          },
          "expectedVersion": {
            "type": "integer",
            "minimum": 0,
            "description": "Current configVersion from GET /api/document-provider. A stale version returns 409 DOCUMENT_PROVIDER_VERSION_CONFLICT."
          }
        }
      },
      "DocumentProviderOperationResponse": {
        "type": "object",
        "required": [
          "success",
          "operation"
        ],
        "description": "Read the existing owner-scoped operation. This endpoint does not send a new issuance or reconcile the provider result.",
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "operation": {
            "type": "object",
            "required": [
              "operationId",
              "state",
              "documentId",
              "safeToEdit",
              "canCompleteLocally",
              "result"
            ],
            "properties": {
              "operationId": {
                "type": "string"
              },
              "state": {
                "type": "string",
                "description": "Stored provider state, such as reserved, provider_sending, outcome_unknown, rejected, provider_accepted or finalized; internal is the fallback. provider_accepted is not finalization."
              },
              "documentId": {
                "type": "string",
                "nullable": true
              },
              "safeToEdit": {
                "type": "boolean",
                "enum": [
                  false
                ],
                "description": "The status response never authorizes changing the issuance identity or payload."
              },
              "canCompleteLocally": {
                "type": "boolean",
                "description": "True only for eligible provider_accepted operation kinds; it is not a completion confirmation."
              },
              "result": {
                "type": "object",
                "nullable": true,
                "additionalProperties": true,
                "description": "Finalized public result projection; null until finalized."
              }
            }
          }
        }
      },
      "AccountingDocumentError": {
        "type": "object",
        "description": "Inspect errorCode and safeToEdit. An operationId or unknown provider outcome means the existing issuance needs reconciliation; do not create a replacement identity or assume the document failed.",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "error": {
            "type": "string"
          },
          "errorCode": {
            "type": "string"
          },
          "safeToEdit": {
            "type": "boolean"
          },
          "operationId": {
            "type": "string"
          }
        }
      },
      "AccountingDocumentCreateResponse": {
        "type": "object",
        "description": "Existing document aliases remain available. A provider result returns the original published PDF only after finalization. Issuance does not send a customer message or perform a monetary refund.",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "documentId": {
            "type": "string"
          },
          "documentNumber": {
            "type": "string"
          },
          "documentType": {
            "type": "string"
          },
          "invoiceId": {
            "type": "string"
          },
          "invoiceNumber": {
            "type": "string"
          },
          "receiptId": {
            "type": "string"
          },
          "receiptNumber": {
            "type": "string"
          },
          "invoiceReceiptId": {
            "type": "string"
          },
          "pdfUrl": {
            "type": "string"
          },
          "amount": {
            "type": "number"
          },
          "totalAmount": {
            "type": "number"
          },
          "currency": {
            "type": "string"
          },
          "issuerProvider": {
            "type": "string"
          },
          "idempotentReplay": {
            "type": "boolean"
          },
          "testMode": {
            "type": "boolean"
          }
        }
      },
      "RecurringApiError": {
        "type": "object",
        "description": "Operation error. errorCode appears only on routes that return a code. The existing internal requireAuth guard may return only error=Unauthorized.",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "error": {
            "type": "string"
          },
          "errorCode": {
            "type": "string"
          }
        }
      },
      "RecurringStatusResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "status": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "chargeInFlight": {
            "type": "boolean",
            "description": "A charge already sent to the provider may still complete. Cancellation does not refund or reverse an existing transaction."
          },
          "recurringPayment": {
            "$ref": "#/components/schemas/RecurringPayment"
          }
        }
      },
      "RecurringReadResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "recurringPayment": {
            "$ref": "#/components/schemas/RecurringPayment"
          }
        }
      },
      "RecurringPageInfo": {
        "type": "object",
        "properties": {
          "hasMore": {
            "type": "boolean"
          },
          "nextCursor": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "RecurringListResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "recurringPayments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RecurringListItem"
            }
          },
          "count": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "nullable": true
          },
          "pageInfo": {
            "$ref": "#/components/schemas/RecurringPageInfo"
          }
        }
      },
      "RecurringListItem": {
        "type": "object",
        "description": "List summary without the full phone number, email address, or card token. Read a single recurring instruction for details.",
        "properties": {
          "id": {
            "type": "string"
          },
          "customerName": {
            "type": "string",
            "nullable": true
          },
          "customerPhoneSuffix": {
            "type": "string",
            "nullable": true
          },
          "customerEmailHint": {
            "type": "string",
            "nullable": true
          },
          "amount": {
            "type": "number"
          },
          "currency": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string"
          },
          "frequency": {
            "type": "string"
          },
          "interval": {
            "type": "integer"
          },
          "totalBills": {
            "type": "integer"
          },
          "billsCharged": {
            "type": "integer"
          },
          "status": {
            "type": "string"
          },
          "isActive": {
            "type": "boolean"
          },
          "billingMode": {
            "type": "string",
            "nullable": true
          },
          "nextBillDate": {
            "type": "string",
            "nullable": true
          },
          "lastChargeDate": {
            "type": "string",
            "nullable": true
          },
          "cancelAtPeriodEnd": {
            "type": "boolean"
          },
          "cancellationEffectiveAt": {
            "type": "string",
            "nullable": true
          },
          "chargeContext": {
            "$ref": "#/components/schemas/RecurringChargeContext"
          },
          "capabilities": {
            "$ref": "#/components/schemas/RecurringCapabilities"
          }
        }
      },
      "RecurringSummary": {
        "type": "object",
        "properties": {
          "confirmedCount": {
            "type": "integer"
          },
          "unresolvedCount": {
            "type": "integer"
          },
          "partial": {
            "type": "boolean"
          },
          "bankSettlementConfirmed": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "totals": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "currency": {
                  "type": "string"
                },
                "grossMinor": {
                  "type": "integer"
                },
                "refundedMinor": {
                  "type": "integer"
                },
                "netMinor": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "RecurringHistoryEntry": {
        "type": "object",
        "description": "A history record is not in itself proof of collection. The summary is calculated from verified transactions; In the internal interface paymentVerified and isManual are added to the record. Externally, you should also check billingMode/isManual in the instruction itself.",
        "properties": {
          "id": {
            "type": "string"
          },
          "paymentId": {
            "type": "string",
            "nullable": true
          },
          "billNumber": {
            "type": "integer",
            "nullable": true
          },
          "amount": {
            "type": "number",
            "nullable": true
          },
          "currency": {
            "type": "string",
            "nullable": true
          },
          "chargeDate": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "status": {
            "type": "string"
          },
          "transactionId": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "isManual": {
            "type": "boolean"
          },
          "paymentVerified": {
            "type": "boolean"
          },
          "paymentStatus": {
            "type": "string"
          },
          "refundAmount": {
            "type": "number"
          },
          "document": {
            "type": "object",
            "nullable": true
          },
          "workflow": {
            "type": "object",
            "nullable": true
          }
        }
      },
      "RecurringHistoryResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "history": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RecurringHistoryEntry"
            }
          },
          "count": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "pageInfo": {
            "$ref": "#/components/schemas/RecurringPageInfo"
          },
          "summary": {
            "$ref": "#/components/schemas/RecurringSummary"
          }
        }
      },
      "InternalRecurringListResponse": {
        "type": "object",
        "description": "payments includes recurring instructions and pending approval requests. incomplete means the list is limited. This response differs from recurringPayments in the external API.",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "payments": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "incomplete": {
            "type": "boolean"
          },
          "schedulerHealth": {
            "type": "object"
          },
          "customerProjectionHealth": {
            "type": "object"
          }
        }
      },
      "InternalRecurringHistoryResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "history": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RecurringHistoryEntry"
            }
          },
          "summary": {
            "$ref": "#/components/schemas/RecurringSummary"
          },
          "historyPartial": {
            "type": "boolean"
          },
          "originalApprovalLink": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "InternalRecurringStatusRequest": {
        "type": "object",
        "required": [
          "status"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "active",
              "paused",
              "cancelled"
            ]
          },
          "cancelReason": {
            "type": "string"
          }
        }
      },
      "RecurringWorkflows": {
        "type": "object",
        "description": "The settings replace the previous settings, and apply to future charges only. The default is off. Delivery channels require documentAfterCharge=true, recipient details, proper configuration and recipient consent; queued or provider_accepted is not a delivery confirmation.",
        "properties": {
          "documentAfterCharge": {
            "type": "boolean",
            "default": false
          },
          "channels": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "email",
                "whatsapp"
              ]
            },
            "default": []
          },
          "notifyOwnerOnFailure": {
            "type": "boolean",
            "default": false
          },
          "notifyOwnerOnCompletion": {
            "type": "boolean",
            "default": false
          }
        }
      },
      "RecurringReconcileResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "chargeCreated": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "paymentId": {
            "type": "string",
            "nullable": true
          },
          "recurringPaymentId": {
            "type": "string",
            "nullable": true
          },
          "outcome": {
            "type": "string"
          }
        }
      },
      "CreatePaymentRequest": {
        "type": "object",
        "required": [
          "amount",
          "description"
        ],
        "properties": {
          "amount": {
            "type": "number",
            "maximum": 10000000,
            "description": "A positive amount in the selected currency. An exact number must be sent, without additional characters; A value like 110abc will be rejected.",
            "minimum": 0,
            "exclusiveMinimum": true
          },
          "description": {
            "type": "string",
            "description": "Payment description"
          },
          "customerName": {
            "type": "string"
          },
          "customerPhone": {
            "type": "string",
            "description": "Format: 05XXXXXXXX"
          },
          "customerEmail": {
            "type": "string"
          },
          "numOfPayments": {
            "type": "integer",
            "default": 1,
            "minimum": 1,
            "maximum": 36,
            "description": "Integer number of payments between 1 and 36; If not sent, defaults to 1."
          },
          "currency": {
            "type": "string",
            "enum": [
              "ILS",
              "USD"
            ],
            "default": "ILS",
            "description": "Payment currency. The server trims whitespace and normalizes case; omit it for ILS. Unsupported values return 400 INVALID_CURRENCY for a one-time payment, or 400 RECURRING_CURRENCY_UNSUPPORTED for a recurring request, before creating a payment or making a provider call. Dedicated SaaS clients must also match their approved plan currency. The chosen document-provider binding must separately permit the requested currency for new payments."
          },
          "webhookUrl": {
            "type": "string",
            "description": "URL for status updates"
          },
          "metadata": {
            "type": "object",
            "description": "In SaaS v1 only planId, planVersion and billingConsentId are saved."
          },
          "contractVersion": {
            "type": "string",
            "enum": [
              "saas-v1"
            ],
            "description": "Required for a dedicated SaaS billing API client (integrationProfile=saas_billing, realmarketing_saas, or realstore_saas)."
          },
          "ownerCorrelationId": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{1,128}$",
            "description": "ID of the subscriber in the SaaS system. Not an email address and not a payment method."
          },
          "recurringData": {
            "type": "object",
            "description": "Recurring billing with a standard card. By default, customer approval charges once and saves the card token. initialCharge=on_scheduled_date saves the card token without an immediate charge, income record, or financial document. The instruction starts only after GetLpResult confirms approval and a valid token. This requires the terminal's token module, is unavailable for Apple Pay or Google Pay, and is unsupported by SaaS v1. After approval, read the payment and recurring status. Link creation alone does not prove token storage or subscription activation. Saving the card does not emit a financial payment.completed webhook.",
            "properties": {
              "initialCharge": {
                "type": "string",
                "enum": [
                  "on_approval",
                  "on_scheduled_date"
                ],
                "default": "on_approval",
                "description": "First billing date. on_scheduled_date saves the card token now and starts charging on startDate. X-Idempotency-Key is required for every retry. Available through internal POST /api/create-payment with Bearer authentication and external POST /external/create-payment with X-API-Key. The external route requires a live API key and an API client with zero commission. A test key returns DEFERRED_REGISTRATION_TEST_MODE_NOT_SUPPORTED without a provider call; nonzero commission returns DEFERRED_REGISTRATION_COMMISSION_NOT_SUPPORTED. Charges run on the daily Israel-time schedule; an exact execution time cannot be selected."
              },
              "isAutoRecurringPayment": {
                "type": "boolean"
              },
              "frequency": {
                "type": "string",
                "enum": [
                  "daily",
                  "weekly",
                  "monthly",
                  "yearly"
                ]
              },
              "interval": {
                "type": "integer",
                "minimum": 1,
                "maximum": 365,
                "default": 1
              },
              "totalBills": {
                "type": "integer",
                "minimum": 0,
                "maximum": 1200,
                "default": 0,
                "description": "Maximum number of charges, including any initial approval charge. 0 or omission means no count limit; an endDate cutoff still applies. Card registration is not a charge."
              },
              "startDate": {
                "type": "string",
                "format": "date",
                "description": "YYYY-MM-DD, tomorrow or later in Israel time. With on_approval, this is the next charge after the immediate charge; with on_scheduled_date, it is the first charge. If approval arrives late, the date moves to a future cycle without a retroactive charge. totalBills counts charges, not the card save operation."
              },
              "endDate": {
                "type": "string",
                "format": "date",
                "nullable": true,
                "description": "Optional inclusive last Israel calendar day, YYYY-MM-DD. No new provider call begins after this day or after the totalBills charge count is reached; the first limit reached ends new charges. Omitting it leaves no date cutoff. Outcomes already sent remain reconcilable after the cutoff. Preserve this field with the same idempotency key across retries."
              }
            }
          }
        }
      },
      "CreatePaymentResponse": {
        "type": "object",
        "properties": {
          "shortUrl": {
            "type": "string",
            "nullable": true
          },
          "recurringAgreement": {
            "type": "object",
            "nullable": true,
            "description": "The terms of the settlement as calculated by the server. Creating a link is not customer confirmation or proof of subscription activation."
          },
          "operationState": {
            "type": "string",
            "description": "The status of the link creation, for example link_created; Not billing status or subscription activation."
          },
          "idempotencyProtected": {
            "type": "boolean"
          },
          "success": {
            "type": "boolean"
          },
          "paymentUrl": {
            "type": "string",
            "nullable": true,
            "description": "Wrapped RealPayment link to send to customer. In the standing order, the link includes recurring=1 to show the customer a clear marking."
          },
          "directUrl": {
            "type": "string",
            "nullable": true,
            "description": "Direct CardCom link for technical use only. Do not send it to the customer instead of paymentUrl."
          },
          "returnValue": {
            "type": "string"
          },
          "paymentId": {
            "type": "string"
          },
          "lowProfileId": {
            "type": "string",
            "nullable": true
          },
          "isRecurringPayment": {
            "type": "boolean",
            "description": "true when the request included recurringData. The final recurring status is determined after customer approval and a verified provider result."
          },
          "recurringPaymentId": {
            "type": "string",
            "nullable": true,
            "description": "will appear immediately only if the provider returned an instruction ID already in the creation of the link; Otherwise check after the webhook through the API points of the standing instructions."
          },
          "recurringId": {
            "type": "string",
            "nullable": true,
            "description": "CardCom direct debit ID, if received."
          },
          "recurring": {
            "type": "object",
            "nullable": true
          },
          "amounts": {
            "type": "object"
          },
          "commission": {
            "type": "object"
          },
          "contractVersion": {
            "type": "string",
            "nullable": true
          },
          "ownerCorrelationId": {
            "type": "string",
            "nullable": true
          },
          "idempotentReplay": {
            "type": "boolean"
          },
          "testOnly": {
            "type": "boolean",
            "description": "true when client policy is test_only; No CardCom read was performed."
          },
          "providerCallPerformed": {
            "type": "boolean"
          },
          "returnUrl": {
            "type": "string",
            "nullable": true,
            "description": "Only in test_only: a server-generated return URL for checking the billing screen without a provider charge."
          }
        }
      },
      "CreateCustomerRequest": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "address": {
            "type": "string"
          },
          "company": {
            "type": "string"
          },
          "taxId": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          }
        },
        "description": "name plus at least one contact method is required. Email-only customers are supported.",
        "anyOf": [
          {
            "required": [
              "phone"
            ]
          },
          {
            "required": [
              "email"
            ]
          }
        ]
      },
      "SalesProcessActivateRequest": {
        "type": "object",
        "required": [
          "customerName",
          "customerPhone",
          "price"
        ],
        "properties": {
          "idempotencyKey": {
            "type": "string",
            "pattern": "^[a-zA-Z0-9_-]{16,120}$",
            "description": "Optional stable key for retrying the same activation without creating a second sales process. Reuse the same key and inputs. The Idempotency-Key header takes precedence."
          },
          "customerName": {
            "type": "string"
          },
          "customerPhone": {
            "type": "string"
          },
          "price": {
            "type": "number",
            "minimum": 0,
            "exclusiveMinimum": true,
            "description": "Positive and final price. The system also accepts a full numeric string; Partial values ​​like 110abc are not accepted."
          },
          "productName": {
            "type": "string"
          },
          "customerEmail": {
            "type": "string"
          },
          "templateId": {
            "type": "string"
          },
          "metadata": {
            "type": "object"
          }
        }
      },
      "Product": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "price": {
            "type": "number"
          },
          "type": {
            "type": "string",
            "enum": [
              "product",
              "service"
            ]
          },
          "sku": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "UpsertProductRequest": {
        "type": "object",
        "required": [
          "name",
          "price"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "price": {
            "type": "number"
          },
          "type": {
            "type": "string",
            "enum": [
              "product",
              "service"
            ],
            "default": "service"
          },
          "sku": {
            "type": "string"
          },
          "description": {
            "type": "string"
          }
        }
      },
      "RecurringChargeContext": {
        "type": "object",
        "description": "The identity of the next charge as presented to the approver. keep the values ​​until the final result; They are not replaced in the next cycle during a retry.",
        "properties": {
          "billNumber": {
            "type": "integer",
            "minimum": 1
          },
          "cardCredentialVersion": {
            "type": "integer",
            "minimum": 1,
            "nullable": true
          }
        }
      },
      "RecurringChargeRequest": {
        "type": "object",
        "required": [
          "expectedBillNumber",
          "expectedCardCredentialVersion"
        ],
        "additionalProperties": false,
        "properties": {
          "expectedBillNumber": {
            "type": "integer",
            "minimum": 1,
            "description": "chargeContext.billNumber from the instruction the user approved"
          },
          "expectedCardCredentialVersion": {
            "type": "integer",
            "minimum": 1,
            "description": "chargeContext.cardCredentialVersion from the same directive"
          },
          "attemptId": {
            "type": "string",
            "description": "customer experience ID; The persistent protection must also be sent in the X-Idempotency-Key header"
          }
        }
      },
      "ManualRecurringCreateRequest": {
        "type": "object",
        "required": [
          "customerName",
          "customerPhone",
          "amount",
          "description",
          "frequency",
          "startDate"
        ],
        "properties": {
          "customerName": {
            "type": "string",
            "description": "customer name"
          },
          "customerPhone": {
            "type": "string",
            "description": "Israeli phone; For example 0534735616 or +972 53-473-5616"
          },
          "customerEmail": {
            "type": "string",
            "format": "email"
          },
          "amount": {
            "type": "number",
            "minimum": 0,
            "exclusiveMinimum": true,
            "description": "amount to be registered in each cycle; is not collected by this API"
          },
          "currency": {
            "type": "string",
            "default": "ILS"
          },
          "description": {
            "type": "string"
          },
          "frequency": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "yearly"
            ]
          },
          "interval": {
            "type": "integer",
            "minimum": 1,
            "maximum": 365,
            "default": 1
          },
          "totalBills": {
            "type": "integer",
            "minimum": 0,
            "maximum": 1200,
            "default": 0,
            "description": "0 or omitting the field means unlimited number of cycles"
          },
          "startDate": {
            "type": "string",
            "format": "date",
            "description": "The date of the first period in the format YYYY-MM-DD"
          }
        }
      },
      "ManualRecurringRecordRequest": {
        "type": "object",
        "required": [
          "expectedBillNumber"
        ],
        "properties": {
          "expectedBillNumber": {
            "type": "integer",
            "minimum": 1,
            "description": "the number of the next cycle as read from the instruction; Prevents double registration in the next cycle"
          },
          "attemptId": {
            "type": "string",
            "description": "In the internal API only; In the external API it is mandatory to send X-Idempotency-Key in the header"
          }
        }
      },
      "RecurringPayment": {
        "type": "object",
        "properties": {
          "recurringAgreement": {
            "type": "object",
            "description": "Subscription terms include initialCharge. In a deferred registration, check active, billsCharged=0 and a future billing date; The initial link alone is not activation confirmation."
          },
          "canReconcile": {
            "type": "boolean"
          },
          "reconciliationPaymentId": {
            "type": "string",
            "nullable": true
          },
          "chargeContext": {
            "$ref": "#/components/schemas/RecurringChargeContext"
          },
          "chargeFailed": {
            "type": "boolean"
          },
          "requiresPaymentReview": {
            "type": "boolean",
            "description": "There is a non-final debit result; Do not make a new charge or change card to bypass it"
          },
          "recoveryAction": {
            "type": "string",
            "nullable": true,
            "enum": [
              "refresh_card",
              "review_payment",
              null
            ]
          },
          "id": {
            "type": "string"
          },
          "customerName": {
            "type": "string",
            "nullable": true
          },
          "customerPhone": {
            "type": "string",
            "nullable": true
          },
          "customerEmail": {
            "type": "string",
            "nullable": true
          },
          "amount": {
            "type": "number"
          },
          "currency": {
            "type": "string",
            "default": "ILS"
          },
          "description": {
            "type": "string"
          },
          "frequency": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "yearly"
            ]
          },
          "interval": {
            "type": "number"
          },
          "totalBills": {
            "type": "number"
          },
          "billsCharged": {
            "type": "number"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "paused",
              "cancelled",
              "completed",
              "failed",
              "disabled"
            ]
          },
          "isActive": {
            "type": "boolean"
          },
          "billingMode": {
            "type": "string"
          },
          "isManual": {
            "type": "boolean",
            "description": "true on a manual tracking command; Its history is not a CardCom clearing authorization"
          },
          "contractVersion": {
            "type": "string",
            "nullable": true
          },
          "ownerCorrelationId": {
            "type": "string",
            "nullable": true
          },
          "currentPeriodStart": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "currentPeriodEnd": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "cancelAtPeriodEnd": {
            "type": "boolean"
          },
          "cancellationEffectiveAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "providerCancellationState": {
            "type": "string",
            "nullable": true
          },
          "futureChargesDisabled": {
            "type": "boolean",
            "description": "true only when the billing authority is a token scheduler and future cancellation is locked or already applied. Required before deleting an account."
          },
          "saasRecoveryRequiredBillNumber": {
            "type": "integer",
            "nullable": true
          },
          "saasRecoveryAttemptUsed": {
            "type": "boolean"
          },
          "capabilities": {
            "$ref": "#/components/schemas/RecurringCapabilities"
          },
          "nextBillDate": {
            "type": "string",
            "description": "ISO date/stamp of next charge; When saving a card without immediate debit, this is the first charge. Daily run at 09:00 Israel time, no commitment to an exact execution time.",
            "nullable": true
          },
          "lastChargeDate": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "initialPaymentId": {
            "type": "string",
            "nullable": true
          },
          "source": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "RecurringCapabilities": {
        "type": "object",
        "description": "Safe abilities to perform right now. The card token and its validity are not exposed in the API.",
        "properties": {
          "managedBy": {
            "type": "string",
            "enum": [
              "realpayment",
              "cardcom"
            ]
          },
          "automaticBilling": {
            "type": "boolean",
            "description": "Is the instruction active and available for automatic billing, without future cancellation, known failure or need for card verification/updation."
          },
          "canChargeNow": {
            "type": "boolean",
            "description": "true only when the directive is active and backed by a valid token, validator and vendor connection."
          },
          "canRefreshCard": {
            "type": "boolean",
            "description": "Is it currently possible to create a secure link to save a card again?"
          },
          "needsCardRefresh": {
            "type": "boolean"
          },
          "recoveryRequired": {
            "type": "boolean"
          },
          "recoveryAttemptUsed": {
            "type": "boolean"
          },
          "recoveryAction": {
            "type": "string",
            "nullable": true,
            "enum": [
              "refresh_card",
              "review_payment",
              null
            ]
          },
          "requiresPaymentReview": {
            "type": "boolean"
          },
          "chargeFailed": {
            "type": "boolean"
          },
          "expiredCard": {
            "type": "boolean"
          },
          "futureChargesDisabled": {
            "type": "boolean"
          },
          "allowedStatusUpdates": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "active",
                "paused",
                "cancelled",
                "disabled"
              ]
            }
          }
        }
      },
      "RecurringChargeResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "paymentId": {
            "type": "string"
          },
          "transactionId": {
            "type": "string",
            "nullable": true
          },
          "billNumber": {
            "type": "integer"
          },
          "isCompleted": {
            "type": "boolean"
          },
          "idempotentReplay": {
            "type": "boolean",
            "description": "true when the same charge operation was already completed and was not sent to the provider again."
          },
          "requiresReview": {
            "type": "boolean"
          },
          "message": {
            "type": "string"
          }
        }
      },
      "RecurringCardRefreshResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "paymentId": {
            "type": "string"
          },
          "lowProfileId": {
            "type": "string"
          },
          "paymentUrl": {
            "type": "string",
            "description": "Wrapped RealPayment link to be sent to the customer to re-save the card."
          },
          "shortUrl": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "idempotentReplay": {
            "type": "boolean",
            "description": "True when returning the already-created link from the existing reserved attempt."
          }
        }
      },
      "UpdateRecurringStatusRequest": {
        "type": "object",
        "required": [
          "status"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "active",
              "paused",
              "cancelled",
              "disabled"
            ]
          },
          "cancelReason": {
            "type": "string"
          }
        }
      },
      "SaasRecurringActionRequest": {
        "type": "object",
        "required": [
          "ownerCorrelationId"
        ],
        "properties": {
          "ownerCorrelationId": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{1,128}$"
          },
          "contractVersion": {
            "type": "string",
            "enum": [
              "saas-v1"
            ],
            "default": "saas-v1"
          }
        }
      },
      "SaasRecurringRecoveryRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/SaasRecurringActionRequest"
          },
          {
            "type": "object",
            "required": [
              "failedPaymentId"
            ],
            "properties": {
              "failedPaymentId": {
                "type": "string",
                "description": "ID of the failed auto-renew attempt. Must belong to the same owner, bill and appointment."
              }
            }
          }
        ]
      },
      "SaasRecurringActionResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "idempotentReplay": {
            "type": "boolean"
          },
          "providerVerification": {
            "type": "string",
            "enum": [
              "token_scheduler_stop",
              "token_scheduler_resume",
              "token_managed_local_authority",
              "cardcom_low_profile_checked",
              "provider_webhook_authority"
            ]
          },
          "recurringPayment": {
            "$ref": "#/components/schemas/RecurringPayment"
          }
        }
      },
      "SaasDocumentReference": {
        "type": "object",
        "description": "No raw vendor URL. Attach retrievalPath to the base that ends in /api/external and send X-API-Key.",
        "properties": {
          "id": {
            "type": "string",
            "nullable": true
          },
          "type": {
            "type": "string",
            "nullable": true
          },
          "available": {
            "type": "boolean"
          },
          "retrievalPath": {
            "type": "string",
            "nullable": true,
            "example": "/payments/saas_x/document?ownerCorrelationId=owner_x"
          }
        }
      },
      "SaasPaymentMethodSummary": {
        "type": "object",
        "description": "Filtered summary only; Never includes token, full card number or CVV.",
        "properties": {
          "brand": {
            "type": "string",
            "nullable": true
          },
          "last4": {
            "type": "string",
            "nullable": true,
            "pattern": "^[0-9]{4}$"
          },
          "expiryMonth": {
            "type": "integer",
            "nullable": true,
            "minimum": 1,
            "maximum": 12
          },
          "expiryYear": {
            "type": "integer",
            "nullable": true
          }
        }
      },
      "SaasWebhookEvent": {
        "type": "object",
        "description": "Sent with X-RealPayment-Event-Id, X-RealPayment-Timestamp, X-RealPayment-Key-Id and X-RealPayment-Signature. The signature is HMAC-SHA256 on timestamp + '.' + rawBody.",
        "required": [
          "contractVersion",
          "eventId",
          "eventType",
          "ownerCorrelationId"
        ],
        "properties": {
          "contractVersion": {
            "type": "string",
            "enum": [
              "saas-v1"
            ]
          },
          "eventId": {
            "type": "string"
          },
          "eventType": {
            "type": "string",
            "enum": [
              "subscription.activated",
              "charge.succeeded",
              "charge.failed",
              "subscription.cancelled",
              "payment_method.updated",
              "document.issued"
            ]
          },
          "ownerCorrelationId": {
            "type": "string"
          },
          "subscriptionId": {
            "type": "string",
            "nullable": true
          },
          "paymentId": {
            "type": "string",
            "nullable": true
          },
          "recurringPaymentId": {
            "type": "string",
            "nullable": true
          },
          "amount": {
            "type": "number",
            "nullable": true
          },
          "currency": {
            "type": "string"
          },
          "periodStart": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "periodEnd": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "periodKey": {
            "type": "string",
            "nullable": true
          },
          "document": {
            "$ref": "#/components/schemas/SaasDocumentReference"
          },
          "paymentMethod": {
            "$ref": "#/components/schemas/SaasPaymentMethodSummary"
          },
          "metadata": {
            "type": "object"
          }
        }
      },
      "Payment": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "rawStatus": {
            "type": "string",
            "nullable": true
          },
          "amount": {
            "type": "number"
          },
          "baseAmount": {
            "type": "number",
            "nullable": true
          },
          "commission": {
            "type": "number",
            "nullable": true
          },
          "currency": {
            "type": "string",
            "default": "ILS"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "customerName": {
            "type": "string",
            "nullable": true
          },
          "customerPhone": {
            "type": "string",
            "nullable": true
          },
          "customerEmail": {
            "type": "string",
            "nullable": true
          },
          "returnValue": {
            "type": "string",
            "nullable": true
          },
          "paymentUrl": {
            "type": "string",
            "nullable": true
          },
          "shortUrl": {
            "type": "string",
            "nullable": true
          },
          "transactionId": {
            "type": "string",
            "nullable": true
          },
          "recurringPaymentId": {
            "type": "string",
            "nullable": true
          },
          "isRecurring": {
            "type": "boolean"
          },
          "source": {
            "type": "string",
            "nullable": true
          },
          "apiClientId": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "completedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "refundedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "refundAmount": {
            "type": "number",
            "nullable": true
          }
        }
      },
      "BusinessProfile": {
        "type": "object",
        "properties": {
          "businessName": {
            "type": "string"
          },
          "taxId": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "address": {
            "type": "string"
          },
          "contactName": {
            "type": "string"
          },
          "logoUrl": {
            "type": "string",
            "nullable": true,
            "description": "Current business logo. New updates accept an HTTPS URL or null to remove it. This value is global to the business."
          },
          "tagline": {
            "type": "string"
          },
          "brandColor": {
            "type": "string"
          },
          "secondaryColor": {
            "type": "string"
          },
          "integrations": {
            "type": "object",
            "properties": {
              "cardcomConfigured": {
                "type": "boolean"
              },
              "whatsappConfigured": {
                "type": "boolean"
              }
            }
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "UpdateBusinessProfileRequest": {
        "type": "object",
        "properties": {
          "businessName": {
            "type": "string"
          },
          "taxId": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "address": {
            "type": "string"
          },
          "contactName": {
            "type": "string"
          },
          "logoUrl": {
            "type": "string",
            "maxLength": 2048,
            "nullable": true,
            "anyOf": [
              {
                "format": "uri",
                "pattern": "^[Hh][Tt][Tt][Pp][Ss]://[^/@\\s]+(?:[/?#]|$)"
              },
              {
                "enum": [
                  ""
                ]
              }
            ],
            "description": "HTTPS logo URL of at most 2048 characters without embedded credentials, or null to remove it. An empty string is also normalized to null for compatibility. Applies to RealPayment's payment page and business branding; the CardCom iframe is unchanged."
          },
          "tagline": {
            "type": "string"
          },
          "brandColor": {
            "type": "string",
            "pattern": "^#[0-9A-Fa-f]{6}$",
            "example": "#1e40af"
          },
          "secondaryColor": {
            "type": "string",
            "pattern": "^#[0-9A-Fa-f]{6}$",
            "example": "#3EC9D6"
          }
        }
      },
      "CreateInvoiceReceiptRequest": {
        "type": "object",
        "required": [
          "customerName",
          "amount"
        ],
        "properties": {
          "customerName": {
            "type": "string",
            "minLength": 2
          },
          "customerPhone": {
            "type": "string"
          },
          "customerEmail": {
            "type": "string"
          },
          "customerTaxId": {
            "type": "string",
            "description": "Customer H.P./E.M., 9 digits. Mandatory when a tax invoice/receipt requires an allocation number according to Israeli invoices. The server will block a tax document that requires assignment without both fields.",
            "pattern": "^[0-9]{9}$"
          },
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "description": {
                  "type": "string",
                  "minLength": 1
                },
                "quantity": {
                  "description": "Send a JSON number. Positive quantity. Numbers or complete decimal strings are accepted; booleans, nonfinite values and strings with extra characters are rejected.",
                  "default": 1,
                  "type": "number",
                  "minimum": 0,
                  "exclusiveMinimum": true
                },
                "price": {
                  "description": "Send a JSON number. Non-negative unit price. Zero is valid. Numbers or complete decimal strings are accepted; booleans, nonfinite values and strings with extra characters are rejected.",
                  "type": "number",
                  "minimum": 0
                },
                "unitPrice": {
                  "description": "Send a JSON number. Existing price alias when price is omitted; complete finite decimal input only.",
                  "type": "number",
                  "minimum": 0
                }
              },
              "description": "Existing item defaults are retained: omitted quantity is 1, omitted price uses unitPrice or the request amount, and omitted description uses the request description or a service label. Explicit invalid numeric values are rejected."
            }
          },
          "notes": {
            "type": "string"
          },
          "paymentMethod": {
            "type": "string",
            "description": "Payment method label. The documented Hebrew default is the API's existing card-payment value.",
            "default": "אשראי"
          },
          "allocationNumber": {
            "type": "string",
            "description": "Allocation number from the Tax Authority, 9 digits. Mandatory when the document is above the legal threshold before VAT",
            "pattern": "^[0-9]{9}$"
          },
          "requestId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 180,
            "pattern": "^[A-Za-z0-9_.:-]+$",
            "description": "Stable document issuance identity. Use the same value and body for retries. If any Idempotency-Key or X-Idempotency-Key header is also sent, every supplied identity must match."
          },
          "paymentId": {
            "type": "string",
            "description": "Existing owned payment to link to this document. The amount, currency and customer must match the immutable payment."
          },
          "parentDocumentId": {
            "type": "string",
            "description": "Existing owned source document when the selected issuance flow supports it; this does not authorize a correction or monetary refund."
          },
          "currency": {
            "type": "string",
            "enum": [
              "ILS",
              "USD"
            ],
            "default": "ILS"
          },
          "customerId": {
            "type": "string",
            "description": "Existing customer owned by the API key account; supplied contact details must resolve consistently."
          },
          "amount": {
            "description": "Send a JSON number. Positive amount. Numbers or complete decimal strings are accepted; booleans, nonfinite values and strings with extra characters are rejected.",
            "type": "number",
            "minimum": 0,
            "exclusiveMinimum": true
          },
          "description": {
            "type": "string"
          }
        },
        "description": "amount is the required positive document total. items are optional; when omitted, the server uses description and amount for a single service item. Supplied numeric values must be complete and finite. This is document issuance, not payment collection."
      },
      "DocumentProviderConnectRequest": {
        "type": "object",
        "required": [
          "expectedVersion"
        ],
        "properties": {
          "expectedVersion": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Current settings configVersion."
          }
        },
        "example": {
          "expectedVersion": 3
        }
      },
      "BillingEnrollmentCreate": {
        "type": "object",
        "required": [
          "externalAccountId",
          "agreementId",
          "agreementVersion",
          "payerReference",
          "consentReference",
          "amount",
          "currency",
          "firstChargeMode",
          "firstChargeDate",
          "nextChargeDate",
          "billingDay",
          "customer"
        ],
        "properties": {
          "externalAccountId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          },
          "agreementId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          },
          "agreementVersion": {
            "type": "integer",
            "minimum": 1
          },
          "amount": {
            "type": "number",
            "minimum": 0.01,
            "maximum": 10000000,
            "multipleOf": 0.01,
            "description": "Full monthly amount in ILS, including any applicable tax. No proration is computed."
          },
          "currency": {
            "type": "string",
            "enum": [
              "ILS"
            ]
          },
          "firstChargeMode": {
            "type": "string",
            "enum": [
              "immediate",
              "scheduled"
            ]
          },
          "firstChargeDate": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "nextChargeDate": {
            "type": "string",
            "format": "date"
          },
          "billingDay": {
            "type": "integer",
            "minimum": 1,
            "maximum": 31,
            "description": "Persistent monthly anchor. nextChargeDate day must equal min(billingDay,lastDayOfMonth). 31 returns to 31 after February."
          },
          "payerReference": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          },
          "consentReference": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          },
          "customer": {
            "type": "object",
            "required": [
              "name",
              "email"
            ],
            "properties": {
              "name": {
                "type": "string",
                "minLength": 1,
                "maxLength": 160
              },
              "email": {
                "type": "string",
                "format": "email",
                "maxLength": 254
              },
              "phone": {
                "type": "string",
                "maxLength": 32,
                "nullable": true
              }
            }
          }
        },
        "description": "Requires an active ordinary API client with persisted allowBillingEnrollments=true and commission=0 (missing commission defaults to zero). Test keys are not supported. Immediate: firstChargeDate=null and nextChargeDate is a chosen future Israel calendar date. Scheduled: firstChargeDate=nextChargeDate, both future. Original first consent must be confirmed before that calendar date; late approval cannot create a mandate or charge and returns BILLING_AGREEMENT_DATE_EXPIRED. Both modes use CreateTokenOnly; only the server may dispatch money after verified token and current consent/fence. Only one non-stopped enrollment per API client/externalAccountId."
      },
      "BillingEnrollmentHistory": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "paymentId": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string"
          },
          "amount": {
            "type": "number"
          },
          "currency": {
            "type": "string",
            "enum": [
              "ILS"
            ]
          },
          "chargeDate": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "transactionId": {
            "type": "string",
            "nullable": true
          },
          "failureCode": {
            "type": "string",
            "nullable": true
          },
          "documentUrl": {
            "type": "string",
            "format": "uri",
            "nullable": true
          }
        },
        "description": "Financial attempts only. Registration is not income. documentUrl is an existing official provider document URL, never synthesized; null means no confirmed document is available. Document issuance/delivery remain governed by the merchant issuer and automation configuration, not this GET."
      },
      "BillingEnrollment": {
        "type": "object",
        "required": [
          "id",
          "externalAccountId",
          "agreementId",
          "agreementVersion",
          "state",
          "revision",
          "updatedAt",
          "chargeInFlight",
          "canRetry",
          "history"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^be_[a-f0-9]{40}$"
          },
          "externalAccountId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          },
          "agreementId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          },
          "agreementVersion": {
            "type": "integer",
            "minimum": 1
          },
          "amount": {
            "type": "number",
            "minimum": 0.01,
            "maximum": 10000000,
            "multipleOf": 0.01,
            "description": "Full monthly amount in ILS, including any applicable tax. No proration is computed."
          },
          "currency": {
            "type": "string",
            "enum": [
              "ILS"
            ]
          },
          "firstChargeMode": {
            "type": "string",
            "enum": [
              "immediate",
              "scheduled"
            ]
          },
          "firstChargeDate": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "nextChargeDate": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "billingDay": {
            "type": "integer",
            "minimum": 1,
            "maximum": 31,
            "description": "Persistent monthly anchor. nextChargeDate day must equal min(billingDay,lastDayOfMonth). 31 returns to 31 after February."
          },
          "state": {
            "type": "string",
            "enum": [
              "pending_registration",
              "pending_initial_charge",
              "active",
              "payment_failed",
              "provider_outcome_unknown",
              "pending_stop",
              "cancelled"
            ]
          },
          "revision": {
            "type": "string",
            "pattern": "^[0-9]{12}\\.[0-9]{9}$",
            "description": "Monotonic fixed-width Firestore commit timestamp covering every snapshot in the projection. Compare lexicographically; ignore older/equal responses."
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "failureCode": {
            "type": "string",
            "nullable": true
          },
          "paymentUrl": {
            "type": "string",
            "format": "uri",
            "nullable": true
          },
          "registrationPaymentId": {
            "type": "string",
            "nullable": true
          },
          "initialPaymentId": {
            "type": "string",
            "nullable": true
          },
          "recurringPaymentId": {
            "type": "string",
            "nullable": true
          },
          "registrationState": {
            "type": "string",
            "enum": [
              "pending",
              "confirmed",
              "failed",
              "cancelled"
            ]
          },
          "paymentState": {
            "type": "string"
          },
          "mandateState": {
            "type": "string"
          },
          "chargeInFlight": {
            "type": "boolean"
          },
          "canRetry": {
            "type": "boolean"
          },
          "historyPartial": {
            "type": "boolean"
          },
          "history": {
            "type": "array",
            "maxItems": 500,
            "items": {
              "$ref": "#/components/schemas/BillingEnrollmentHistory"
            }
          }
        },
        "description": "Authoritative client-owned projection. A cancelled tombstone created before enrollment may omit amount/firstChargeMode/billingDay. card/token/provider credentials are never exposed. Unknown dispatched money remains unknown or pending_stop; the client must not mark free or replace until cancelled. active means the mandate is ready, not proof that a particular payment succeeded. History is capped at500; historyPartial declares truncation."
      },
      "BillingEnrollmentResponse": {
        "type": "object",
        "required": [
          "success",
          "enrollment"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "enrollment": {
            "$ref": "#/components/schemas/BillingEnrollment"
          },
          "idempotentReplay": {
            "type": "boolean"
          }
        }
      },
      "BillingEnrollmentError": {
        "type": "object",
        "required": [
          "success",
          "errorCode"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "errorCode": {
            "type": "string"
          },
          "enrollmentId": {
            "type": "string"
          }
        }
      },
      "BillingCapabilities": {
        "type": "object",
        "required": [
          "success",
          "contractVersion",
          "clientReference",
          "enabled",
          "ready",
          "providerAccepted",
          "blockers"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "contractVersion": {
            "type": "string",
            "enum": [
              "billing-enrollments-v1"
            ]
          },
          "clientReference": {
            "type": "string",
            "pattern": "^[a-f0-9]{32}$",
            "description": "Stable opaque API client identity. Changing keys must preserve this identity while any enrollment may be active."
          },
          "enabled": {
            "type": "boolean"
          },
          "ready": {
            "type": "boolean"
          },
          "providerAccepted": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "blockers": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "description": "Configuration readiness only; no CardCom call, registration, charge, or provider acceptance proof."
      },
      "DocumentWorkspaceIssuer": {
        "type": "object",
        "properties": {
          "provider": {
            "type": "string",
            "enum": [
              "internal",
              "cardcom"
            ]
          },
          "source": {
            "type": "string",
            "enum": [
              "new",
              "payment"
            ]
          },
          "ready": {
            "type": "boolean"
          },
          "issuanceTypes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "correctionTypes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "currencies": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "paymentMethods": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "provider",
          "source",
          "ready",
          "issuanceTypes",
          "correctionTypes",
          "currencies",
          "paymentMethods"
        ]
      },
      "DocumentWorkspacePayment": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 160
          },
          "status": {
            "type": "string",
            "nullable": true
          },
          "amount": {
            "type": "number"
          },
          "currency": {
            "type": "string",
            "nullable": true
          },
          "customerId": {
            "type": "string",
            "nullable": true
          },
          "customerName": {
            "type": "string"
          },
          "customerPhone": {
            "type": "string",
            "nullable": true
          },
          "customerEmail": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string"
          },
          "paymentMethod": {
            "type": "string",
            "nullable": true
          },
          "paymentDetails": {
            "type": "object",
            "nullable": true
          },
          "paymentDate": {
            "nullable": true,
            "description": "Serialized source payment completion/creation timestamp; use the returned date rather than inventing one."
          },
          "paymentReference": {
            "type": "string",
            "nullable": true
          },
          "checkNumber": {
            "type": "string",
            "nullable": true
          },
          "checkDate": {
            "type": "string",
            "nullable": true
          },
          "bankNumber": {
            "type": "string",
            "nullable": true
          },
          "bankBranch": {
            "type": "string",
            "nullable": true
          },
          "accountNumber": {
            "type": "string",
            "nullable": true
          },
          "canIssue": {
            "type": "boolean"
          },
          "failureCode": {
            "type": "string",
            "nullable": true
          }
        },
        "required": [
          "id",
          "amount",
          "canIssue",
          "failureCode"
        ]
      },
      "DocumentWorkspaceContext": {
        "type": "object",
        "properties": {
          "businessAllowedTypes": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "receipt",
                "quote",
                "invoice",
                "invoice_receipt"
              ]
            }
          },
          "businessType": {
            "type": "string",
            "nullable": true
          },
          "activeProvider": {
            "type": "string",
            "enum": [
              "internal",
              "cardcom"
            ]
          },
          "configVersion": {
            "type": "integer",
            "minimum": 0
          },
          "issuer": {
            "$ref": "#/components/schemas/DocumentWorkspaceIssuer"
          },
          "payment": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DocumentWorkspacePayment"
              }
            ],
            "nullable": true
          },
          "quoteIssuer": {
            "$ref": "#/components/schemas/DocumentWorkspaceQuoteIssuer"
          }
        },
        "required": [
          "businessAllowedTypes",
          "businessType",
          "activeProvider",
          "configVersion",
          "issuer",
          "payment",
          "quoteIssuer"
        ]
      },
      "DocumentWorkspaceFailure": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "error": {
            "type": "string"
          },
          "errorCode": {
            "type": "string"
          },
          "safeToEdit": {
            "type": "boolean"
          },
          "requestId": {
            "type": "string"
          },
          "operationId": {
            "type": "string"
          },
          "documentId": {
            "type": "string"
          },
          "finalizedDocumentId": {
            "type": "string"
          },
          "field": {
            "type": "string",
            "description": "Invalid numeric input location, for example amount, vatRate, items[0].price or totalAmount. A derived-total overflow is reported as totalAmount."
          }
        },
        "required": [
          "success",
          "error"
        ]
      },
      "DocumentWorkspaceItem": {
        "type": "object",
        "properties": {
          "description": {
            "type": "string"
          },
          "quantity": {
            "type": "number"
          },
          "price": {
            "type": "number"
          },
          "total": {
            "type": "number"
          }
        },
        "required": [
          "description",
          "quantity",
          "price"
        ]
      },
      "DocumentWorkspaceDraftRequest": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "receipt",
              "quote",
              "invoice",
              "invoice_receipt"
            ]
          },
          "customerId": {
            "type": "string",
            "nullable": true
          },
          "customerName": {
            "type": "string",
            "maxLength": 200
          },
          "customerPhone": {
            "type": "string",
            "nullable": true
          },
          "customerEmail": {
            "type": "string",
            "nullable": true
          },
          "customerAddress": {
            "type": "string",
            "nullable": true
          },
          "customerTaxId": {
            "type": "string",
            "nullable": true
          },
          "customerCompany": {
            "type": "string",
            "nullable": true
          },
          "currency": {
            "type": "string",
            "description": "Canonical supported currency; issuance is additionally restricted to the selected or original issuer evidence."
          },
          "amount": {
            "type": "number",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DocumentWorkspaceItem"
            }
          },
          "paymentMethod": {
            "type": "string",
            "nullable": true
          },
          "paymentDetails": {
            "type": "object",
            "nullable": true,
            "description": "Legacy compatible details. Send canonical top-level bank/check/reference fields; draft DTO retains only nested checkNumber and note."
          },
          "paymentDate": {
            "type": "string",
            "maxLength": 40,
            "nullable": true
          },
          "paymentReference": {
            "type": "string",
            "maxLength": 80,
            "nullable": true
          },
          "checkNumber": {
            "type": "string",
            "maxLength": 80,
            "nullable": true
          },
          "checkDate": {
            "type": "string",
            "maxLength": 40,
            "nullable": true
          },
          "bankNumber": {
            "type": "string",
            "maxLength": 20,
            "nullable": true
          },
          "bankBranch": {
            "type": "string",
            "maxLength": 20,
            "nullable": true
          },
          "accountNumber": {
            "type": "string",
            "maxLength": 80,
            "nullable": true
          },
          "cashAmount": {
            "type": "number",
            "nullable": true
          },
          "transactionTotal": {
            "type": "number",
            "nullable": true
          },
          "vatRate": {
            "type": "number",
            "nullable": true
          },
          "discount": {
            "type": "number",
            "nullable": true
          },
          "allocationNumber": {
            "type": "string",
            "nullable": true
          },
          "validUntil": {
            "type": "string",
            "nullable": true
          },
          "deliveryTime": {
            "type": "string",
            "nullable": true
          },
          "paymentTerms": {
            "type": "string",
            "nullable": true
          },
          "noPaymentTerms": {
            "type": "boolean"
          },
          "dueDate": {
            "type": "string",
            "nullable": true
          },
          "sourceType": {
            "type": "string",
            "nullable": true
          },
          "sourceId": {
            "type": "string",
            "nullable": true
          },
          "paymentId": {
            "type": "string",
            "nullable": true
          },
          "draftVersion": {
            "type": "integer",
            "minimum": 0,
            "description": "Required matching stored version when updating. A stale version returns 409."
          }
        },
        "required": [
          "type"
        ]
      },
      "DocumentWorkspaceDraft": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "receipt",
              "quote",
              "invoice",
              "invoice_receipt"
            ]
          },
          "customerId": {
            "type": "string",
            "nullable": true
          },
          "customerName": {
            "type": "string",
            "maxLength": 200
          },
          "customerPhone": {
            "type": "string",
            "nullable": true
          },
          "customerEmail": {
            "type": "string",
            "nullable": true
          },
          "customerAddress": {
            "type": "string",
            "nullable": true
          },
          "customerTaxId": {
            "type": "string",
            "nullable": true
          },
          "customerCompany": {
            "type": "string",
            "nullable": true
          },
          "currency": {
            "type": "string",
            "description": "Canonical supported currency; issuance is additionally restricted to the selected or original issuer evidence."
          },
          "amount": {
            "type": "number",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DocumentWorkspaceItem"
            }
          },
          "paymentMethod": {
            "type": "string",
            "nullable": true
          },
          "paymentDetails": {
            "type": "object",
            "nullable": true,
            "description": "Legacy compatible details. Send canonical top-level bank/check/reference fields; draft DTO retains only nested checkNumber and note."
          },
          "paymentDate": {
            "type": "string",
            "maxLength": 40,
            "nullable": true
          },
          "paymentReference": {
            "type": "string",
            "maxLength": 80,
            "nullable": true
          },
          "checkNumber": {
            "type": "string",
            "maxLength": 80,
            "nullable": true
          },
          "checkDate": {
            "type": "string",
            "maxLength": 40,
            "nullable": true
          },
          "bankNumber": {
            "type": "string",
            "maxLength": 20,
            "nullable": true
          },
          "bankBranch": {
            "type": "string",
            "maxLength": 20,
            "nullable": true
          },
          "accountNumber": {
            "type": "string",
            "maxLength": 80,
            "nullable": true
          },
          "cashAmount": {
            "type": "number",
            "nullable": true
          },
          "transactionTotal": {
            "type": "number",
            "nullable": true
          },
          "vatRate": {
            "type": "number",
            "nullable": true
          },
          "discount": {
            "type": "number",
            "nullable": true
          },
          "allocationNumber": {
            "type": "string",
            "nullable": true
          },
          "validUntil": {
            "type": "string",
            "nullable": true
          },
          "deliveryTime": {
            "type": "string",
            "nullable": true
          },
          "paymentTerms": {
            "type": "string",
            "nullable": true
          },
          "noPaymentTerms": {
            "type": "boolean"
          },
          "dueDate": {
            "type": "string",
            "nullable": true
          },
          "sourceType": {
            "type": "string",
            "nullable": true
          },
          "sourceId": {
            "type": "string",
            "nullable": true
          },
          "paymentId": {
            "type": "string",
            "nullable": true
          },
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 160
          },
          "status": {
            "type": "string"
          },
          "lifecycleStatus": {
            "type": "string"
          },
          "draftVersion": {
            "type": "integer",
            "minimum": 1
          },
          "isFinal": {
            "type": "boolean"
          },
          "finalizationDocumentId": {
            "type": "string",
            "nullable": true
          },
          "finalizedDocumentId": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "nullable": true
          },
          "updatedAt": {
            "nullable": true
          }
        },
        "required": [
          "id",
          "type",
          "draftVersion"
        ]
      },
      "DocumentWorkspaceCreateRequest": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "receipt",
              "quote",
              "invoice",
              "invoice_receipt"
            ]
          },
          "customerId": {
            "type": "string",
            "nullable": true
          },
          "customerName": {
            "type": "string",
            "maxLength": 200
          },
          "customerPhone": {
            "type": "string",
            "nullable": true
          },
          "customerEmail": {
            "type": "string",
            "nullable": true
          },
          "customerAddress": {
            "type": "string",
            "nullable": true
          },
          "customerTaxId": {
            "type": "string",
            "nullable": true
          },
          "customerCompany": {
            "type": "string",
            "nullable": true
          },
          "currency": {
            "type": "string",
            "description": "Canonical supported currency; issuance is additionally restricted to the selected or original issuer evidence."
          },
          "amount": {
            "type": "number",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DocumentWorkspaceItem"
            }
          },
          "paymentMethod": {
            "type": "string",
            "nullable": true
          },
          "paymentDetails": {
            "type": "object",
            "nullable": true,
            "description": "Legacy compatible details. Send canonical top-level bank/check/reference fields; draft DTO retains only nested checkNumber and note."
          },
          "paymentDate": {
            "type": "string",
            "maxLength": 40,
            "nullable": true
          },
          "paymentReference": {
            "type": "string",
            "maxLength": 80,
            "nullable": true
          },
          "checkNumber": {
            "type": "string",
            "maxLength": 80,
            "nullable": true
          },
          "checkDate": {
            "type": "string",
            "maxLength": 40,
            "nullable": true
          },
          "bankNumber": {
            "type": "string",
            "maxLength": 20,
            "nullable": true
          },
          "bankBranch": {
            "type": "string",
            "maxLength": 20,
            "nullable": true
          },
          "accountNumber": {
            "type": "string",
            "maxLength": 80,
            "nullable": true
          },
          "cashAmount": {
            "type": "number",
            "nullable": true
          },
          "transactionTotal": {
            "type": "number",
            "nullable": true
          },
          "vatRate": {
            "type": "number",
            "nullable": true
          },
          "discount": {
            "type": "number",
            "nullable": true
          },
          "allocationNumber": {
            "type": "string",
            "nullable": true
          },
          "validUntil": {
            "type": "string",
            "nullable": true
          },
          "deliveryTime": {
            "type": "string",
            "nullable": true
          },
          "paymentTerms": {
            "type": "string",
            "nullable": true
          },
          "noPaymentTerms": {
            "type": "boolean"
          },
          "dueDate": {
            "type": "string",
            "nullable": true
          },
          "sourceType": {
            "type": "string",
            "nullable": true
          },
          "sourceId": {
            "type": "string",
            "nullable": true
          },
          "paymentId": {
            "type": "string",
            "nullable": true
          },
          "requestId": {
            "type": "string",
            "description": "Stable client creation identity. Preserve with the entire original payload for continuation; response requestId can be a distinct diagnostic ID."
          },
          "draftVersion": {
            "type": "integer",
            "minimum": 1
          },
          "sourceDraftId": {
            "type": "string",
            "nullable": true,
            "description": "Owned saved draft ID. Send the current draftVersion and unchanged complete creation payload; the server stores the immutable attempt snapshot."
          }
        },
        "required": [
          "type",
          "customerName"
        ]
      },
      "ExternalWebhookSigningRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "keyId",
          "expectedVersion",
          "consumerReady"
        ],
        "properties": {
          "keyId": {
            "type": "string",
            "minLength": 3,
            "maxLength": 80,
            "pattern": "^[A-Za-z0-9._-]{3,80}$",
            "description": "Installed owner/client-specific key identifier. Never send a secret in this request."
          },
          "expectedVersion": {
            "type": "integer",
            "minimum": 0,
            "description": "Current saved webhookSigning version; zero for an unmigrated ordinary client."
          },
          "consumerReady": {
            "type": "boolean",
            "enum": [
              true
            ],
            "description": "Explicit owner confirmation that the receiver is prepared. This attestation is not a live acceptance receipt."
          }
        }
      },
      "ExternalWebhookSigningMetadata": {
        "type": "object",
        "required": [
          "mode",
          "version",
          "keyId",
          "configured",
          "consumerConfirmedByOwner"
        ],
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "dual_v2"
            ]
          },
          "version": {
            "type": "integer",
            "minimum": 1
          },
          "keyId": {
            "type": "string"
          },
          "configured": {
            "type": "boolean",
            "enum": [
              true
            ],
            "description": "Saved configuration, not proof of receiver acceptance."
          },
          "consumerConfirmedByOwner": {
            "type": "boolean",
            "enum": [
              true
            ]
          }
        }
      },
      "ExternalWebhookSigningResponse": {
        "type": "object",
        "required": [
          "success",
          "webhookSigning"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "webhookSigning": {
            "$ref": "#/components/schemas/ExternalWebhookSigningMetadata"
          }
        }
      },
      "ExternalWebhookManagementError": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "errorCode": {
            "type": "string"
          },
          "error": {
            "type": "string"
          }
        }
      },
      "RecurringCardRefreshFailure": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "paymentId": {
            "type": "string",
            "description": "Original refresh attempt identity when available."
          },
          "error": {
            "type": "string"
          },
          "errorCode": {
            "type": "string"
          },
          "canRetry": {
            "type": "boolean",
            "description": "False for ambiguous creation and changed state. Omission never authorizes another provider request."
          }
        }
      },
      "DocumentWorkspaceQuoteIssuer": {
        "type": "object",
        "required": [
          "provider",
          "ready",
          "basis",
          "currencies",
          "signatureAcknowledgmentEnabled"
        ],
        "properties": {
          "provider": {
            "type": "string",
            "enum": [
              "internal",
              "cardcom"
            ]
          },
          "ready": {
            "type": "boolean",
            "description": "Server-assessed issuance/binding/release policy. For CardCom, separate acknowledgment policy must also be enabled. It is not proof of actual provider issuance or downstream acceptance."
          },
          "basis": {
            "type": "string",
            "enum": [
              "internal",
              "provider_contract"
            ],
            "description": "CardCom Quote/CreateDocument and report type 50 derive from the documented provider contract; accounting/correction evidence is not broadened."
          },
          "currencies": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "ILS",
                "USD"
              ]
            }
          },
          "signatureAcknowledgmentEnabled": {
            "type": "boolean",
            "description": "Explicit current shared server policy for CardCom original plus separate customer approval; the original is never replaced."
          }
        }
      },
      "DocumentSignatureStatusResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "documentId": {
            "type": "string"
          },
          "documentNumber": {
            "type": "string"
          },
          "issuerProvider": {
            "type": "string",
            "enum": [
              "internal",
              "cardcom"
            ]
          },
          "signatureStatus": {
            "type": "string"
          },
          "signatureProcessingState": {
            "type": "string",
            "nullable": true,
            "enum": [
              "preparing",
              "failed",
              "ready",
              null
            ]
          },
          "signaturePdfReadyAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "supportsSignature": {
            "type": "boolean"
          },
          "signatureAcknowledgmentEnabled": {
            "type": "boolean"
          },
          "signatureMode": {
            "type": "string",
            "enum": [
              "local_quote",
              "cardcom_quote_acknowledgment"
            ]
          },
          "signatureArtifactKind": {
            "type": "string",
            "nullable": true,
            "enum": [
              "signature_acknowledgment",
              null
            ]
          },
          "pdfUrl": {
            "type": "string",
            "nullable": true,
            "description": "Current short bearer URL for the original document. CardCom original is unchanged."
          },
          "signatureAcknowledgmentPdfUrl": {
            "type": "string",
            "nullable": true,
            "description": "Separate current short bearer URL for the customer acknowledgment; present only after the current original and ACK PDF proofs pass. Never substitute it for the original."
          },
          "signedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "signerName": {
            "type": "string",
            "nullable": true
          },
          "signatureUrl": {
            "type": "string",
            "nullable": true
          }
        }
      }
    }
  },
  "paths": {
    "/api/customers/{customerId}/obligations/resolve-attempt": {
      "post": {
        "tags": [
          "Internal customer obligations"
        ],
        "summary": "Resolve or explicitly retire one frozen customer-editor attempt",
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "parameters": [
          {
            "name": "customerId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerObligationEditorResolution"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved exact ACK or terminal uncommitted marker; no account reactivation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerObligationEditorResolutionAck"
                }
              }
            }
          },
          "400": {
            "description": "Original operation/body required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "403": {
            "description": "Inactive owner",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "404": {
            "description": "Current owned customer/privacy/merge fence",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "409": {
            "description": "Fingerprint conflict, orphan or older outcome remains held",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "503": {
            "description": "Resolution unknown; retain exact request and key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          }
        }
      }
    },
    "/api/payments/manual/resolve-attempt": {
      "post": {
        "tags": [
          "Internal payments"
        ],
        "summary": "Explicitly resolve or terminally retire one frozen v2 create attempt",
        "description": "Send the exact original frozen v2 body. Explicit owner/key namespace transaction returns its consistent saved ACK, or creates an immutable terminal uncommitted marker. No expiry or reuse of retired keys. No v1/old-generation outcome may be claimed, deleted or retired.",
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManualPaymentAttemptResolution"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Complete existing saved ACK or terminal uncommitted acknowledgement.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentAttemptResolutionAck"
                }
              }
            }
          },
          "400": {
            "description": "Original v2 body required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "403": {
            "description": "Owner inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "409": {
            "description": "Mismatched fingerprint, legacy outcome or broken command; preserve attempt and require review",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "503": {
            "description": "Resolution outcome unknown; retry the exact resolution body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          }
        }
      }
    },
    "/api/customer-obligations/summary": {
      "get": {
        "tags": [
          "Internal customer obligations"
        ],
        "summary": "Read canonical owned receivable including quality",
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Owned summary; may be unknown with null amount.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "summary": {
                      "$ref": "#/components/schemas/CustomerObligationSummary"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Source unavailable; no fabricated zero",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          }
        }
      }
    },
    "/api/customers/{customerId}/obligations": {
      "get": {
        "tags": [
          "Internal customer obligations"
        ],
        "summary": "Read owned typed obligations and current legacy evidence",
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "parameters": [
          {
            "name": "customerId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 1500,
              "description": "Exact Firestore UTF-8 document ID (1500 bytes maximum); no slash, dot/dotdot, reserved __.*__ or malformed Unicode. Never normalize an ID as a phone."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Owned source and quality; historical raw metadata is not a public DTO.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerObligationRead"
                }
              }
            }
          },
          "404": {
            "description": "Owned customer unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "503": {
            "description": "Source unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Internal customer obligations"
        ],
        "summary": "Explicitly declare existing debt without historical rewrite",
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "parameters": [
          {
            "name": "customerId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 1500,
              "description": "Exact Firestore UTF-8 document ID (1500 bytes maximum); no slash, dot/dotdot, reserved __.*__ or malformed Unicode. Never normalize an ID as a phone."
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerObligationDeclaration"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved operation or exact replay. Preserve the same body/key if response is missing.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "id",
                    "idempotentReplay"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "id": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 1500,
                      "description": "Exact Firestore UTF-8 document ID (1500 bytes maximum); no slash, dot/dotdot, reserved __.*__ or malformed Unicode. Never normalize an ID as a phone."
                    },
                    "idempotentReplay": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid declaration/amount/ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "403": {
            "description": "Inactive or foreign owner",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "404": {
            "description": "Owned customer/obligation unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "409": {
            "description": "Source/revision changed, reserved debt, duplicate/collision or legacy reset blocked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "503": {
            "description": "Unknown/unavailable source or save. Keep same request/key; never assume zero or create another attempt.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          }
        }
      }
    },
    "/api/customer-obligations/{obligationId}": {
      "patch": {
        "tags": [
          "Internal customer obligations"
        ],
        "summary": "Adjust one owned obligation with revision/reservation guards",
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "parameters": [
          {
            "name": "obligationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 1500,
              "description": "Exact Firestore UTF-8 document ID (1500 bytes maximum); no slash, dot/dotdot, reserved __.*__ or malformed Unicode. Never normalize an ID as a phone."
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerObligationAdjustment"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved operation or exact replay. Preserve the same body/key if response is missing.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "id",
                    "idempotentReplay"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "id": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 1500,
                      "description": "Exact Firestore UTF-8 document ID (1500 bytes maximum); no slash, dot/dotdot, reserved __.*__ or malformed Unicode. Never normalize an ID as a phone."
                    },
                    "idempotentReplay": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid declaration/amount/ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "403": {
            "description": "Inactive or foreign owner",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "404": {
            "description": "Owned customer/obligation unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "409": {
            "description": "Source/revision changed, reserved debt, duplicate/collision or legacy reset blocked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "503": {
            "description": "Unknown/unavailable source or save. Keep same request/key; never assume zero or create another attempt.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          }
        }
      }
    },
    "/api/customers/update-debts": {
      "post": {
        "tags": [
          "Internal customer obligations"
        ],
        "summary": "Guarded compatibility update of untyped historical scalar only",
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LegacyDebtUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Scalar operation saved or exactly replayed; remains untyped and does not reconcile a currency-bound balance.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "idempotentReplay",
                    "remainsUntyped"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "idempotentReplay": {
                      "type": "boolean"
                    },
                    "remainsUntyped": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid declaration/amount/ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "403": {
            "description": "Inactive or foreign owner",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "404": {
            "description": "Owned customer/obligation unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "409": {
            "description": "Source/revision changed, reserved debt, duplicate/collision or legacy reset blocked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "503": {
            "description": "Unknown/unavailable source or save. Keep same request/key; never assume zero or create another attempt.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          }
        }
      }
    },
    "/api/payments/manual/preview": {
      "post": {
        "tags": [
          "Internal payments"
        ],
        "summary": "Resolve an explicit received time or preview an unpaid manual plan",
        "description": "Pure authenticated calculation, no writes/provider call. Uses one canonical server calculator for exact cents, original calendar-day month clamping and clock changes. Ambiguous received local time returns two explicit offset choices.",
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManualPaymentPreviewRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Canonical receivedAt or planned rows/total/count; no payment has been saved."
          },
          "400": {
            "description": "Invalid data or an ambiguous/nonexistent local time",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          }
        }
      }
    },
    "/api/payments/add": {
      "post": {
        "tags": [
          "Internal payments"
        ],
        "summary": "Record received money or atomically save unpaid manual payments",
        "description": "A v2 received command writes completedAt from explicit actual receipt input. Planned rows are pending with scheduledAt, without a completion anchor or money/customer projection. Group command and all children commit atomically. Equal mode preserves every cent; full mode repeats the amount. A stable owner/key cannot change intent or input. Existing v1 keyed outcomes replay unchanged; fresh legacy ordinary input needs its explicit valid full createdAt receipt instant, while old spread/nonreceived requests require a refresh. No historical date inference, charge or send.",
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManualPaymentCreateV2"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Complete saved command or exact durable replay; never a partial group ACK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentAck"
                }
              }
            }
          },
          "400": {
            "description": "Invalid amount, contact, intent, receipt date/time or schedule",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "403": {
            "description": "Inactive owner",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "409": {
            "description": "Key reuse, command integrity/collision or issuer/accounting restriction",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "500": {
            "description": "Unknown or failed save; retain the exact request/key before retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          }
        }
      }
    },
    "/api/payments/{id}": {
      "patch": {
        "tags": [
          "Internal payments"
        ],
        "summary": "Update an owned payment; record actual receipt on the same manual row",
        "description": "Full actual receipt completes the same manual row. Typed partial receipt settles exactly the cash child and leaves original pending remainder, with exact cent/cost allocation. Server selects none for linked debt projection; immutable FK and accounting locks remain. Cancellation releases collection reservation and does not forgive debt or undo received cash.",
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManualPaymentReceiptPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated row or receipt replay, including current manualRevision.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentUpdateAck"
                }
              }
            }
          },
          "400": {
            "description": "Invalid/unsupported update or missing actual receipt context",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "403": {
            "description": "Owner mismatch or inactive owner",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "404": {
            "description": "Owned payment not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          },
          "409": {
            "description": "Stale manualRevision, retained accounting or conflicting receipt attempt",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualPaymentError"
                }
              }
            }
          }
        }
      }
    },
    "/api/document-provider": {
      "get": {
        "summary": "Read internal document-provider settings",
        "description": "Internal management operation using the signed-in owner's Firebase Bearer token, not X-API-Key or a dedicated SaaS key. Returns the current selection, release gate, connection assessment, CardCom readiness and recorded capabilities without credentials. This reads stored configuration and evidence; it does not provision a provider account or issue a document.",
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ],
        "tags": [
          "Documents"
        ],
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Current settings.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentProviderSettingsResponse"
                }
              }
            }
          },
          "403": {
            "description": "Missing or invalid owner Firebase Bearer token, unmet existing account/session/MFA authorization checks, or a forbidden provider binding. Authentication guards can return error and code; provider failures return errorCode and safeToEdit."
          },
          "409": {
            "description": "DOCUMENT_PROVIDER_CONFIGURATION_INVALID: the stored selection or binding requires review.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountingDocumentError"
                }
              }
            }
          },
          "500": {
            "description": "The settings or operation could not be read or updated. Inspect errorCode; this is not proof of a provider outcome.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountingDocumentError"
                }
              }
            }
          }
        }
      }
    },
    "/api/document-provider/validate": {
      "post": {
        "summary": "Validate an existing CardCom document connection",
        "description": "Internal owner Bearer operation. Requires an existing owner-bound CardCom binding with an explicit environment and configured credentials. Reads the current-day report from CardCom and records a successful read check for the same credentials and environment before returning fresh settings. It does not issue a document or charge a customer. A successful read does not establish full issuance readiness or provision the binding.",
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ],
        "tags": [
          "Documents"
        ],
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Current settings.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentProviderSettingsResponse"
                }
              }
            }
          },
          "403": {
            "description": "Missing or invalid owner Firebase Bearer token, unmet existing account/session/MFA authorization checks, or a forbidden provider binding. Authentication guards can return error and code; provider failures return errorCode and safeToEdit."
          },
          "409": {
            "description": "DOCUMENT_PROVIDER_BINDING_REQUIRED or DOCUMENT_PROVIDER_BINDING_CHANGED: prepare or review the existing binding; the endpoint does not create it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountingDocumentError"
                }
              }
            }
          },
          "500": {
            "description": "The settings or operation could not be read or updated. Inspect errorCode; this is not proof of a provider outcome.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountingDocumentError"
                }
              }
            }
          }
        }
      }
    },
    "/api/document-provider/selection": {
      "put": {
        "summary": "Select the internal document issuer",
        "description": "Internal owner Bearer operation. Send provider and the current configVersion as expectedVersion. CardCom selection requires the server release gate and verified issuance readiness. A changed version or binding, or open document operations, blocks switching with 409. Repeating the already-selected provider with the current version leaves the version unchanged; an actual switch increments it. Selection governs future captured issuance choices and does not replace issuer snapshots on existing payments or documents or create a provider binding.",
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ],
        "tags": [
          "Documents"
        ],
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Current settings.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentProviderSettingsResponse"
                }
              }
            }
          },
          "400": {
            "description": "DOCUMENT_PROVIDER_SELECTION_INVALID: provider must be internal or cardcom, and expectedVersion must be a nonnegative safe integer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountingDocumentError"
                }
              }
            }
          },
          "403": {
            "description": "Missing or invalid owner Firebase Bearer token, unmet existing account/session/MFA authorization checks, or a forbidden provider binding. Authentication guards can return error and code; provider failures return errorCode and safeToEdit."
          },
          "409": {
            "description": "DOCUMENT_PROVIDER_VERSION_CONFLICT for a stale version; DOCUMENT_PROVIDER_NOT_READY for disabled or unready CardCom; DOCUMENT_PROVIDER_SWITCH_BLOCKED while the binding has open operations; DOCUMENT_PROVIDER_BINDING_CHANGED if the verified binding changed; DOCUMENT_PROVIDER_CONFIGURATION_INVALID for invalid stored configuration.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountingDocumentError"
                }
              }
            }
          },
          "500": {
            "description": "The settings or operation could not be read or updated. Inspect errorCode; this is not proof of a provider outcome.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountingDocumentError"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DocumentProviderSelectionRequest"
              }
            }
          }
        }
      }
    },
    "/api/document-provider/operations/{operationId}": {
      "get": {
        "summary": "Read an existing document-provider operation",
        "description": "Internal owner Bearer operation. Use the operationId returned by document issuance, including when the provider outcome is unknown. This retrieves only an operation owned by the signed-in user and returns its stored state; it does not query or reconcile CardCom, issue another document, or authorize a new request identity. External API keys cannot access this management route. Keep the original identity and payload while the existing outcome is being resolved.",
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ],
        "tags": [
          "Documents"
        ],
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Current operation status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentProviderOperationResponse"
                }
              }
            }
          },
          "403": {
            "description": "Missing or invalid owner Firebase Bearer token, unmet existing account/session/MFA authorization checks, or a forbidden provider binding. Authentication guards can return error and code; provider failures return errorCode and safeToEdit."
          },
          "404": {
            "description": "DOCUMENT_PROVIDER_OPERATION_NOT_FOUND: operation absent or not owned by the signed-in user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountingDocumentError"
                }
              }
            }
          },
          "500": {
            "description": "The settings or operation could not be read or updated. Inspect errorCode; this is not proof of a provider outcome.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountingDocumentError"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "operationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1
            },
            "description": "Existing operationId returned by the original issuance."
          }
        ]
      }
    },
    "/api/create-payment": {
      "post": {
        "summary": "Creating a link to confirm a subscription from the internal interface",
        "description": "Firebase ID token of the business owner, not an external API key. To send a monthly subscription select recurringData.isAutoRecurringPayment=true and frequency=monthly. initialCharge=on_scheduled_date Keeps a normal card uncharged now, and activates the instruction only after a confirmed carrier result. startDate is the first collection date; Creating a link alone is not activation. Registering a subscription via Apple Pay/Google Pay is not supported here. X-Idempotency-Key is required every time a link is created; Missing key returns 428 before creating a record or contacting the provider. A retry must preserve the same key and body. The external SaaS fields are not a contract of this internal operation. New requests also require the captured document binding to support the requested currency and payment method. An ILS-only CardCom receipt binding does not permit a new USD payment. Checks do not expand verified capabilities or change historical issuers; completed idempotent replays retain the recorded result.\n\nUI name: קישור לאישור הוראת קבע (Recurring payment approval link). This operation is listed under Recurring Payments as Creating a link to confirm a subscription from the internal interface. The internal UI uses Firebase Bearer authentication; external integrations use POST /external/create-payment with X-API-Key. For monthly billing use recurringData.isAutoRecurringPayment=true, frequency=monthly and interval=1. initialCharge=on_approval charges after verified approval and stores the card for later cycles; startDate is the next automatic charge. initialCharge=on_scheduled_date stores the card after verified approval without charging now; startDate is the first future charge. operationState=link_created confirms link creation only, not customer approval, a successful payment or activation. Read payment and recurring status after approval. Where approvalLinkExpiresAt is returned for a managed local approval link, it describes RealPayment's pending-approval deadline; CardCom controls form validity separately and may expire it sooner. The local deadline does not extend or reopen the provider form.",
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ],
        "tags": [
          "Recurring Payments"
        ],
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "parameters": [
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 160,
              "pattern": "^[A-Za-z0-9_-]+$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePaymentRequest"
              },
              "examples": {
                "monthlyDeferred": {
                  "summary": "An example only — replace startDate with a future date according to Israel time",
                  "value": {
                    "amount": 110,
                    "currency": "ILS",
                    "description": "Monthly subscription",
                    "customerName": "Sample customer",
                    "customerPhone": "0500000000",
                    "numOfPayments": 1,
                    "recurringData": {
                      "isAutoRecurringPayment": true,
                      "initialCharge": "on_scheduled_date",
                      "frequency": "monthly",
                      "interval": 1,
                      "totalBills": 0,
                      "startDate": "2030-01-01"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A link was created or returned in a repeated attempt - this is not proof of registration or billing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreatePaymentResponse"
                }
              }
            }
          },
          "400": {
            "description": "Subscription or date data is incorrect An unsupported currency returns INVALID_CURRENCY for a one-time payment or RECURRING_CURRENCY_UNSUPPORTED for a recurring request; no payment or provider call is created for that invalid currency."
          },
          "403": {
            "description": "Business owner permission is missing or there is no access to the terminal"
          },
          "409": {
            "description": "A different request with the same key, a process attempt or an inconclusive provider result"
          },
          "428": {
            "description": "A trial key is required in the server policy"
          },
          "500": {
            "description": "The link is not complete; Do not change a trial key to override an unknown result"
          }
        }
      }
    },
    "/api/recurring-payments": {
      "get": {
        "summary": "List of instructions and approval requests of the business owner",
        "description": "Limited internal list, no cursor. includes instructions and requests awaiting approval; incomplete=true when one of the data sources has reached the limit. A confirmation request should not be considered an active subscription or a charge.",
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ],
        "tags": [
          "Recurring Payments"
        ],
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 1000,
              "default": 1000
            }
          }
        ],
        "responses": {
          "200": {
            "description": "payments, the state of running and the state of completeness of the list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InternalRecurringListResponse"
                }
              }
            }
          },
          "403": {
            "description": "Unauthorized — Firebase ID token is missing or incorrect"
          },
          "500": {
            "description": "The list was not loaded"
          }
        }
      }
    },
    "/api/recurring-payments/{id}/status": {
      "post": {
        "summary": "Delay, renewal or cancellation of future charges in the interface",
        "description": "Canceled stops new charges in a token route managed by RealPayment, is not a refund. chargeInFlight=true: A charge that has already been sent to the carrier may still be completed. An order that has been terminated or canceled is not reopened. On the cardcom_recurring route, the server rejects a local stop - you must also stop at CardCom. In my opinion disabled is not an allowed status.",
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ],
        "tags": [
          "Recurring Payments"
        ],
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InternalRecurringStatusRequest"
              },
              "example": {
                "status": "cancelled",
                "cancelReason": "Customer request"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "status updated; Check chargeInFlight",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringStatusResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid status, final command or unsupported CardCom-managed stop"
          },
          "403": {
            "description": "Permission or instruction from another business owner is missing"
          },
          "404": {
            "description": "Instruction not found"
          },
          "409": {
            "description": "Billing in process requires inspection"
          },
          "500": {
            "description": "Error updating"
          }
        }
      }
    },
    "/api/recurring-payments/{id}/history": {
      "get": {
        "summary": "History, verified collection and documents in the interface",
        "description": "Last 50 records by chargeDate descending, without cursor. historyPartial=true when the page reached 50. The summary is calculated separately from 1,000 transactions and marks partial; Therefore it is not necessarily the sum of the displayed rows. The source of the confirmation link is documentary only. The summary is not a bank credit confirmation.",
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ],
        "tags": [
          "Recurring Payments"
        ],
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "History and summary",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InternalRecurringHistoryResponse"
                }
              }
            }
          },
          "403": {
            "description": "No permission"
          },
          "404": {
            "description": "Instruction not found"
          },
          "500": {
            "description": "History is not loaded"
          }
        }
      }
    },
    "/api/recurring-payments/{id}/refresh-card-link": {
      "post": {
        "summary": "A link to confirm saving a card again in the interface",
        "description": "Creates a link to save a normal card, no charge and no immediate change to the subscription card. The card is updated only after confirmation and verified provider result. Inconclusive billing result requires reconcile before exchange; Do not switch cards to bypass an unknown charge. An ambiguous LowProfile/Create outcome (including timeout, network failure, HTTP 5xx/408/429 or incomplete success) keeps the original card-refresh attempt and lock. The initial response is 503 with canRetry=false and the original paymentId; a repeated request returns 409 and cannot create a second link. Do not change identities or clear a lock to bypass this state. A callback may still complete the original attempt; without a returned LowProfileId, automated provider lookup is not established. Resolve the existing attempt before another creation. A known definitive provider rejection can release the lock; generic errors do not grant permission to retry. For an ordinary token plan, a verified saved replacement card clears the credential failure and an overdue bill may be charged by the next due scheduler run. This existing collection timing is unchanged. A dedicated SaaS plan instead retains its explicit /recover requirement.",
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ],
        "tags": [
          "Recurring Payments"
        ],
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Card confirmation link",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringCardRefreshResponse"
                }
              }
            }
          },
          "400": {
            "description": "The track or teaching mode does not allow substitution"
          },
          "403": {
            "description": "No permission"
          },
          "404": {
            "description": "Instruction not found"
          },
          "409": {
            "description": "Existing refresh has unknown outcome (RECURRING_CARD_REFRESH_PROVIDER_OUTCOME_UNKNOWN), state changed, charge is unresolved, or another operation blocks creation. Unknown/state-changed responses have canRetry=false and retain the original paymentId.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringCardRefreshFailure"
                }
              }
            }
          },
          "500": {
            "description": "The link was not created"
          },
          "503": {
            "description": "New card-refresh creation outcome is unknown: RECURRING_CARD_REFRESH_PROVIDER_OUTCOME_UNKNOWN for ordinary plans or SAAS_CARD_UPDATE_PROVIDER_OUTCOME_UNKNOWN for SaaS. canRetry=false; no second Create is safe. Other existing policy-unavailable responses retain their own error code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringCardRefreshFailure"
                },
                "examples": {
                  "ordinaryUnknown": {
                    "value": {
                      "success": false,
                      "paymentId": "existing_refresh_attempt",
                      "error": "The original card-refresh creation outcome must be checked.",
                      "errorCode": "RECURRING_CARD_REFRESH_PROVIDER_OUTCOME_UNKNOWN",
                      "canRetry": false
                    }
                  },
                  "saasUnknown": {
                    "value": {
                      "success": false,
                      "paymentId": "existing_saas_refresh_attempt",
                      "error": "The original card-refresh creation outcome must be checked.",
                      "errorCode": "SAAS_CARD_UPDATE_PROVIDER_OUTCOME_UNKNOWN",
                      "canRetry": false
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/recurring-payments/{id}/reconcile": {
      "post": {
        "summary": "Checking an existing result without creating a new charge",
        "description": "Checks for a LowProfile result or an existing charge and updates the documentation as appropriate. Does not create a new link or charge. optional paymentId indicates an existing experience; Without that identifier, the existing experience of the instruction is checked.",
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ],
        "tags": [
          "Recurring Payments"
        ],
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "paymentId": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "an existing result; chargeCreated=false",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringReconcileResponse"
                }
              }
            }
          },
          "403": {
            "description": "No permission"
          },
          "404": {
            "description": "The instruction or request was not found"
          },
          "409": {
            "description": "The inquiry cannot be completed at this time; No additional charge is incurred"
          }
        }
      }
    },
    "/api/recurring-payments/{id}/workflows": {
      "put": {
        "summary": "Document and delivery settings for future billing",
        "description": "Internal UI operation only. Saving these settings does not generate a document or send a message. Delivery depends on configuration and recipient consent; selecting a channel does not prove delivery. Manual tracking instructions do not support these payment document automations.",
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ],
        "tags": [
          "Recurring Payments"
        ],
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RecurringWorkflows"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Settings saved",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "workflows": {
                      "$ref": "#/components/schemas/RecurringWorkflows"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Incorrect settings or channel, or delivery channels without producing a document"
          },
          "403": {
            "description": "No permission"
          },
          "404": {
            "description": "The instruction was not found in the account"
          },
          "409": {
            "description": "The route is manual or the operation was not completed"
          }
        }
      }
    },
    "/external/create-payment": {
      "post": {
        "summary": "Create a payment link",
        "description": "Creates a payment or subscription approval link. A monthly subscription uses recurringData.isAutoRecurringPayment=true, frequency=monthly, interval=1. on_approval charges upon approval; on_scheduled_date stores a standard card token and first charges on startDate. Deferred registration requires a live API key, zero commission, and the terminal token module; SaaS v1 and Apple Pay/Google Pay do not support it. Preserve the 16–160 character X-Idempotency-Key and identical request body across retries. After approval, read payment and recurring status; link creation alone does not prove activation. Dedicated SaaS clients use server-approved price, currency, and redirects. Legacy profiles are realmarketing_saas and realstore_saas; the reusable profile is saas_billing. RealStore additionally requires ownerCorrelationId=store-<storeId>. All SaaS clients require metadata.planId, planVersion, and billingConsentId. mode=test_only returns a server-owned returnUrl without a CardCom call. mode=live requires a separate server gate for the client profile; the generic saas_billing profile also requires per-client live approval. New requests also require the captured document binding to support the requested currency and payment method. An ILS-only CardCom receipt binding does not permit a new USD payment. Checks do not expand verified capabilities or change historical issuers; completed idempotent replays retain the recorded result.\n\nUI name: קישור לאישור הוראת קבע (Recurring payment approval link). This operation is listed under Payments as Create a payment link. External integrations use X-API-Key; the internal UI uses POST /api/create-payment with Firebase Bearer authentication. For monthly billing use recurringData.isAutoRecurringPayment=true, frequency=monthly and interval=1. initialCharge=on_approval charges after verified approval and stores the card for later cycles; startDate is the next automatic charge. initialCharge=on_scheduled_date stores the card after verified approval without charging now; startDate is the first future charge. operationState=link_created confirms link creation only, not customer approval, a successful payment or activation. Read payment and recurring status after approval. Where approvalLinkExpiresAt is returned for a managed local approval link, it describes RealPayment's pending-approval deadline; CardCom controls form validity separately and may expire it sooner. The local deadline does not extend or reopen the provider form.",
        "tags": [
          "Payments"
        ],
        "parameters": [
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128
            },
            "description": "SaaS v1 requires 8–128 safe ASCII characters. Deferred registration with a standard card requires 16–160 ASCII letters, digits, hyphens, or underscores. A 16–128 character key works for both. Missing the key in deferred registration returns 428 before a record or provider call is made. Reuse the same key and body on retry. This requirement does not change ordinary external payment link creation outside deferred registration and SaaS v1."
          },
          {
            "name": "X-RealPayment-Contract-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "saas-v1"
              ]
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePaymentRequest"
              },
              "examples": {
                "monthlyDeferred": {
                  "summary": "Sign up for a free subscription now — just an example, a future date must be selected",
                  "value": {
                    "amount": 110,
                    "currency": "ILS",
                    "description": "Monthly subscription",
                    "customerName": "Sample customer",
                    "customerPhone": "0500000000",
                    "numOfPayments": 1,
                    "recurringData": {
                      "isAutoRecurringPayment": true,
                      "initialCharge": "on_scheduled_date",
                      "frequency": "monthly",
                      "interval": 1,
                      "totalBills": 0,
                      "startDate": "2030-01-01"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success - wrapped customer link, technical CardCom link, payment IDs and direct debit data if applicable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreatePaymentResponse"
                }
              }
            }
          },
          "400": {
            "description": "validation error, or DEFERRED_REGISTRATION_TEST_MODE_NOT_SUPPORTED / DEFERRED_REGISTRATION_COMMISSION_NOT_SUPPORTED / SAAS_DEFERRED_REGISTRATION_NOT_SUPPORTED; Without creating a provider link on blocked routes An unsupported currency returns INVALID_CURRENCY for a one-time payment or RECURRING_CURRENCY_UNSUPPORTED for a recurring request; no payment or provider call is created for that invalid currency.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringApiError"
                }
              }
            }
          },
          "401": {
            "description": "API Key is missing or incorrect"
          },
          "409": {
            "description": "A key returns with a different body or a work-in-progress/incomplete result"
          },
          "428": {
            "description": "The link creation policy requires a trial key"
          },
          "429": {
            "description": "Rate limit"
          },
          "500": {
            "description": "The link creation was not completed"
          }
        }
      }
    },
    "/external/create-invoice": {
      "post": {
        "summary": "Create a tax invoice",
        "tags": [
          "Documents"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "customerName",
                  "items"
                ],
                "properties": {
                  "customerName": {
                    "type": "string",
                    "minLength": 2
                  },
                  "customerPhone": {
                    "type": "string"
                  },
                  "customerEmail": {
                    "type": "string"
                  },
                  "customerTaxId": {
                    "type": "string",
                    "description": "Customer H.P./E.M., 9 digits. Mandatory when the tax invoice requires an allocation number according to Israeli invoices",
                    "pattern": "^[0-9]{9}$"
                  },
                  "items": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "type": "object",
                      "required": [
                        "description",
                        "quantity",
                        "price"
                      ],
                      "properties": {
                        "description": {
                          "type": "string",
                          "minLength": 1
                        },
                        "quantity": {
                          "description": "Send a JSON number. Positive quantity. Numbers or complete decimal strings are accepted; booleans, nonfinite values and strings with extra characters are rejected.",
                          "type": "number",
                          "minimum": 0,
                          "exclusiveMinimum": true
                        },
                        "price": {
                          "description": "Send a JSON number. Non-negative unit price. Zero is valid. Numbers or complete decimal strings are accepted; booleans, nonfinite values and strings with extra characters are rejected.",
                          "type": "number",
                          "minimum": 0
                        }
                      }
                    }
                  },
                  "allocationNumber": {
                    "type": "string",
                    "description": "Allocation number from the Tax Authority, 9 digits. Mandatory when the invoice is above the legal threshold before VAT",
                    "pattern": "^[0-9]{9}$"
                  },
                  "notes": {
                    "type": "string"
                  },
                  "dueDate": {
                    "type": "string",
                    "format": "date"
                  },
                  "requestId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 180,
                    "pattern": "^[A-Za-z0-9_.:-]+$",
                    "description": "Stable document issuance identity. Use the same value and body for retries. If any Idempotency-Key or X-Idempotency-Key header is also sent, every supplied identity must match."
                  },
                  "paymentId": {
                    "type": "string",
                    "description": "Existing owned payment to link to this document. The amount, currency and customer must match the immutable payment."
                  },
                  "parentDocumentId": {
                    "type": "string",
                    "description": "Existing owned source document when the selected issuance flow supports it; this does not authorize a correction or monetary refund."
                  },
                  "currency": {
                    "type": "string",
                    "enum": [
                      "ILS",
                      "USD"
                    ],
                    "default": "ILS"
                  },
                  "customerId": {
                    "type": "string",
                    "description": "Existing customer owned by the API key account; supplied contact details must resolve consistently."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Document finalized; legacy endpoint-specific ID/number aliases are retained.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountingDocumentCreateResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure, DOCUMENT_PROVIDER_REQUEST_ID_REQUIRED or conflicting issuance identities.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountingDocumentError"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or inactive X-API-Key."
          },
          "403": {
            "description": "Owner or provider permission denied; dedicated SaaS billing clients cannot use this document-creation route."
          },
          "404": {
            "description": "Linked payment or source document was not found."
          },
          "409": {
            "description": "Conflicting request, provider readiness block or unconfirmed issuance outcome. Keep the existing identity and inspect operationId/safeToEdit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountingDocumentError"
                }
              }
            }
          },
          "429": {
            "description": "API client rate limit exceeded."
          },
          "500": {
            "description": "Document generation or publication failed. Do not infer absence of an issued document from this response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountingDocumentError"
                }
              }
            }
          },
          "502": {
            "description": "Document provider did not return a verified successful result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountingDocumentError"
                }
              }
            }
          }
        },
        "description": "Available to ordinary external API clients under their owner account; dedicated saas_billing, realmarketing_saas and realstore_saas clients cannot call this route. The accounting issuer is selected server-side. For CardCom issuance without paymentId, supply a stable requestId or issuance header. Provider readiness, enabled document type and document compliance are checked before issuance. Test mode cannot issue through a live provider binding. After an uncertain outcome, inspect the existing operation; do not retry with a new identity. Legacy internal issuance does not provide the same durable replay guarantee.",
        "parameters": [
          {
            "$ref": "#/components/parameters/DocumentIdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/DocumentXIdempotencyKey"
          }
        ]
      }
    },
    "/external/create-quote": {
      "post": {
        "summary": "Create a quote",
        "tags": [
          "Documents"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "customerName"
                ],
                "properties": {
                  "customerName": {
                    "type": "string",
                    "minLength": 2
                  },
                  "customerPhone": {
                    "type": "string"
                  },
                  "customerEmail": {
                    "type": "string"
                  },
                  "items": {
                    "type": "array",
                    "minItems": 0,
                    "items": {
                      "type": "object",
                      "required": [
                        "description",
                        "quantity",
                        "price"
                      ],
                      "properties": {
                        "description": {
                          "type": "string",
                          "minLength": 1
                        },
                        "quantity": {
                          "description": "Send a JSON number. Positive quantity. Numbers or complete decimal strings are accepted; booleans, nonfinite values and strings with extra characters are rejected.",
                          "type": "number",
                          "minimum": 0,
                          "exclusiveMinimum": true
                        },
                        "price": {
                          "description": "Send a JSON number. Non-negative unit price. Zero is valid. Numbers or complete decimal strings are accepted; booleans, nonfinite values and strings with extra characters are rejected.",
                          "type": "number",
                          "minimum": 0
                        }
                      }
                    },
                    "maxItems": 100,
                    "description": "If nonempty, items are authoritative. Unit prices are rounded half-up to cents before quantity multiplication; rows are rounded to cents and summed. An empty list requires amount."
                  },
                  "notes": {
                    "type": "string"
                  },
                  "validUntil": {
                    "type": "string",
                    "format": "date"
                  },
                  "amount": {
                    "type": "number",
                    "minimum": 0,
                    "description": "Amount BEFORE VAT; used only when items is absent or empty. Complete decimal strings also accepted; prefer JSON numbers."
                  },
                  "discount": {
                    "type": "number",
                    "minimum": 0,
                    "default": 0,
                    "description": "Discount before VAT. Must not exceed the rounded item subtotal or amount."
                  },
                  "vatRate": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 100,
                    "description": "Explicit VAT rate, or the system's date-aware default when omitted."
                  },
                  "currency": {
                    "type": "string",
                    "enum": [
                      "ILS",
                      "USD"
                    ],
                    "default": "ILS"
                  },
                  "description": {
                    "type": "string",
                    "description": "Description for an amount-only quote."
                  },
                  "deliveryTime": {
                    "type": "string"
                  },
                  "customerId": {
                    "type": "string",
                    "description": "Existing customer owned by the API key account; contact data must match."
                  },
                  "requestId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 180,
                    "pattern": "^[A-Za-z0-9_.:-]+$",
                    "description": "Required stable creation identity when the server-selected issuer is CardCom. Idempotency-Key and X-Idempotency-Key aliases must match. Keep the same original body/key until the existing attempt is resolved."
                  }
                },
                "anyOf": [
                  {
                    "required": [
                      "items"
                    ],
                    "properties": {
                      "items": {
                        "minItems": 1
                      }
                    }
                  },
                  {
                    "required": [
                      "amount"
                    ]
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Quote issued, not signed or paid. Exact canonical amounts. pdfUrl is a 30-day RealPayment bearer link, not a Storage URL. If access-link preparation alone fails, success stays true, pdfAvailable=true, linkState=unavailable and pdfUrl=null; renew access rather than issuing again.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "quoteId": {
                      "type": "string"
                    },
                    "quoteNumber": {
                      "type": "string"
                    },
                    "pdfUrl": {
                      "type": "string",
                      "nullable": true
                    },
                    "totalAmount": {
                      "type": "number"
                    },
                    "currency": {
                      "type": "string",
                      "enum": [
                        "ILS",
                        "USD"
                      ]
                    },
                    "vatRate": {
                      "type": "number"
                    },
                    "subtotalBeforeVat": {
                      "type": "number",
                      "description": "Net subtotal after discount, before VAT"
                    },
                    "vatAmount": {
                      "type": "number"
                    },
                    "discount": {
                      "type": "number"
                    },
                    "quoteCalculationVersion": {
                      "type": "string",
                      "enum": [
                        "quote_cents_v1"
                      ]
                    },
                    "linkExpiresAt": {
                      "type": "string",
                      "format": "date-time",
                      "nullable": true
                    },
                    "linkLifetimeDays": {
                      "type": "integer",
                      "enum": [
                        30
                      ]
                    },
                    "linkState": {
                      "type": "string"
                    },
                    "linkMessage": {
                      "type": "string"
                    },
                    "pdfAvailable": {
                      "type": "boolean"
                    },
                    "issuerProvider": {
                      "type": "string",
                      "enum": [
                        "internal",
                        "cardcom"
                      ]
                    },
                    "idempotentReplay": {
                      "type": "boolean",
                      "description": "The existing finalized provider result was returned without issuing another record."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid quote inputs fail before customer, operation, number or PDF writes: QUOTE_ITEMS_INVALID, QUOTE_DISCOUNT_INVALID, QUOTE_INPUT_INVALID, DOCUMENT_NUMERIC_INPUT_INVALID, DOCUMENT_CURRENCY_UNSUPPORTED or DOCUMENT_PROVIDER_QUOTE_PAYMENT_SOURCE_FORBIDDEN. Includes field; safeToEdit=true.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "error"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string"
                    },
                    "errorCode": {
                      "type": "string"
                    },
                    "field": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer"
                    },
                    "safeToEdit": {
                      "type": "boolean"
                    }
                  }
                },
                "examples": {
                  "invalidRow": {
                    "summary": "Positive quantity is required",
                    "value": {
                      "success": false,
                      "errorCode": "QUOTE_ITEMS_INVALID",
                      "field": "items[0].quantity",
                      "safeToEdit": true,
                      "error": "כמות הפריט חייבת להיות חיובית והמחיר אינו יכול להיות שלילי."
                    }
                  },
                  "excessDiscount": {
                    "summary": "Discount exceeds subtotal",
                    "value": {
                      "success": false,
                      "errorCode": "QUOTE_DISCOUNT_INVALID",
                      "field": "discount",
                      "safeToEdit": true,
                      "error": "ההנחה אינה יכולה להיות גדולה מסכום הפריטים בהצעה."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Unready/disabled signature or provider chain, unsupported binding/type/currency, changed payload, provider rejection or unresolved provider outcome. Retain key/body and inspect the existing operation; do not fall back or blindly reissue.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "errorCode": {
                      "type": "string"
                    },
                    "error": {
                      "type": "string"
                    },
                    "operationId": {
                      "type": "string",
                      "description": "Existing owned provider attempt to inspect/complete/reconcile; retain it with the original client request identity."
                    },
                    "safeToEdit": {
                      "type": "boolean",
                      "description": "Only explicit true permits an edited submission. False or absent must not be bypassed using a fresh identity."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "A provider record may already exist (DOCUMENT_PROVIDER_LOCAL_PENDING); local publication/readback is unfinished. Continue the existing operation, never issue again.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "errorCode": {
                      "type": "string"
                    },
                    "error": {
                      "type": "string"
                    },
                    "operationId": {
                      "type": "string",
                      "description": "Existing owned provider attempt to inspect/complete/reconcile; retain it with the original client request identity."
                    },
                    "safeToEdit": {
                      "type": "boolean",
                      "description": "Only explicit true permits an edited submission. False or absent must not be bypassed using a fresh identity."
                    }
                  }
                }
              }
            }
          }
        },
        "description": "Ordinary external API clients only. Requires customerName plus described items (maximum 100) or amount BEFORE VAT. Positive quantities, non-negative prices and complete finite numeric values are required; booleans and numeric strings with trailing text are rejected. New quotes use quote_cents_v1: round unit prices and rows to cents, subtract a non-negative discount bounded by subtotal, then round VAT once. Nonempty items override amount. Currency ILS/USD only; no cross-currency offsets. Quote creation is not customer signature, payment, receipt, refund or conversion. paymentId, parentDocumentId and refundEventId are forbidden here. Legacy issued quote files are not rewritten. Existing invoice/refund arithmetic is unchanged; the dedicated conversion route preserves canonical new quote cents. A shared URL is bearer access, valid 30 days; cancellation or closed owner blocks reads. Existing previously shared Storage links retain their original expiry. The server selects the issuer: internal or the active verified CardCom binding. CardCom creates a real Quote record, retains an immutable original provider PDF and requires the explicitly enabled separate-acknowledgment chain. Supply one stable requestId or issuance header; all supplied identities must agree. A replay preserves the captured issuer and canonical cents. No fallback to internal occurs after provider dispatch or an unknown outcome. CardCom requires a positive final quote total; zero-price rows remain supported inside a positive quote. A whole zero-total CardCom quote returns DOCUMENT_PROVIDER_QUOTE_ZERO_UNSUPPORTED before dispatch. Production binding cannot be used in API test mode. Quote currency remains restricted by the actual binding. DOCUMENT_PROVIDER_OUTCOME_UNKNOWN (409) and DOCUMENT_PROVIDER_LOCAL_PENDING (503) include operationId and safeToEdit=false; they are not an invitation to create a fresh identity. An owner can inspect and reconcile the existing operation with Firebase Bearer authentication; X-API-Key cannot call those internal recovery routes.",
        "parameters": [
          {
            "$ref": "#/components/parameters/DocumentIdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/DocumentXIdempotencyKey"
          }
        ]
      }
    },
    "/external/create-receipt": {
      "post": {
        "summary": "Creating a receipt",
        "tags": [
          "Documents"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "customerName",
                  "amount",
                  "description"
                ],
                "properties": {
                  "customerName": {
                    "type": "string",
                    "minLength": 2
                  },
                  "amount": {
                    "description": "Send a JSON number. Nonzero signed receipt amount. A negative amount preserves the existing internal receipt contract; it does not refund a payment or bypass provider correction restrictions. Numbers or complete decimal strings are accepted; booleans, nonfinite values and strings with extra characters are rejected.",
                    "type": "number",
                    "not": {
                      "enum": [
                        0
                      ]
                    }
                  },
                  "description": {
                    "type": "string",
                    "minLength": 2
                  },
                  "paymentMethod": {
                    "type": "string"
                  },
                  "requestId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 180,
                    "pattern": "^[A-Za-z0-9_.:-]+$",
                    "description": "Stable document issuance identity. Use the same value and body for retries. If any Idempotency-Key or X-Idempotency-Key header is also sent, every supplied identity must match."
                  },
                  "paymentId": {
                    "type": "string",
                    "description": "Existing owned payment to link to this document. The amount, currency and customer must match the immutable payment."
                  },
                  "parentDocumentId": {
                    "type": "string",
                    "description": "Existing owned source document when the selected issuance flow supports it; this does not authorize a correction or monetary refund."
                  },
                  "currency": {
                    "type": "string",
                    "enum": [
                      "ILS",
                      "USD"
                    ],
                    "default": "ILS"
                  },
                  "customerId": {
                    "type": "string",
                    "description": "Existing customer owned by the API key account; supplied contact details must resolve consistently."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Document finalized; legacy endpoint-specific ID/number aliases are retained.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountingDocumentCreateResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure, DOCUMENT_PROVIDER_REQUEST_ID_REQUIRED or conflicting issuance identities.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountingDocumentError"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or inactive X-API-Key."
          },
          "403": {
            "description": "Owner or provider permission denied; dedicated SaaS billing clients cannot use this document-creation route."
          },
          "404": {
            "description": "Linked payment or source document was not found."
          },
          "409": {
            "description": "Conflicting request, provider readiness block or unconfirmed issuance outcome. Keep the existing identity and inspect operationId/safeToEdit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountingDocumentError"
                }
              }
            }
          },
          "429": {
            "description": "API client rate limit exceeded."
          },
          "500": {
            "description": "Document generation or publication failed. Do not infer absence of an issued document from this response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountingDocumentError"
                }
              }
            }
          },
          "502": {
            "description": "Document provider did not return a verified successful result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountingDocumentError"
                }
              }
            }
          }
        },
        "description": "Available to ordinary external API clients under their owner account; dedicated saas_billing, realmarketing_saas and realstore_saas clients cannot call this route. The accounting issuer is selected server-side. For CardCom issuance without paymentId, supply a stable requestId or issuance header. Provider readiness, enabled document type and document compliance are checked before issuance. Test mode cannot issue through a live provider binding. After an uncertain outcome, inspect the existing operation; do not retry with a new identity. Legacy internal issuance does not provide the same durable replay guarantee.",
        "parameters": [
          {
            "$ref": "#/components/parameters/DocumentIdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/DocumentXIdempotencyKey"
          }
        ]
      }
    },
    "/external/payment-status/{paymentId}": {
      "get": {
        "summary": "Payment status",
        "tags": [
          "Payments"
        ],
        "parameters": [
          {
            "name": "paymentId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ownerCorrelationId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "A must for a dedicated SaaS customer; Must match the payee."
          }
        ],
        "responses": {
          "200": {
            "description": "payment object with status"
          }
        },
        "description": "For an owned pending deferred registration, this read can reconcile a provider-verified CreateTokenOnly/J2 result through the existing callback and atomic activation pipeline. A response code alone is insufficient: provider operation, JParameter and stored tenant/terminal/LowProfile/request identities must match. Recovery activates only the already-approved future instruction with zero initial charges, revenue or documents; it does not create another checkout."
      }
    },
    "/external/payments/{paymentId}/document": {
      "get": {
        "summary": "Download a secure vendor document for SaaS payment",
        "description": "Available only to a dedicated SaaS billing API client. RealPayment downloads the document server to server only from secure.cardcom.solutions, follows no redirects, limits it to 10 MB, and returns PDF or octet-stream. The raw provider URL is never returned.",
        "tags": [
          "SaaS Billing"
        ],
        "parameters": [
          {
            "name": "paymentId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ownerCorrelationId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A verified binary document",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "example": "private, no-store, max-age=0"
                }
              }
            },
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "404": {
            "description": "The payment or document was not found for the requested owner"
          },
          "409": {
            "description": "The payment has not been completed or the provider's host/content-type has not yet been verified"
          },
          "502": {
            "description": "The vendor document is temporarily unavailable"
          }
        }
      }
    },
    "/external/analytics": {
      "get": {
        "summary": "Usage analytics",
        "tags": [
          "Analytics"
        ],
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "schema": {
              "type": "number",
              "default": 30
            }
          }
        ],
        "responses": {
          "200": {
            "description": "calls, revenue, wallet, daily"
          }
        }
      }
    },
    "/external/documents": {
      "get": {
        "summary": "List of documents",
        "tags": [
          "Documents"
        ],
        "parameters": [
          {
            "name": "type",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "invoice",
                "quote",
                "receipt"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "number",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "documents array"
          }
        }
      }
    },
    "/external/document/{id}": {
      "get": {
        "summary": "Single document",
        "tags": [
          "Documents"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "document object"
          }
        }
      },
      "put": {
        "summary": "Document update",
        "tags": [
          "Documents"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Recognized fields: customerName, customerPhone, customerEmail, customerAddress, notes, metadata, status. General status values are draft, sent, viewed and cancelled; emitted/protected active quotes and final accounting documents permit only sent/viewed. Current owner/state and immutable content rules are checked before committing the update."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "success"
          },
          "400": {
            "description": "Unsupported status; field=status. General status validation runs before immutable-state checks.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "error"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string"
                    },
                    "errorCode": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer"
                    },
                    "field": {
                      "type": "string"
                    },
                    "blockedFields": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Document belongs to a different owner, including a latest-owner change detected by the atomic update.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "error"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string"
                    },
                    "errorCode": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer"
                    },
                    "field": {
                      "type": "string"
                    },
                    "blockedFields": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Document not found, including removal detected by the atomic update.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "error"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string"
                    },
                    "errorCode": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer"
                    },
                    "field": {
                      "type": "string"
                    },
                    "blockedFields": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Quote content/status is protected; accounting-document immutable/status guards or a source-operation binding also block an update.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "error"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string"
                    },
                    "errorCode": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer"
                    },
                    "field": {
                      "type": "string"
                    },
                    "blockedFields": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                },
                "examples": {
                  "quoteContentBlocked": {
                    "summary": "Issued or signed quote content cannot be changed",
                    "value": {
                      "success": false,
                      "status": 409,
                      "errorCode": "QUOTE_DOCUMENT_EDIT_BLOCKED",
                      "blockedFields": [
                        "notes"
                      ],
                      "error": "תוכן הצעה שכבר הופקה או נמצאת בחתימה או בהמרה אינו ניתן לעריכה. יש ליצור הצעה חדשה."
                    }
                  },
                  "quoteStatusBlocked": {
                    "summary": "A protected quote cannot become draft/cancelled through ordinary PUT",
                    "value": {
                      "success": false,
                      "status": 409,
                      "errorCode": "QUOTE_DOCUMENT_STATUS_CHANGE_BLOCKED",
                      "blockedFields": [
                        "status"
                      ],
                      "error": "אפשר לעדכן רק סטטוס שליחה או צפייה בהצעה פעילה. ביטול מתבצע במסלול הביטול."
                    }
                  }
                }
              }
            }
          }
        },
        "description": "Updates recognized customer contact/address, notes, metadata or status fields on an owned document when its current lifecycle allows it. A quote with its number and an emitted PDF/snapshot or pending signature, captured or processing signature, started signature/conversion operation, conversion link or cancellation is protected from content edits, returning 409 QUOTE_DOCUMENT_EDIT_BLOCKED. On an active protected quote, status=sent or viewed is allowed and does not change its saved content/signature. Reverting to draft or cancelling via ordinary PUT returns 409 QUOTE_DOCUMENT_STATUS_CHANGE_BLOCKED; a cancelled quote cannot be revived with sent/viewed. Use the supported cancellation flow. A genuine legacy quote draft without an emitted artifact, captured signature or started operation remains editable for recognized fields. Owner and latest document/signature/conversion state are re-read in the same transaction as the update. A different owner returns 403; a missing document returns 404. Final accounting-document content and status guards remain in force (FINAL_DOCUMENT_EDIT_BLOCKED or FINAL_DOCUMENT_STATUS_CHANGE_BLOCKED); nonfinal accounting status changes return ACCOUNTING_DOCUMENT_NOT_FINAL_STATUS_BLOCKED. This route changes neither amounts/numbers nor the issued PDF and adds no replay, issuance or provider capability."
      },
      "delete": {
        "summary": "Deleting a document",
        "tags": [
          "Documents"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "success"
          }
        }
      }
    },
    "/external/document/{id}/send": {
      "post": {
        "summary": "Sending a document to the client",
        "tags": [
          "Documents"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "channel"
                ],
                "properties": {
                  "channel": {
                    "type": "string",
                    "enum": [
                      "whatsapp",
                      "email"
                    ]
                  },
                  "phone": {
                    "type": "string"
                  },
                  "email": {
                    "type": "string"
                  },
                  "message": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "success, sentVia, sentTo"
          }
        }
      }
    },
    "/external/document/{id}/signature-status": {
      "get": {
        "summary": "Signature status",
        "tags": [
          "Signatures"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current signature/publication state, original URL and distinct acknowledgment URL when ready.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentSignatureStatusResponse"
                }
              }
            }
          }
        },
        "description": "Owned ordinary-client readback. Captured signature alone is insufficient: preparing/failed publication stays pending and downstream sales/messages do not advance until the current PDF proof is ready. CardCom customer approval is a separate linked acknowledgment, not a modification to the original provider document or payment evidence. Original and acknowledgment access can be temporarily unavailable independently of successful capture/publication; renew access instead of signing or issuing again."
      }
    },
    "/external/create-signature-link": {
      "post": {
        "summary": "Create a signature link",
        "tags": [
          "Signatures"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "documentId",
                  "signerName"
                ],
                "properties": {
                  "documentId": {
                    "type": "string",
                    "minLength": 1
                  },
                  "signerName": {
                    "type": "string",
                    "minLength": 1
                  },
                  "signerPhone": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "signatureLink as a short /s/ URL, for example https://realpayment.co.il/s/a1b2c3d4e5, expiresAt"
          },
          "400": {
            "description": "Missing documentId/signerName, non-quote document or already signed quote."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "Document ownership denied or dedicated SaaS route unavailable."
          },
          "404": {
            "description": "Document not found."
          },
          "500": {
            "description": "Signature-link creation did not complete."
          }
        },
        "description": "Ordinary external API clients only. The document must be an owned unsigned quote. Creating a replacement signature request invalidates its previous token; this endpoint does not have an issuance idempotency contract. CardCom quotes require current separate-acknowledgment support and finalized original provenance. The original provider quote stays unchanged; a later captured signature publishes a separate acknowledgment. Merely creating/opening this link is not approval or payment."
      }
    },
    "/external/customers": {
      "get": {
        "summary": "customer list",
        "tags": [
          "Customers"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "number",
              "default": 50
            }
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "customers array"
          }
        }
      },
      "post": {
        "summary": "Creating a client",
        "tags": [
          "Customers"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCustomerRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "customerId, customer"
          }
        }
      }
    },
    "/external/customers/{id}": {
      "get": {
        "summary": "Single customer",
        "tags": [
          "Customers"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "customer object"
          }
        }
      },
      "put": {
        "summary": "Client update",
        "tags": [
          "Customers"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "success"
          }
        }
      }
    },
    "/external/sales-process/activate": {
      "post": {
        "summary": "Running a sales process",
        "description": "Triggers an automated sales process: quote → signature → payment → receipt",
        "tags": [
          "Sales Process"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SalesProcessActivateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "processId, status, quoteId"
          }
        }
      }
    },
    "/external/sales-process/status/{processId}": {
      "get": {
        "summary": "Sales process status",
        "tags": [
          "Sales Process"
        ],
        "parameters": [
          {
            "name": "processId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "process object"
          }
        }
      }
    },
    "/external/sales-process/list": {
      "get": {
        "summary": "List of sales processes",
        "tags": [
          "Sales Process"
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "number",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "processes array"
          }
        }
      }
    },
    "/external/webhook/test": {
      "post": {
        "summary": "Webhook test",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "testUrl": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Receiver returned 2xx; response.success=true, test=true and event=payment.test"
          },
          "400": {
            "description": "No webhook destination configured"
          },
          "401": {
            "description": "API key required"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Transport or signing failure, including unavailable dedicated V2 key material"
          },
          "502": {
            "description": "Receiver returned a non-2xx response; success=false"
          },
          "503": {
            "description": "Existing server-managed webhook authentication unavailable"
          }
        },
        "description": "Sends a real HTTP payment.test message to the resolved configured destination (falling back to testUrl). Uses this client's saved signing mode; an enabled dual_v2 client receives the V2 headers in x-ordinary-external-webhook-contract. Does not create a payment, charge or document. The endpoint test is not the completed-payment durable envelope/retry ledger. A 2xx response from the receiver establishes transport acceptance only.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/api/recurring-payments/{id}/charge-now": {
      "post": {
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ],
        "summary": "Immediate credit debit for standing order",
        "description": "Internal and protected endpoint for the management interface. Performs an immediate CardCom debit only for an active standing order that is backed by a card token and valid CardExpirationMMYY. A direct debit managed by CardCom will not be charged here to avoid double charging. The displayed expectedBillNumber and expectedCardCredentialVersion must be sent to confirm and save X-Idempotency-Key on each retry. The amount is read from the instruction; Success consumes the next charge and advances the date. A repeated request for the same identity returns the existing transaction even after completion, delay or replacement of a card.",
        "tags": [
          "Recurring Payments"
        ],
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Standing order ID in the system."
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 160,
              "pattern": "^[A-Za-z0-9_-]+$"
            },
            "description": "stable developer for experience; Do not generate a new key when the result is unknown. Using the same key for another cycle is blocked."
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RecurringChargeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The charge has been made or an already completed attempt has been returned without further charge",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringChargeResponse"
                }
              }
            }
          },
          "400": {
            "description": "The direct debit is not active, is managed by CardCom, or is not backed by an appropriate token"
          },
          "403": {
            "description": "No permission or route SaaS requires protected recover"
          },
          "404": {
            "description": "Instruction not found"
          },
          "409": {
            "description": "The charge context has changed, no valid token/validity, previous failure or inconclusive result. errorCode and recoveryAction must be read; Do not repeat a charge or change a card to bypass an unknown result."
          },
          "500": {
            "description": "The operation was not completed"
          },
          "502": {
            "description": "Incomplete doubt result; Check providerOutcome/errorCode, and don't assume it's safe to charge again"
          },
          "503": {
            "description": "There is a charge in progress or an unknown result; The existing experience must be ascertained"
          }
        }
      }
    },
    "/api/recurring-payments/manual": {
      "post": {
        "summary": "Creating a manual tracking order in the management interface",
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ],
        "description": "Internal interface with Firebase ID token. Follow-up order creator and canonical customer; Does not open a clearing and does not require a card. It is mandatory to save the same X-Idempotency-Key in a repeated attempt.",
        "tags": [
          "Recurring Payments"
        ],
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "parameters": [
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 160,
              "pattern": "^[A-Za-z0-9_-]+$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManualRecurringCreateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "A tracking order was created or returned without duplicates"
          },
          "400": {
            "description": "Bad request data"
          },
          "409": {
            "description": "A trial key has already been used for other data"
          },
          "428": {
            "description": "Missing experience key"
          }
        }
      }
    },
    "/api/recurring-payments/{id}/record-manual": {
      "post": {
        "summary": "Registering a manual payment in a follow-up order",
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ],
        "description": "Registers a payment reported by an operator, without contacting CardCom. The history record is checked isManual=true; It should not be considered a confirmation of clearance from the supplier.",
        "tags": [
          "Recurring Payments"
        ],
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 160,
              "pattern": "^[A-Za-z0-9_-]+$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManualRecurringRecordRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The record is saved or restored without duplication"
          },
          "409": {
            "description": "The teaching situation has changed; It should be read again"
          },
          "428": {
            "description": "The next cycle number is missing"
          }
        }
      }
    },
    "/external/recurring-payments/manual": {
      "post": {
        "summary": "Manually create a tracking instruction in an external API",
        "description": "Creates a manual recurring instruction and canonical customer under the API key owner's account. This is tracking only: no approval link, stored card, or automatic charge. Dedicated SaaS billing clients cannot use this action. Reusing the same idempotency key and body returns the original instruction; reusing a key with a different body is rejected.",
        "tags": [
          "Recurring Payments"
        ],
        "parameters": [
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 160,
              "pattern": "^[A-Za-z0-9_-]+$"
            },
            "description": "Stable key for one creation attempt. Do not change it before the result is known."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManualRecurringCreateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "A tracking order was created or returned without duplicates; recurringPayment contains billingMode=manual_tracking"
          },
          "400": {
            "description": "Bad request data"
          },
          "403": {
            "description": "The operation is blocked for a dedicated SaaS contract"
          },
          "409": {
            "description": "A trial key has already been used for other data"
          },
          "428": {
            "description": "X-Idempotency-Key is missing"
          }
        }
      }
    },
    "/external/recurring-payments/{id}/record-manual": {
      "post": {
        "summary": "Registering a manual payment cycle in an external API",
        "description": "Registers a cycle in a trace instruction generated by that API client. does not charge the clearing provider. Retrying with the same ID and cycle number does not incur an additional charge. Success is manual registration only, not proof of payment.",
        "tags": [
          "Recurring Payments"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 160,
              "pattern": "^[A-Za-z0-9_-]+$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManualRecurringRecordRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Cycle registered or returned without duplicates; isManual=true, providerCharge=false"
          },
          "403": {
            "description": "The operation is blocked for a dedicated SaaS contract"
          },
          "404": {
            "description": "The directive does not belong to this API client"
          },
          "409": {
            "description": "The state of the instruction has changed or the attempt has already been used for another operation"
          },
          "428": {
            "description": "Missing X-Idempotency-Key or expectedBillNumber"
          }
        }
      }
    },
    "/external/recurring-payments": {
      "get": {
        "summary": "List of standing orders",
        "description": "Returns a list of standing instructions with limited contact information only: customerPhoneSuffix and customerEmailHint. You can filter by status. The results are sorted by record ID. If pageInfo.hasMore is true, pageInfo.nextCursor must be sent as a cursor with the same status to get the next page; count refers to the current page only. For full contact details use a single standing order call.",
        "tags": [
          "Recurring Payments"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 100,
              "minimum": 1,
              "maximum": 500
            },
            "description": "Number of records to return. Default: 100, Max: 500."
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "paused",
                "cancelled",
                "completed",
                "failed",
                "disabled"
              ]
            },
            "description": "Optional filtering by standing order status."
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "The previous page marker from pageInfo.nextCursor. The same status filter must be maintained between the pages."
          }
        ],
        "responses": {
          "200": {
            "description": "current page's recurringPayments, count and pageInfo with hasMore and nextCursor",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringListResponse"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_LIMIT / INVALID_CURSOR / Invalid status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "429": {
            "description": "Rate limit"
          },
          "500": {
            "description": "The list was not loaded"
          }
        }
      }
    },
    "/external/recurring-payments/{id}": {
      "get": {
        "summary": "Single standing order",
        "description": "Returns a recurring instruction owned by the API key owner's account. Dedicated SaaS clients must also provide ownerCorrelationId, and the instruction must belong to the same apiClientId. Raw card and token data are never returned. Use nextBillDate/lastChargeDate for timing and capabilities for currently allowed actions.",
        "tags": [
          "Recurring Payments"
        ],
        "parameters": [
          {
            "name": "ownerCorrelationId",
            "in": "query",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,128}$"
            },
            "description": "Required for a dedicated SaaS client; must match the subscription owner. It is not a card identifier."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "recurringPayment object",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringReadResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid SaaS contract details"
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "403": {
            "description": "An instruction from a business owner or other API client"
          },
          "404": {
            "description": "Recurring payment not found"
          },
          "429": {
            "description": "Rate limit"
          },
          "500": {
            "description": "The information is not loaded"
          }
        }
      }
    },
    "/external/recurring-payments/{id}/history": {
      "get": {
        "summary": "Direct debit charge history",
        "description": "The results are sorted by record ID. If pageInfo.hasMore is true, pageInfo.nextCursor should be sent as a cursor to that directive. count refers to the current page only; The billing date appears on each record. summary is calculated from verified transactions up to 1,000 records and not from multiplying the amount of the instruction. totals separated by currency and in penny units: grossMinor, refundedMinor and netMinor. partial or unresolvedCount indicates an incomplete summary. bankSettlementConfirmed=false: There is no bank credit confirmation.",
        "tags": [
          "Recurring Payments"
        ],
        "parameters": [
          {
            "name": "ownerCorrelationId",
            "in": "query",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,128}$"
            },
            "description": "Required for a dedicated SaaS client; the instruction must also belong to the same apiClientId."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 500,
              "minimum": 1,
              "maximum": 500
            },
            "description": "Number of history records to return. Default and maximum: 500."
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Mark the previous page from pageInfo.nextCursor of that standing order."
          }
        ],
        "responses": {
          "200": {
            "description": "history of the current page, count and pageInfo with hasMore and nextCursor; summary with confirmedCount, unresolvedCount, partial, totals and bankSettlementConfirmed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringHistoryResponse"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_LIMIT / INVALID_CURSOR or missing SaaS information",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "403": {
            "description": "No access to instruction"
          },
          "404": {
            "description": "Instruction not found"
          },
          "429": {
            "description": "Rate limit"
          },
          "500": {
            "description": "History is not loaded"
          }
        }
      }
    },
    "/external/recurring-payments/{id}/charge-now": {
      "post": {
        "summary": "Immediate debit of a standing order from a reserved token",
        "description": "Charges the fixed amount of an ordinary recurring instruction using its stored token. Do not send card details or an amount. Send expectedBillNumber and expectedCardCredentialVersion from the chargeContext snapshot; a stable X-Idempotency-Key is also recommended. Alternatively, omit the body and send only a stable key, which the server binds once to the current cycle. A request with neither snapshot nor key returns 409. Retries must preserve the original key and snapshot and cannot charge the next period. Dedicated SaaS clients cannot use this action; after a failed renewal, use /recover.",
        "tags": [
          "Recurring Payments"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 160,
              "pattern": "^[A-Za-z0-9_-]+$"
            },
            "description": "Mandatory if no chargeContext snapshot is sent. The same key must be preserved for each retry."
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RecurringChargeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The charge has been made or has already been completed in a previous request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringChargeResponse"
                }
              }
            }
          },
          "400": {
            "description": "The instruction is not active, managed by CardCom, or is not in token track"
          },
          "404": {
            "description": "Recurring payment not found"
          },
          "409": {
            "description": "The charge is already in progress, completed, previously declined, or the card requires a refresh"
          },
          "502": {
            "description": "CardCom declined the charge"
          },
          "503": {
            "description": "The outcome of the dispute is still uncertain; Do not try again immediately"
          }
        }
      }
    },
    "/external/recurring-payments/{id}/recover": {
      "post": {
        "summary": "Single recovery attempt after card renewal and update failure",
        "description": "Available only to a dedicated SaaS client with policy.mode=live and its server live gate enabled. Requires failedPaymentId from the failed scheduler attempt and a newer card credential version. The scheduler does not retry automatically. Only one explicit recovery is allowed per billing cycle; replay uses the same operation identity and cannot charge twice. This endpoint is not available to ordinary token plans. Their existing next-due-run behavior after verified card replacement remains unchanged. An unknown charge result cannot be bypassed by updating a card or starting another recovery.",
        "tags": [
          "SaaS Billing"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SaasRecurringRecoveryRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The recovery was successful or a replay of the same operation was returned",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringChargeResponse"
                }
              }
            }
          },
          "409": {
            "description": "The card has not been updated, the failed payment does not match, or the only recovery attempt has already been used"
          },
          "503": {
            "description": "The outcome of the dispute is uncertain; Only the same request is allowed for reconciliation/replay"
          }
        }
      }
    },
    "/external/recurring-payments/{id}/refresh-card-link": {
      "post": {
        "summary": "Creating a secure link to refresh a card",
        "description": "Creates a link to send the customer for saving a new card on an existing recurring instruction. For dedicated SaaS clients, policy.mode=live and the client server live gate are required, and the provider returns to the approved billing screen. After a failed SaaS renewal, this link is allowed even when the old token still exists. A new token is stored only after customer approval and a verified CardCom result; it is never returned through the API. An ambiguous LowProfile/Create outcome (including timeout, network failure, HTTP 5xx/408/429 or incomplete success) keeps the original card-refresh attempt and lock. The initial response is 503 with canRetry=false and the original paymentId; a repeated request returns 409 and cannot create a second link. Do not change identities or clear a lock to bypass this state. A callback may still complete the original attempt; without a returned LowProfileId, automated provider lookup is not established. Resolve the existing attempt before another creation. A known definitive provider rejection can release the lock; generic errors do not grant permission to retry. For an ordinary token plan, a verified saved replacement card clears the credential failure and an overdue bill may be charged by the next due scheduler run. This existing collection timing is unchanged. A dedicated SaaS plan instead retains its explicit /recover requirement.",
        "tags": [
          "Recurring Payments"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128
            },
            "description": "A must for a dedicated SaaS customer."
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SaasRecurringActionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A link has been created to save a card again",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringCardRefreshResponse"
                }
              }
            }
          },
          "400": {
            "description": "It is not possible to refresh a card in the current state"
          },
          "404": {
            "description": "Recurring payment not found"
          },
          "409": {
            "description": "Existing refresh has unknown outcome (RECURRING_CARD_REFRESH_PROVIDER_OUTCOME_UNKNOWN), state changed, charge is unresolved, or another operation blocks creation. Unknown/state-changed responses have canRetry=false and retain the original paymentId.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringCardRefreshFailure"
                }
              }
            }
          },
          "503": {
            "description": "New card-refresh creation outcome is unknown: RECURRING_CARD_REFRESH_PROVIDER_OUTCOME_UNKNOWN for ordinary plans or SAAS_CARD_UPDATE_PROVIDER_OUTCOME_UNKNOWN for SaaS. canRetry=false; no second Create is safe. Other existing policy-unavailable responses retain their own error code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringCardRefreshFailure"
                },
                "examples": {
                  "ordinaryUnknown": {
                    "value": {
                      "success": false,
                      "paymentId": "existing_refresh_attempt",
                      "error": "The original card-refresh creation outcome must be checked.",
                      "errorCode": "RECURRING_CARD_REFRESH_PROVIDER_OUTCOME_UNKNOWN",
                      "canRetry": false
                    }
                  },
                  "saasUnknown": {
                    "value": {
                      "success": false,
                      "paymentId": "existing_saas_refresh_attempt",
                      "error": "The original card-refresh creation outcome must be checked.",
                      "errorCode": "SAAS_CARD_UPDATE_PROVIDER_OUTCOME_UNKNOWN",
                      "canRetry": false
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/external/recurring-payments/{id}/status": {
      "patch": {
        "summary": "Update standing order status",
        "description": "Setting cancelled or paused stops new charges in RealPayment's token flow. Cancellation does not refund past charges. chargeInFlight=true means a charge already sent to the provider may still complete. Cancelled or completed instructions cannot be reopened. CardCom-managed instructions return 400 because cancellation must also occur at the provider. Dedicated SaaS clients cannot use this route (403 SAAS_STATUS_MUTATION_NOT_ALLOWED); use cancel-at-period-end or resume as appropriate.",
        "tags": [
          "Recurring Payments"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateRecurringStatusRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "status, recurringPayment and chargeInFlight",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringStatusResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid status, final instruction or CardCom-managed; No suspension was performed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "403": {
            "description": "No permission or SAAS_STATUS_MUTATION_NOT_ALLOWED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringApiError"
                }
              }
            }
          },
          "404": {
            "description": "Instruction not found"
          },
          "409": {
            "description": "Billing in process requires review before change"
          },
          "429": {
            "description": "Rate limit"
          },
          "500": {
            "description": "The status has not been updated"
          }
        }
      }
    },
    "/external/recurring-payments/{id}/cancel-at-period-end": {
      "post": {
        "summary": "SaaS subscription cancellation at the end of the paid period",
        "description": "Available only to a dedicated SaaS billing API client. For a RealPayment token-managed instruction, the scheduler stops at nextBillDate. A CardCom-managed instruction fails closed until provider cancellation is verified.",
        "tags": [
          "SaaS Billing"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SaasRecurringActionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Cancellation will be scheduled at the end of the period",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SaasRecurringActionResponse"
                }
              }
            }
          },
          "409": {
            "description": "No period end, subscription is inactive, or provider cancellation is not verified"
          }
        }
      }
    },
    "/external/recurring-payments/{id}/resume": {
      "post": {
        "summary": "Canceling a cancellation request before the end of the period",
        "description": "Available only to a dedicated SaaS billing API client before period-end cancellation takes effect. It does not reopen a cancelled or completed instruction or charge immediately. An ordinary API client uses PATCH status to resume a paused instruction.",
        "tags": [
          "SaaS Billing"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SaasRecurringActionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The cancellation request was removed before the end date; There is no separate event for resume",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SaasRecurringActionResponse"
                }
              }
            }
          },
          "409": {
            "description": "The appointment has already ended or the cancellation deadline has passed"
          }
        }
      }
    },
    "/external/recurring-payments/{id}/reconcile": {
      "post": {
        "summary": "Adjustment of SaaS subscription status without charge",
        "description": "A LowProfile payment checker waits against CardCom, or returns the appropriate status authority for the token route. The operation does not require a card.",
        "tags": [
          "SaaS Billing"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SaasRecurringActionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "return state with providerVerification; No charge was made",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SaasRecurringActionResponse"
                }
              }
            }
          }
        }
      }
    },
    "/external/document-provider": {
      "get": {
        "summary": "Read the business document-provider selection",
        "operationId": "getExternalDocumentProvider",
        "tags": [
          "Documents"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-required-scopes": [
          "documents.providers.read"
        ],
        "description": "Candidate 0.12.0. Requires X-API-Key and the explicit owner-granted documents.providers.read scope. The business owner is resolved from the key; a caller cannot choose another owner. Test-mode ordinary clients may read settings when scoped. Dedicated SaaS billing clients cannot use this route. Returns stored selection and safe CardCom readiness/capabilities without contacting a provider, issuing documents, or creating a binding.",
        "responses": {
          "200": {
            "description": "Current safe settings.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExternalDocumentProviderSettingsResponse"
                },
                "examples": {
                  "settings": {
                    "value": {
                      "success": true,
                      "settings": {
                        "activeProvider": "internal",
                        "configVersion": 3,
                        "readinessSource": "stored_evidence",
                        "cardcom": {
                          "configured": false,
                          "canSelect": false,
                          "readiness": "not_verified",
                          "blockers": [
                            "binding_missing"
                          ]
                        },
                        "capabilities": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentProviderApiError"
                }
              }
            }
          },
          "403": {
            "description": "DOCUMENT_PROVIDER_API_SCOPE_REQUIRED for missing documents.providers.read; DOCUMENT_PROVIDER_API_OWNER_MISMATCH for another owner; DOCUMENT_PROVIDER_SAAS_CLIENT_FORBIDDEN for a dedicated SaaS profile.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentProviderApiError"
                }
              }
            }
          },
          "409": {
            "description": "The stored provider selection or binding requires review.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentProviderApiError"
                }
              }
            }
          },
          "429": {
            "description": "External API rate limit reached."
          },
          "500": {
            "description": "Settings could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentProviderApiError"
                }
              }
            }
          }
        }
      }
    },
    "/external/document-provider/selection": {
      "put": {
        "summary": "Select the business document provider with safe retries",
        "operationId": "selectExternalDocumentProvider",
        "tags": [
          "Documents"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-required-scopes": [
          "documents.providers.write"
        ],
        "description": "Candidate 0.12.0. Requires X-API-Key, explicit owner-granted documents.providers.write, and X-Idempotency-Key. Read configVersion and send it as expectedVersion. Only internal and cardcom are supported. CardCom must pass its existing release/readiness gates. Test-mode clients cannot mutate selection; dedicated SaaS billing clients cannot use this route. Reuse the same key and payload after an uncertain transport result: a completed attempt returns its original selection and operationId with replayed=true, plus current settings, without another switch. Current settings may differ after a later owner change; replay does not reapply the old selection. A changed payload with the same key, a stale version, an unready provider, a changed binding, or open document operations returns 409. A new intentional change uses fresh settings and a new key. Selection governs future issuer capture; existing payments and documents keep their original issuer. This operation does not provision a provider account, issue a document, or charge money.",
        "parameters": [
          {
            "$ref": "#/components/parameters/DocumentProviderSelectionIdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExternalDocumentProviderSelectionRequest"
              },
              "examples": {
                "selection": {
                  "summary": "Choose internal with the current version",
                  "value": {
                    "provider": "internal",
                    "expectedVersion": 3
                  }
                },
                "selectCardcom": {
                  "summary": "Choose CardCom only when canSelect is true",
                  "value": {
                    "provider": "cardcom",
                    "expectedVersion": 3
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Selection completed or the original selection result was replayed. settings always reflects current configuration.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExternalDocumentProviderSelectionResponse"
                },
                "examples": {
                  "selectionResult": {
                    "value": {
                      "success": true,
                      "settings": {
                        "activeProvider": "internal",
                        "configVersion": 3,
                        "readinessSource": "stored_evidence",
                        "cardcom": {
                          "configured": false,
                          "canSelect": false,
                          "readiness": "not_verified",
                          "blockers": [
                            "binding_missing"
                          ]
                        },
                        "capabilities": {}
                      },
                      "operationId": "selection_example_operation",
                      "replayed": false,
                      "selection": {
                        "activeProvider": "internal",
                        "configVersion": 3
                      }
                    }
                  },
                  "replayedSelectionResult": {
                    "value": {
                      "success": true,
                      "settings": {
                        "activeProvider": "internal",
                        "configVersion": 3,
                        "readinessSource": "stored_evidence",
                        "cardcom": {
                          "configured": false,
                          "canSelect": false,
                          "readiness": "not_verified",
                          "blockers": [
                            "binding_missing"
                          ]
                        },
                        "capabilities": {}
                      },
                      "operationId": "selection_example_operation",
                      "replayed": true,
                      "selection": {
                        "activeProvider": "internal",
                        "configVersion": 3
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "DOCUMENT_PROVIDER_SELECTION_INVALID for provider/version/body validation; DOCUMENT_PROVIDER_SELECTION_IDEMPOTENCY_INVALID for an invalid key format.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentProviderApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentProviderApiError"
                }
              }
            }
          },
          "403": {
            "description": "DOCUMENT_PROVIDER_API_SCOPE_REQUIRED for missing documents.providers.write; DOCUMENT_PROVIDER_API_OWNER_MISMATCH for another owner; DOCUMENT_PROVIDER_SAAS_CLIENT_FORBIDDEN for a dedicated SaaS profile.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentProviderApiError"
                }
              }
            }
          },
          "409": {
            "description": "DOCUMENT_PROVIDER_TEST_MODE_WRITE_FORBIDDEN, DOCUMENT_PROVIDER_VERSION_CONFLICT, DOCUMENT_PROVIDER_SELECTION_IDEMPOTENCY_CONFLICT, DOCUMENT_PROVIDER_NOT_READY, or DOCUMENT_PROVIDER_SWITCH_BLOCKED; changed binding or invalid stored configuration can also conflict. Read the error and current settings before a new intentional operation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentProviderApiError"
                }
              }
            }
          },
          "428": {
            "description": "DOCUMENT_PROVIDER_SELECTION_IDEMPOTENCY_REQUIRED: X-Idempotency-Key is required.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentProviderApiError"
                }
              }
            }
          },
          "429": {
            "description": "External API rate limit reached."
          },
          "500": {
            "description": "Selection could not be completed. Keep the original key and payload for a retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentProviderApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/api-clients": {
      "post": {
        "summary": "Create an ordinary API client with optional provider permissions",
        "operationId": "createOwnerApiClient",
        "tags": [
          "Documents"
        ],
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ],
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "description": "Candidate 0.12.0 scope extension to the existing owner-only key form. Send documentProviderScopes explicitly to grant read and/or write for an ordinary client. Omitted or empty means neither provider permission is granted; legacy keys are not automatically granted permissions. The owner is the signed-in user. This does not create a dedicated SaaS profile. The new apiKey is revealed once to the owner in the creation response; subsequent client reads expose safe client fields and the key prefix.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OwnerApiClientCreateRequest"
              },
              "examples": {
                "createScopedClient": {
                  "value": {
                    "clientName": "Example CRM integration",
                    "documentProviderScopes": [
                      "documents.providers.read",
                      "documents.providers.write"
                    ]
                  }
                },
                "createClientWithoutProviderAccess": {
                  "value": {
                    "clientName": "Example ordinary integration"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "New API client and the owner-only one-time apiKey.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OwnerApiClientCreateResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid client fields or provider scopes."
          },
          "403": {
            "description": "Owner authentication/account/session checks failed or the requested provider permissions are forbidden."
          },
          "500": {
            "description": "Client could not be created."
          }
        }
      }
    },
    "/api/api-clients/{clientId}": {
      "put": {
        "summary": "Save an ordinary API client and its explicit provider permissions",
        "operationId": "updateOwnerApiClient",
        "tags": [
          "Documents"
        ],
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ],
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "description": "Candidate 0.12.0 scope extension to the existing owner-only key form. Send the current editable client fields. When documentProviderScopes is present, expectedProviderScopesVersion is required and is checked atomically with the client-field update. Only the two provider scopes are replaced; other scopes are retained. Omit documentProviderScopes to retain the provider subset, or send [] with the current version to revoke both. Dedicated SaaS clients are blocked. To change permissions alone, use the dedicated document-provider-scopes route. This update does not reveal a new API-key secret.",
        "parameters": [
          {
            "name": "clientId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OwnerApiClientUpdateRequest"
              },
              "examples": {
                "updateScopedClient": {
                  "summary": "Provider fields added when editing the newly created example client",
                  "value": {
                    "clientName": "Example CRM integration",
                    "documentProviderScopes": [
                      "documents.providers.read"
                    ],
                    "expectedProviderScopesVersion": 1
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated safe client, including allowedScopes and documentProviderScopesVersion.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentProviderScopesResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid client fields/scopes or missing expectedProviderScopesVersion when provider scopes were supplied."
          },
          "403": {
            "description": "Client is not owned by the caller, owner authentication/account/session checks failed, or the client has a dedicated SaaS profile."
          },
          "404": {
            "description": "Client was not found."
          },
          "409": {
            "description": "DOCUMENT_PROVIDER_SCOPES_VERSION_CONFLICT: provider-scope version changed; no client fields or scopes are saved."
          },
          "500": {
            "description": "Client could not be updated."
          }
        }
      }
    },
    "/api/api-clients/{clientId}/document-provider-scopes": {
      "put": {
        "summary": "Grant or revoke an owned client's document-provider scopes",
        "operationId": "replaceDocumentProviderScopes",
        "tags": [
          "Documents"
        ],
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ],
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "description": "Candidate 0.12.0. Internal management operation for the signed-in business owner using a Firebase Bearer token. Only an owned ordinary API client may be changed; dedicated SaaS billing clients are blocked. Replaces only documents.providers.read and documents.providers.write, preserving all other scopes. Send [] to revoke both. Send the current documentProviderScopesVersion as expectedVersion (0 before a version is recorded). A stale version returns 409. Scope changes do not change the provider, issue documents, or provision a provider account.",
        "parameters": [
          {
            "name": "clientId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 180,
              "pattern": "^[A-Za-z0-9_.:-]+$"
            },
            "description": "API client owned by the signed-in business owner."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DocumentProviderScopesRequest"
              },
              "examples": {
                "grantScopes": {
                  "value": {
                    "scopes": [
                      "documents.providers.read",
                      "documents.providers.write"
                    ],
                    "expectedVersion": 0
                  }
                },
                "revokeScopes": {
                  "value": {
                    "scopes": [],
                    "expectedVersion": 1
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated owner-visible client with documentProviderScopesVersion.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentProviderScopesResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid scopes or expectedVersion.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentProviderApiError"
                }
              }
            }
          },
          "403": {
            "description": "Owner authentication/account/session checks failed, the client is not owned by the caller, or the client has a dedicated SaaS billing profile.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentProviderApiError"
                }
              }
            }
          },
          "404": {
            "description": "Client was not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentProviderApiError"
                }
              }
            }
          },
          "409": {
            "description": "DOCUMENT_PROVIDER_SCOPES_VERSION_CONFLICT: the client scope version changed. Read the current client and retry the intended replacement with its current version.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentProviderApiError"
                }
              }
            }
          },
          "500": {
            "description": "Scopes could not be updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentProviderApiError"
                }
              }
            }
          }
        }
      }
    },
    "/external/business-profile": {
      "get": {
        "summary": "Business details and branding",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Read the business profile for the owner resolved from X-API-Key, including global logo and colors. These are business-wide settings.",
        "tags": [
          "Business Profile"
        ],
        "responses": {
          "200": {
            "description": "businessProfile object",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BusinessProfileResponse"
                }
              }
            }
          }
        }
      },
      "put": {
        "summary": "Updating business details and branding",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Update global business details and branding for the owner resolved from X-API-Key. logoUrl must be an HTTPS URL; null removes the logo. brandColor and secondaryColor must use six-digit HEX, such as #1e40af. Logo and colors apply to RealPayment's payment page. These settings are not per-link overrides and do not alter the CardCom iframe or provision a payment/document provider.",
        "tags": [
          "Business Profile"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "examples": {
                "branding": {
                  "value": {
                    "logoUrl": "https://example.com/business-logo.png",
                    "brandColor": "#1e40af",
                    "secondaryColor": "#3EC9D6"
                  }
                },
                "removeLogo": {
                  "value": {
                    "logoUrl": null
                  }
                }
              },
              "schema": {
                "$ref": "#/components/schemas/UpdateBusinessProfileRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "updated businessProfile",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BusinessProfileResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid logo URL or HEX color; no profile update is saved."
          }
        }
      }
    },
    "/external/create-invoice-receipt": {
      "post": {
        "summary": "Create a tax invoice/receipt",
        "tags": [
          "Documents"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateInvoiceReceiptRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "invoiceReceiptId, documentNumber, pdfUrl, totalAmount"
          },
          "400": {
            "description": "validation error"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/DocumentIdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/DocumentXIdempotencyKey"
          }
        ]
      }
    },
    "/external/digital-documents/recipient-consents": {
      "post": {
        "summary": "Registering or canceling a recipient's consent to a computerized document",
        "description": "Saves consent for the delivery of a computerized document via email or whatsapp. Required before sending a computerized document through a digital channel.",
        "tags": [
          "Digital Documents"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "channel"
                ],
                "properties": {
                  "action": {
                    "type": "string",
                    "enum": [
                      "grant",
                      "revoke"
                    ],
                    "default": "grant"
                  },
                  "channel": {
                    "type": "string",
                    "enum": [
                      "email",
                      "whatsapp"
                    ]
                  },
                  "email": {
                    "type": "string"
                  },
                  "phone": {
                    "type": "string"
                  },
                  "deliveryAddress": {
                    "type": "string"
                  },
                  "customerName": {
                    "type": "string"
                  },
                  "consentMethod": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "consent object"
          },
          "201": {
            "description": "consent object"
          },
          "400": {
            "description": "validation error"
          }
        }
      }
    },
    "/api/document-provider/connect": {
      "post": {
        "tags": [
          "Documents"
        ],
        "summary": "Verify and select the current CardCom document connection",
        "description": "Internal owner Firebase Bearer operation. The only caller input is the current configVersion as expectedVersion. When a private binding is missing, saved credentials and an existing authenticated, signed CardCom document for the same terminal can establish the issuer. Its legal issuer name and tax ID must match the canonical business legal identity; a display brand does not replace the legal name. Company scope, signature, document type, currency and payment method remain evidence-gated. Automatic-document suppression uses provider_contract evidence inferred from the optional LowProfile Document parameter and the application payload guard; historicalPaidJ4NoDocumentObserved is an observation only, not a readiness prerequisite. This does not prove a new live charge or subsequent document issuance. Name and tax-ID mismatches are rejected separately. Existing prepared bindings retain readiness checks. Owner, version, binding, credentials and open operations are rechecked before persistence and selection. Report access alone does not grant issuance readiness. Historical documents and payments keep their original issuer. This operation does not create a CardCom merchant account, issue documents, charge money or notify customers. After an uncertain response, read current settings before retrying. External document-provider selection does not invoke this owner-only bootstrap.",
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DocumentProviderConnectRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Current stored settings after verified preparation, connection checking and CardCom selection; only evidenced document capabilities are enabled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentProviderSettingsResponse"
                }
              }
            }
          },
          "400": {
            "description": "DOCUMENT_PROVIDER_SELECTION_INVALID: provider must be internal or cardcom, and expectedVersion must be a nonnegative safe integer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountingDocumentError"
                }
              }
            }
          },
          "403": {
            "description": "Missing or invalid owner Firebase Bearer token, unmet existing account/session/MFA authorization checks, or a forbidden provider binding. Authentication guards can return error and code; provider failures return errorCode and safeToEdit."
          },
          "409": {
            "description": "DOCUMENT_PROVIDER_VERSION_CONFLICT for a stale version; DOCUMENT_PROVIDER_NOT_READY for disabled or unready CardCom; DOCUMENT_PROVIDER_SWITCH_BLOCKED while the binding has open operations; DOCUMENT_PROVIDER_BINDING_CHANGED if the verified binding changed; DOCUMENT_PROVIDER_CONFIGURATION_INVALID for invalid stored configuration.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountingDocumentError"
                }
              }
            }
          },
          "500": {
            "description": "The settings or operation could not be read or updated. Inspect errorCode; this is not proof of a provider outcome.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountingDocumentError"
                }
              }
            }
          }
        }
      }
    },
    "/external/checkout-attempts/{attemptId}": {
      "get": {
        "tags": [
          "Payments"
        ],
        "operationId": "getSaasCheckoutAttempt",
        "summary": "Read one existing dedicated SaaS checkout attempt",
        "description": "Read-only lookup of the original create-payment attempt using the same UUID v4 and ownerCorrelationId. Requires the approved dedicated SaaS API key with saas.billing scope and zero commission. RealStore uses its immutable store-ID correlation contract. Reads the owned stored payment only: it never calls a provider, creates or renews a checkout, changes a payment, or charges a card. financialSuccess is always false; ready means an existing link is available, unknown requires safe reconciliation rather than a new attempt, and expired does not authorize a charge or automatic replacement.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "attemptId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
            },
            "description": "The UUID v4 used for the original create-payment attempt and billing consent."
          },
          {
            "name": "ownerCorrelationId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9_-]{1,128}$"
            },
            "description": "The unchanged owner correlation of the original attempt; wrong ownership returns 404."
          }
        ],
        "responses": {
          "200": {
            "description": "Existing checkout state only. ready does not mean paid or financially successful.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "lookupVersion",
                    "state",
                    "financialSuccess"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "lookupVersion": {
                      "type": "string",
                      "enum": [
                        "checkout-attempt-read-v1"
                      ]
                    },
                    "state": {
                      "type": "string",
                      "enum": [
                        "ready",
                        "unknown",
                        "expired"
                      ]
                    },
                    "financialSuccess": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "reason": {
                      "type": "string",
                      "enum": [
                        "record_incomplete",
                        "provider_outcome_unknown",
                        "checkout_not_ready"
                      ]
                    },
                    "contractVersion": {
                      "type": "string"
                    },
                    "attemptId": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "apiClientId": {
                      "type": "string"
                    },
                    "ownerCorrelationId": {
                      "type": "string"
                    },
                    "idempotencyKeyHash": {
                      "type": "string",
                      "pattern": "^[a-f0-9]{64}$"
                    },
                    "requestFingerprint": {
                      "type": "string",
                      "pattern": "^[a-f0-9]{64}$"
                    },
                    "paymentId": {
                      "type": "string"
                    },
                    "amountAgorot": {
                      "type": "integer",
                      "minimum": 1
                    },
                    "currency": {
                      "type": "string",
                      "enum": [
                        "ILS"
                      ]
                    },
                    "environment": {
                      "type": "string",
                      "enum": [
                        "live"
                      ]
                    },
                    "testMode": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "isRecurringPayment": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "paymentUrl": {
                      "type": "string",
                      "format": "uri",
                      "description": "The existing realpayment.co.il/payment.html URL; never a newly generated checkout."
                    },
                    "paymentUrlExpiresAt": {
                      "type": "string",
                      "format": "date-time",
                      "nullable": true
                    },
                    "metadata": {
                      "type": "object",
                      "required": [
                        "planId",
                        "planVersion",
                        "billingConsentId"
                      ],
                      "properties": {
                        "planId": {
                          "type": "string"
                        },
                        "planVersion": {
                          "type": "string"
                        },
                        "billingConsentId": {
                          "type": "string",
                          "format": "uuid"
                        }
                      }
                    }
                  },
                  "oneOf": [
                    {
                      "properties": {
                        "state": {
                          "enum": [
                            "ready"
                          ]
                        }
                      },
                      "required": [
                        "contractVersion",
                        "attemptId",
                        "apiClientId",
                        "ownerCorrelationId",
                        "idempotencyKeyHash",
                        "requestFingerprint",
                        "paymentId",
                        "amountAgorot",
                        "currency",
                        "environment",
                        "metadata",
                        "testMode",
                        "isRecurringPayment",
                        "paymentUrl",
                        "paymentUrlExpiresAt"
                      ]
                    },
                    {
                      "properties": {
                        "state": {
                          "enum": [
                            "unknown"
                          ]
                        }
                      },
                      "required": [
                        "reason"
                      ]
                    },
                    {
                      "properties": {
                        "state": {
                          "enum": [
                            "expired"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid attempt UUID or missing/invalid ownerCorrelationId.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "errorCode"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "errorCode": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid X-API-Key (authentication middleware)."
          },
          "403": {
            "description": "A dedicated approved SaaS client and saas.billing scope are required; test keys are rejected.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "errorCode"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "errorCode": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No checkout belongs to this API client, account and owner correlation.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "errorCode"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "errorCode": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "External API rate limit exceeded."
          },
          "503": {
            "description": "Lookup is unavailable or the stored client policy is not safe to use; no provider retry is performed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "errorCode"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "errorCode": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/external/billing-capabilities": {
      "get": {
        "tags": [
          "Billing Enrollments"
        ],
        "operationId": "getBillingCapabilities",
        "summary": "Read opt-in billing configuration",
        "description": "Read-only configuration and stable client identity; readiness does not prove provider/card acceptance.",
        "responses": {
          "200": {
            "description": "Current authoritative state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingCapabilities"
                }
              }
            }
          },
          "400": {
            "description": "Validation, policy, ownership, idempotency or service failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          },
          "403": {
            "description": "Validation, policy, ownership, idempotency or service failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          },
          "404": {
            "description": "Validation, policy, ownership, idempotency or service failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          },
          "409": {
            "description": "Immutable conflict, cancellation fence, expired terms or unknown/unsafe recovery.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          },
          "428": {
            "description": "Validation, policy, ownership, idempotency or service failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          },
          "503": {
            "description": "Validation, policy, ownership, idempotency or service failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          }
        }
      }
    },
    "/external/billing-enrollments": {
      "post": {
        "tags": [
          "Billing Enrollments"
        ],
        "operationId": "createBillingEnrollment",
        "summary": "Create or recover an immutable token-first enrollment",
        "description": "Public id is be_ + first40 hex characters of SHA256(JSON.stringify([agreementId,agreementVersion])). Namespace is isolated by API client. Same identity/payload replays the same token registration; changed terms require cancel/replacement. A lost create response is recovered with the same key or GET of deterministic id; never invent a new agreement to bypass unknown financial outcomes. Cancel can tombstone an id before create finishes. Stale provider pages only register a token; retired agreement fences prevent money.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BillingEnrollmentIdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BillingEnrollmentCreate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Current authoritative state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation, policy, ownership, idempotency or service failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          },
          "403": {
            "description": "Validation, policy, ownership, idempotency or service failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          },
          "404": {
            "description": "Validation, policy, ownership, idempotency or service failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          },
          "409": {
            "description": "Immutable conflict, cancellation fence, expired terms or unknown/unsafe recovery.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          },
          "428": {
            "description": "Validation, policy, ownership, idempotency or service failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          },
          "503": {
            "description": "Validation, policy, ownership, idempotency or service failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          }
        }
      }
    },
    "/external/billing-enrollments/{id}": {
      "get": {
        "tags": [
          "Billing Enrollments"
        ],
        "operationId": "getBillingEnrollment",
        "summary": "Reconcile and read one owned enrollment",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^be_[a-f0-9]{40}$"
            }
          }
        ],
        "description": "Reads/reconciles existing provider references only; never submits a new financial attempt. Verified pending token approval may activate already-consented background initial work. Existing dispatched payment outcomes can finalize. Unknown/absence/timeout is never a decline. Store revision and ignore out-of-order responses. GET and cancel remain available to an owned active ordinary client when enrollment opt-in is later disabled.",
        "responses": {
          "200": {
            "description": "Current authoritative state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation, policy, ownership, idempotency or service failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          },
          "403": {
            "description": "Validation, policy, ownership, idempotency or service failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          },
          "404": {
            "description": "Validation, policy, ownership, idempotency or service failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          },
          "409": {
            "description": "Immutable conflict, cancellation fence, expired terms or unknown/unsafe recovery.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          },
          "428": {
            "description": "Validation, policy, ownership, idempotency or service failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          },
          "503": {
            "description": "Validation, policy, ownership, idempotency or service failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          }
        }
      }
    },
    "/external/billing-enrollments/{id}/cancel": {
      "post": {
        "tags": [
          "Billing Enrollments"
        ],
        "operationId": "cancelBillingEnrollment",
        "summary": "Fence registration and future money before marking free",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^be_[a-f0-9]{40}$"
            }
          },
          {
            "$ref": "#/components/parameters/BillingEnrollmentIdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "externalAccountId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 128
                  },
                  "agreementId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 128
                  },
                  "agreementVersion": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "reason": {
                    "type": "string",
                    "maxLength": 500
                  }
                },
                "description": "Identity is required when id has not been created yet; include it on every request to safely tombstone an uncertain create. Reason defaults to administrator_request."
              }
            }
          }
        },
        "description": "Atomic cancellation precedes new provider dispatch. Before dispatch, cancelled is final even if an old token-only page remains open. If a financial call was already dispatched, pending_stop blocks replacement/free until its authoritative final outcome; reconciliation cannot reactivate a cancelled mandate. Same key and reason replay safely. No refund is implied.",
        "responses": {
          "200": {
            "description": "Current authoritative state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation, policy, ownership, idempotency or service failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          },
          "403": {
            "description": "Validation, policy, ownership, idempotency or service failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          },
          "404": {
            "description": "Validation, policy, ownership, idempotency or service failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          },
          "409": {
            "description": "Immutable conflict, cancellation fence, expired terms or unknown/unsafe recovery.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          },
          "428": {
            "description": "Validation, policy, ownership, idempotency or service failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          },
          "503": {
            "description": "Validation, policy, ownership, idempotency or service failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          }
        }
      }
    },
    "/external/billing-enrollments/{id}/retry": {
      "post": {
        "tags": [
          "Billing Enrollments"
        ],
        "operationId": "retryBillingEnrollment",
        "summary": "Authorize card registration for one known failed bill",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^be_[a-f0-9]{40}$"
            }
          },
          {
            "$ref": "#/components/parameters/BillingEnrollmentIdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "failedPaymentId"
                ],
                "properties": {
                  "failedPaymentId": {
                    "type": "string",
                    "maxLength": 128
                  }
                }
              }
            }
          }
        },
        "description": "Only a confirmed failed current bill/card version (or confirmed registration failure) is eligible. Creates a token-only link and returns pending_registration; no immediate debit in this request. After customer approval a new credential version may retry that one failed bill. Work is fixed to its bill/version so duplicate triggers or a scheduler win cannot charge the next period. Unknown outcomes, expired initial agreements and already-pending registration reject; use GET/cancel rather than blind retry. Same key returns the same recovery link.",
        "responses": {
          "200": {
            "description": "Current authoritative state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation, policy, ownership, idempotency or service failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          },
          "403": {
            "description": "Validation, policy, ownership, idempotency or service failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          },
          "404": {
            "description": "Validation, policy, ownership, idempotency or service failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          },
          "409": {
            "description": "Immutable conflict, cancellation fence, expired terms or unknown/unsafe recovery.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          },
          "428": {
            "description": "Validation, policy, ownership, idempotency or service failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          },
          "503": {
            "description": "Validation, policy, ownership, idempotency or service failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEnrollmentError"
                }
              }
            }
          }
        }
      }
    },
    "/api/cardcom-refund": {
      "post": {
        "tags": [
          "Payments"
        ],
        "summary": "Refund an owned completed CardCom payment once",
        "operationId": "internalCardcomRefund",
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "description": "Owner-only management route. One full or partial refund per completed payment is supported. The stored CardCom transaction IDs must match the supplied ID. The original captured document issuer and its correction capabilities are checked before reserving or sending money. Repeated refunds are unavailable even if the provider offers them. A reservation already sent, accepted, or of unknown outcome is never reopened by lease expiry. A confirmed provider refund does not generate a document by itself; accounting completion uses the original issuer. Never repeat the money request after a 202 response or REFUND_OUTCOME_UNKNOWN. No X-API-Key refund capability is granted.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "transactionId",
                  "cardcomTransactionId"
                ],
                "properties": {
                  "transactionId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 180,
                    "pattern": "^[A-Za-z0-9_.:-]+$",
                    "description": "Owned payments document ID."
                  },
                  "cardcomTransactionId": {
                    "oneOf": [
                      {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 9007199254740991
                      },
                      {
                        "type": "string",
                        "pattern": "^[0-9]+$"
                      }
                    ],
                    "description": "Positive safe integer provider ID. Every stored provider ID must match."
                  },
                  "partialSum": {
                    "oneOf": [
                      {
                        "type": "number",
                        "exclusiveMinimum": true,
                        "minimum": 0,
                        "multipleOf": 0.01
                      },
                      {
                        "type": "string",
                        "pattern": "^[0-9]+(?:\\.[0-9]{1,2})?$"
                      }
                    ],
                    "description": "Optional positive amount of at most two decimal places, no greater than the original payment. Omit for a full refund. Complete decimal strings are accepted for compatibility."
                  },
                  "allowMultipleRefunds": {
                    "type": "boolean",
                    "enum": [
                      false
                    ],
                    "deprecated": true,
                    "description": "Omit or send false. true and other values are rejected before money is sent."
                  },
                  "reason": {
                    "type": "string",
                    "description": "Optional refund reason."
                  }
                }
              },
              "example": {
                "transactionId": "example_payment",
                "cardcomTransactionId": 123456,
                "partialSum": 20.5,
                "reason": "Customer request"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Refund confirmed and local payment recorded. Inspect refundDocument and commissionRefund independently; either can still require attention without another money refund.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "message": {
                      "type": "string"
                    },
                    "refund": {
                      "type": "object",
                      "properties": {
                        "transactionId": {
                          "oneOf": [
                            {
                              "type": "integer",
                              "minimum": 1
                            },
                            {
                              "type": "string"
                            }
                          ]
                        },
                        "amount": {
                          "type": "number"
                        }
                      }
                    },
                    "refundDocument": {
                      "type": "object",
                      "properties": {
                        "state": {
                          "type": "string"
                        },
                        "errorCode": {
                          "type": "string"
                        },
                        "operationId": {
                          "type": "string"
                        },
                        "documentId": {
                          "type": "string"
                        },
                        "documentUrl": {
                          "type": "string"
                        }
                      }
                    },
                    "refundTransactionId": {
                      "oneOf": [
                        {
                          "type": "integer"
                        },
                        {
                          "type": "string"
                        }
                      ]
                    },
                    "refundAmount": {
                      "type": "number"
                    },
                    "cardcom": {
                      "type": "object",
                      "properties": {
                        "responseCode": {
                          "type": "integer",
                          "enum": [
                            0
                          ]
                        },
                        "description": {
                          "type": "string"
                        }
                      }
                    },
                    "commissionRefund": {
                      "type": "object",
                      "properties": {
                        "state": {
                          "type": "string"
                        },
                        "amount": {
                          "type": "number"
                        },
                        "requiresAttention": {
                          "type": "boolean"
                        }
                      }
                    }
                  },
                  "required": [
                    "success",
                    "refund",
                    "refundDocument"
                  ]
                }
              }
            }
          },
          "202": {
            "description": "CardCom confirmed the money refund; local persistence or accounting requires reconciliation. The money request must not be repeated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "refundCompleted": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "canRetry": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "reconciliationRequired": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "refund": {
                      "type": "object",
                      "properties": {
                        "transactionId": {
                          "oneOf": [
                            {
                              "type": "integer",
                              "minimum": 1
                            },
                            {
                              "type": "string"
                            }
                          ]
                        },
                        "amount": {
                          "type": "number"
                        }
                      }
                    },
                    "refundDocument": {
                      "type": "object",
                      "properties": {
                        "state": {
                          "type": "string"
                        },
                        "errorCode": {
                          "type": "string"
                        },
                        "operationId": {
                          "type": "string"
                        },
                        "documentId": {
                          "type": "string"
                        },
                        "documentUrl": {
                          "type": "string"
                        }
                      }
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "success",
                    "refundCompleted",
                    "canRetry",
                    "reconciliationRequired",
                    "refund"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid ID or amount, unsupported multiple-refund flag, unavailable payment or provider-declared decline. Only a verified decline returns REFUND_PROVIDER_DECLINED with canRetry=true; do not infer retry permission from this status alone.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string"
                    },
                    "errorCode": {
                      "type": "string"
                    },
                    "canRetry": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Firebase authentication is required."
          },
          "403": {
            "description": "Existing account or session policy refuses the request."
          },
          "404": {
            "description": "The authenticated owner record is unavailable."
          },
          "409": {
            "description": "Original issuer is unready, the reservation changed, or an in-progress/unknown prior refund needs review. No new financial attempt is permitted by this response.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string"
                    },
                    "errorCode": {
                      "type": "string"
                    },
                    "canRetry": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Internal failure before a verified result; canRetry=false. Read stored state before further action.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string"
                    },
                    "errorCode": {
                      "type": "string"
                    },
                    "canRetry": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Money was sent to the provider but no valid confirmation was received. Do not send another refund; reconcile the existing attempt.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "errorCode": {
                      "type": "string",
                      "enum": [
                        "REFUND_OUTCOME_UNKNOWN"
                      ]
                    },
                    "canRetry": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "success",
                    "errorCode",
                    "canRetry",
                    "error"
                  ]
                }
              }
            }
          }
        },
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ]
      }
    },
    "/api/payments/{id}/refund-document": {
      "post": {
        "tags": [
          "Documents"
        ],
        "summary": "Complete the original document for an already confirmed refund",
        "operationId": "internalCompleteRefundDocument",
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "description": "Requires an owned confirmed refund or owned stored refund event. This continues accounting for the original issuer and never sends another money refund. A receipt-only CardCom binding without correction evidence remains blocked; this route does not expand provider capabilities.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Owned payment ID."
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "refundEventId": {
                    "type": "string",
                    "description": "Optional owned refund event for this payment."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Original refund document is ready.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "refundCompleted": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "document": {
                      "type": "object",
                      "properties": {
                        "state": {
                          "type": "string"
                        },
                        "errorCode": {
                          "type": "string"
                        },
                        "operationId": {
                          "type": "string"
                        },
                        "documentId": {
                          "type": "string"
                        },
                        "documentUrl": {
                          "type": "string"
                        }
                      }
                    }
                  },
                  "required": [
                    "success",
                    "refundCompleted",
                    "document"
                  ]
                }
              }
            }
          },
          "202": {
            "description": "Money refund is already confirmed; document remains pending. Do not repeat money.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "refundCompleted": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "document": {
                      "type": "object",
                      "properties": {
                        "state": {
                          "type": "string"
                        },
                        "errorCode": {
                          "type": "string"
                        },
                        "operationId": {
                          "type": "string"
                        },
                        "documentId": {
                          "type": "string"
                        },
                        "documentUrl": {
                          "type": "string"
                        }
                      }
                    }
                  },
                  "required": [
                    "success",
                    "refundCompleted",
                    "document"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Owner Firebase authentication required."
          },
          "404": {
            "description": "Owned payment or refund event was not found."
          },
          "409": {
            "description": "No confirmed refund or original issuer cannot currently complete the document."
          },
          "500": {
            "description": "Document continuation failed; no money refund is sent."
          }
        },
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ]
      }
    },
    "/api/documents-v2/context": {
      "get": {
        "tags": [
          "Documents"
        ],
        "operationId": "internalDocumentWorkspaceContext",
        "summary": "Read owned document creation capabilities and optional source payment",
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "description": "Owner-only read. Resolves canonical business limits, selected issuer for new work or immutable original issuer for an owned payment. No provider transport, issuance or money movement. The safe source record contains no provider tokens or raw card replies. Quote uses the internal issuer even when CardCom is selected. Failed context must block new submission while preserving entered details. No X-API-Key capability is granted.",
        "parameters": [
          {
            "name": "paymentId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 160
            },
            "description": "Owned payment ID. Foreign or missing payment returns 404; an invalid identifier returns 400."
          }
        ],
        "responses": {
          "200": {
            "description": "Owner creation context; canIssue and ready are independent gates and do not prove actual provider acceptance.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "private, no-store"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "context": {
                      "$ref": "#/components/schemas/DocumentWorkspaceContext"
                    }
                  },
                  "required": [
                    "success",
                    "context"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields or conflicting identity. Edit only when safeToEdit=true.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          },
          "401": {
            "description": "Firebase owner authentication required."
          },
          "403": {
            "description": "Account/session policy or verified document capability refuses the request."
          },
          "404": {
            "description": "Owned source, customer or draft was not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          },
          "409": {
            "description": "Draft version, original issuer, existing issuance attempt or document state blocks the operation. Continue stored state; do not invent a new identity.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          },
          "500": {
            "description": "Operation did not complete locally. Keep the existing input and inspect stored state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          }
        },
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ]
      }
    },
    "/api/documents-v2/create": {
      "post": {
        "tags": [
          "Documents"
        ],
        "operationId": "internalCreateWorkspaceDocument",
        "summary": "Issue or continue an owned document with a stable submission identity",
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "description": "The four workspace types are receipt, quote, invoice and invoice_receipt, intersected with business/provider evidence. Invoice and invoice_receipt require detailed nonzero description/quantity/price items; receipt requires an amount. Canonical customer and owned source payment are revalidated; linked receipts preserve original amount, currency and issuer. Manual bank/check payments need their required dates and details. Draft issuance uses sourceDraftId and the current draftVersion together with the complete creation payload. The immutable attempt snapshot is stored by the server. Saving a draft allocates no official number. Keep the same requestId and unchanged payload after timeout, reload, unknown outcome or continuation failure; only safeToEdit=true permits a changed submission. An HTTP 200 and a document PDF do not prove notification delivery, money settlement or legal/provider certification. No external API-key creation permission is added. Authored amounts, quantity, unit price, VAT, discount and paid values must be complete finite numbers; send JSON numbers. Derived row products, sums, VAT totals and balances must also remain finite. Numeric errors return 400 DOCUMENT_NUMERIC_INPUT_INVALID with field and safeToEdit=true before customer, issuance-attempt, number or PDF writes. Explicit paid and vatRate cannot be negative. Negative receipt amounts for refunds retain the existing receipt rules. Allocation and buyer-identity assessment derive item amounts from quantity multiplied by price; supplied aggregate or row totals cannot lower that assessment. Explicit transactionTotal and cashAmount retain their existing transaction/partial-payment meaning. The configured allocation threshold and invoice-item requirements remain unchanged.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Optional equivalent request identity. If body requestId or X-Idempotency-Key is also supplied, every supplied identity must match."
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DocumentWorkspaceCreateRequest"
              },
              "examples": {
                "sourceReceipt": {
                  "summary": "Receipt for an owned completed card payment",
                  "value": {
                    "type": "receipt",
                    "customerName": "Example customer",
                    "paymentId": "example_payment",
                    "amount": 118,
                    "currency": "ILS",
                    "paymentMethod": "כרטיס אשראי",
                    "requestId": "doc_example_receipt_20261005",
                    "description": "Example paid service"
                  }
                },
                "bankReceipt": {
                  "summary": "Manual bank receipt only when issuer evidence permits it",
                  "value": {
                    "type": "receipt",
                    "customerName": "Example customer",
                    "amount": 118,
                    "currency": "ILS",
                    "paymentMethod": "העברה בנקאית",
                    "paymentDate": "2026-10-05T12:00:00.000Z",
                    "paymentReference": "EXAMPLE-12",
                    "bankNumber": "12",
                    "bankBranch": "345",
                    "accountNumber": "100200",
                    "requestId": "doc_example_bank_20261005"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Document created or existing continuation returned. Existing provider/internal response aliases remain supported.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "requestId": {
                      "type": "string"
                    },
                    "documentId": {
                      "type": "string"
                    },
                    "documentNumber": {
                      "oneOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "integer"
                        }
                      ]
                    },
                    "type": {
                      "type": "string"
                    },
                    "customerId": {
                      "type": "string",
                      "nullable": true
                    },
                    "pdfUrl": {
                      "type": "string",
                      "nullable": true
                    },
                    "documentUrl": {
                      "type": "string",
                      "nullable": true
                    },
                    "replayed": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "success",
                    "documentId"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields or conflicting identity. Edit only when safeToEdit=true. Numeric validation returns DOCUMENT_NUMERIC_INPUT_INVALID and field before customer, attempt, number or PDF writes; derived-total overflow uses field=totalAmount.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                },
                "examples": {
                  "invalidAmount": {
                    "summary": "A complete numeric value is required",
                    "value": {
                      "success": false,
                      "safeToEdit": true,
                      "status": 400,
                      "errorCode": "DOCUMENT_NUMERIC_INPUT_INVALID",
                      "field": "amount",
                      "error": "סכומי המסמך חייבים להיות מספרים מלאים ותקינים. יש לבדוק את הסכומים והפריטים."
                    }
                  },
                  "derivedTotalOverflow": {
                    "summary": "Finite authored values produced a nonfinite total",
                    "value": {
                      "success": false,
                      "safeToEdit": true,
                      "status": 400,
                      "errorCode": "DOCUMENT_NUMERIC_INPUT_INVALID",
                      "field": "totalAmount",
                      "error": "סכומי המסמך חייבים להיות מספרים מלאים ותקינים. יש לבדוק את הסכומים והפריטים."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Firebase owner authentication required."
          },
          "403": {
            "description": "Account/session policy or verified document capability refuses the request."
          },
          "404": {
            "description": "Owned source, customer or draft was not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          },
          "409": {
            "description": "Draft version, original issuer, existing issuance attempt or document state blocks the operation. Continue stored state; do not invent a new identity.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          },
          "429": {
            "description": "Existing document creation limiter refused this request."
          },
          "500": {
            "description": "Operation did not complete locally. Keep the existing input and inspect stored state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          },
          "503": {
            "description": "Provider result unresolved. Preserve the existing identity and payload; reconcile or continue that attempt.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          }
        },
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ]
      }
    },
    "/api/documents-v2/drafts": {
      "post": {
        "tags": [
          "Documents"
        ],
        "operationId": "internalCreateDocumentDraft",
        "summary": "Save an owned draft without issuing a document",
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "description": "Retains bounded top-level bank/check/date/reference/cash details. No provider call, money movement or official document number. Customer identity is owner-scoped.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DocumentWorkspaceDraftRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Draft saved at version 1.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "documentId": {
                      "type": "string"
                    },
                    "draft": {
                      "$ref": "#/components/schemas/DocumentWorkspaceDraft"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "success",
                    "documentId",
                    "draft"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields or conflicting identity. Edit only when safeToEdit=true.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          },
          "401": {
            "description": "Firebase owner authentication required."
          },
          "403": {
            "description": "Account/session policy or verified document capability refuses the request."
          },
          "404": {
            "description": "Owned source, customer or draft was not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          },
          "409": {
            "description": "Draft version, original issuer, existing issuance attempt or document state blocks the operation. Continue stored state; do not invent a new identity.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          },
          "500": {
            "description": "Operation did not complete locally. Keep the existing input and inspect stored state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          }
        },
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ]
      }
    },
    "/api/documents-v2/drafts/{id}": {
      "get": {
        "tags": [
          "Documents"
        ],
        "operationId": "internalReadDocumentDraft",
        "summary": "Load owned draft details and continuation state",
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 160
            },
            "description": "Owned draft document ID."
          }
        ],
        "responses": {
          "200": {
            "description": "Editable or archived draft. readOnly/canResume describe existing issuance state.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "draft": {
                      "$ref": "#/components/schemas/DocumentWorkspaceDraft"
                    },
                    "readOnly": {
                      "type": "boolean"
                    },
                    "canResume": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "success",
                    "draft",
                    "readOnly",
                    "canResume"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields or conflicting identity. Edit only when safeToEdit=true.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          },
          "401": {
            "description": "Firebase owner authentication required."
          },
          "403": {
            "description": "Account/session policy or verified document capability refuses the request."
          },
          "404": {
            "description": "Owned source, customer or draft was not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          },
          "409": {
            "description": "Draft version, original issuer, existing issuance attempt or document state blocks the operation. Continue stored state; do not invent a new identity.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          },
          "500": {
            "description": "Operation did not complete locally. Keep the existing input and inspect stored state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          }
        },
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ]
      },
      "put": {
        "tags": [
          "Documents"
        ],
        "operationId": "internalUpdateDocumentDraft",
        "summary": "Replace editable owned draft using its current version",
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 160
            },
            "description": "Owned draft document ID."
          }
        ],
        "description": "Send the complete draft details and current draftVersion. The transaction increments the version; stale or issuance-started drafts fail before overwriting.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DocumentWorkspaceDraftRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated draft with incremented version.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "documentId": {
                      "type": "string"
                    },
                    "draft": {
                      "$ref": "#/components/schemas/DocumentWorkspaceDraft"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "success",
                    "documentId",
                    "draft"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields or conflicting identity. Edit only when safeToEdit=true.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          },
          "401": {
            "description": "Firebase owner authentication required."
          },
          "403": {
            "description": "Account/session policy or verified document capability refuses the request."
          },
          "404": {
            "description": "Owned source, customer or draft was not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          },
          "409": {
            "description": "Draft version, original issuer, existing issuance attempt or document state blocks the operation. Continue stored state; do not invent a new identity.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          },
          "500": {
            "description": "Operation did not complete locally. Keep the existing input and inspect stored state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          }
        },
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ]
      },
      "delete": {
        "tags": [
          "Documents"
        ],
        "operationId": "internalArchiveDocumentDraft",
        "summary": "Archive an editable owned draft",
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 160
            },
            "description": "Owned draft document ID."
          }
        ],
        "description": "Logical archive only; already archived replays remain safe. Issuance-started or final documents cannot be archived through this route.",
        "responses": {
          "200": {
            "description": "Draft archived.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "documentId": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "success",
                    "documentId"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields or conflicting identity. Edit only when safeToEdit=true.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          },
          "401": {
            "description": "Firebase owner authentication required."
          },
          "403": {
            "description": "Account/session policy or verified document capability refuses the request."
          },
          "404": {
            "description": "Owned source, customer or draft was not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          },
          "409": {
            "description": "Draft version, original issuer, existing issuance attempt or document state blocks the operation. Continue stored state; do not invent a new identity.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          },
          "500": {
            "description": "Operation did not complete locally. Keep the existing input and inspect stored state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          }
        },
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ]
      }
    },
    "/api/documents-v2/drafts/{id}/restore": {
      "post": {
        "tags": [
          "Documents"
        ],
        "operationId": "internalRestoreDocumentDraft",
        "summary": "Restore an owned archived draft before issuance started",
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 160
            },
            "description": "Owned draft document ID."
          }
        ],
        "responses": {
          "200": {
            "description": "Restored draft with incremented version.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "documentId": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "success",
                    "documentId"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields or conflicting identity. Edit only when safeToEdit=true.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          },
          "401": {
            "description": "Firebase owner authentication required."
          },
          "403": {
            "description": "Account/session policy or verified document capability refuses the request."
          },
          "404": {
            "description": "Owned source, customer or draft was not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          },
          "409": {
            "description": "Draft version, original issuer, existing issuance attempt or document state blocks the operation. Continue stored state; do not invent a new identity.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          },
          "500": {
            "description": "Operation did not complete locally. Keep the existing input and inspect stored state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentWorkspaceFailure"
                }
              }
            }
          }
        },
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ]
      }
    },
    "/api/api-clients/{clientId}/webhook-signing": {
      "put": {
        "summary": "Internal: explicitly enable V2 webhook signing for an owned ordinary API client",
        "description": "Owner-only management operation. Use the site origin and a Firebase Bearer token; X-API-Key does not authorize it. Requires a freshly active owner, owned active ordinary client, installed owner/client-specific key material and matching metadata version. SaaS and server-managed clients are excluded. It saves only safe signing metadata and an audit entry. No secret is accepted or returned. Read the saved client metadata before retrying a configuration save after response loss. No existing client is migrated automatically.",
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ],
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "x-internal-management": true,
        "parameters": [
          {
            "name": "clientId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 180,
              "pattern": "^[A-Za-z0-9._:-]{1,180}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExternalWebhookSigningRequest"
              },
              "example": {
                "keyId": "client-key-v1",
                "expectedVersion": 0,
                "consumerReady": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Safe saved metadata; not a live delivery proof",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExternalWebhookSigningResponse"
                }
              }
            }
          },
          "400": {
            "description": "Malformed fields, inline secret or missing explicit confirmation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExternalWebhookManagementError"
                }
              }
            }
          },
          "401": {
            "description": "Firebase authentication required"
          },
          "403": {
            "description": "Owner inactive or client belongs to another owner",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExternalWebhookManagementError"
                }
              }
            }
          },
          "404": {
            "description": "API client not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExternalWebhookManagementError"
                }
              }
            }
          },
          "409": {
            "description": "Client inactive/excluded, invalid saved signing configuration or stale expectedVersion",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExternalWebhookManagementError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected management failure",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExternalWebhookManagementError"
                }
              }
            }
          },
          "503": {
            "description": "EXTERNAL_WEBHOOK_SIGNING_SECRET_UNAVAILABLE: dedicated key material is unavailable to the API runtime; no activation is saved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExternalWebhookManagementError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/retry-webhook": {
      "post": {
        "summary": "Internal admin: retry the original failed webhook delivery",
        "description": "Firebase-authenticated administrators only. For type external_payment_completed with a verified schema-2 envelope, reuses the original raw body, destination, signing references and event/idempotency IDs. A retry may carry a fresh attempt timestamp and matching signature. Concurrent attempts are serialized. It performs no charge, document creation, financial reconciliation or payment write. Historical external rows with only payloadSummary are refused with 409 EXTERNAL_WEBHOOK_ORIGINAL_BODY_UNAVAILABLE, without sending. Other legacy webhook types keep their existing branch; this contract does not repair legacy owner-webhook subscriptions.",
        "servers": [
          {
            "url": "https://realpayment.co.il"
          }
        ],
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "x-internal-management": true,
        "x-required-role": "admin",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "webhookId"
                ],
                "properties": {
                  "webhookId": {
                    "type": "string",
                    "minLength": 1
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Inspect success, status and errorCode: transport failure can return HTTP 200 with success=false. success=true means endpoint acceptance or replay, not downstream business completion."
          },
          "202": {
            "description": "Another delivery attempt is in progress; success=false and status=in_progress. No concurrent send."
          },
          "400": {
            "description": "Missing webhookId or destination on a legacy branch"
          },
          "401": {
            "description": "Authentication required"
          },
          "403": {
            "description": "Administrator role required"
          },
          "404": {
            "description": "Failed webhook not found"
          },
          "409": {
            "description": "Original envelope unavailable/invalid or owner changed; no replacement event is fabricated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExternalWebhookManagementError"
                }
              }
            }
          },
          "500": {
            "description": "Retry could not be completed"
          }
        }
      }
    },
    "/api/documents/{id}/access-link": {
      "post": {
        "summary": "Open the current original or separate signature acknowledgment",
        "tags": [
          "Documents"
        ],
        "security": [
          {
            "firebaseAuth": []
          }
        ],
        "description": "Internal owner-only endpoint. Default artifactKind=document preserves the original. signature_acknowledgment requires a signed-ready CardCom quote plus valid current original/ACK metadata and bytes. Links use /d/{token}, expire after 30 days and fail closed on cancellation, owner closure or changed source. No document issuance, signature capture, charge or notification occurs.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "channel": {
                    "type": "string",
                    "enum": [
                      "view",
                      "download"
                    ],
                    "default": "view"
                  },
                  "artifactKind": {
                    "type": "string",
                    "enum": [
                      "document",
                      "signature_acknowledgment"
                    ],
                    "default": "document"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A current RealPayment short bearer URL for the explicitly selected artifact."
          },
          "400": {
            "description": "Unsupported channel or artifactKind."
          },
          "403": {
            "description": "No owner access or inactive owner."
          },
          "409": {
            "description": "Signature/current PDF proof is not ready."
          },
          "410": {
            "description": "Document cancelled."
          },
          "503": {
            "description": "Access link is temporarily unavailable; retain the existing document and try opening again."
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "Payments",
      "description": "Payments and payment links"
    },
    {
      "name": "Documents",
      "description": "Invoices, quotes, receipts"
    },
    {
      "name": "Customers",
      "description": "Customer management"
    },
    {
      "name": "Signatures",
      "description": "Digital signatures"
    },
    {
      "name": "Sales Process",
      "description": "Automated sales processes"
    },
    {
      "name": "Analytics",
      "description": "Analytics"
    },
    {
      "name": "Webhooks",
      "description": "Status updates"
    },
    {
      "name": "Recurring Payments",
      "description": "Management of standing orders created through the system"
    },
    {
      "name": "SaaS Billing",
      "description": "Dedicated SaaS billing contracts for RealMarketing, RealStore, and other authorized products: isolated API keys, server-approved plans, idempotency, recovery, and signed events."
    },
    {
      "name": "Business Profile",
      "description": "Business details and branding for documents and payments"
    },
    {
      "name": "Digital Documents",
      "description": "Agreements and readiness for computerized documents"
    },
    {
      "name": "Billing Enrollments",
      "description": "Explicitly enabled ordinary clients only; token-first consent with provider-owned cancellation and dispatch fences."
    }
  ],
  "x-ordinary-external-webhook-contract": {
    "mode": "dual_v2",
    "events": [
      "payment.completed",
      "payment.test"
    ],
    "headers": [
      "X-RealPayment-Event",
      "X-RealPayment-Event-Id",
      "X-Idempotency-Key",
      "X-RealPayment-Signature-Version",
      "X-RealPayment-Key-Id",
      "X-RealPayment-Timestamp",
      "X-RealPayment-Signature-V2"
    ],
    "signingInput": "{attemptTimestamp}.{originalEventId}.{rawJsonBody}",
    "algorithm": "HMAC-SHA256",
    "signatureFormat": "sha256=<lowercase hexadecimal digest>",
    "timestampUnit": "Unix seconds",
    "replayWindowSeconds": 300,
    "rawBody": "Verify the exact received UTF-8 JSON body before parsing. Never reconstruct or reserialize it for verification.",
    "receiver": "Resolve Key-Id from this client's private installed keys. Verify V2, the five-minute timestamp window and matching Event-Id/Idempotency-Key. Atomically deduplicate by installed apiClientId plus eventId and body SHA256 together with the business effect. A repeated matching event returns its saved acknowledgment; a changed body under that identity is rejected.",
    "legacy": "X-RealPayment-Signature remains sha256=HMAC_SHA256(apiClientId, rawBody). The API client ID is public: this legacy value is weak and is not a dedicated-secret authenticity proof or a substitute for V2.",
    "migration": "No automatic migration. Provision a dedicated owner/client-bound key in the API runtime and receiver backend, verify the receiver, then the active owner explicitly enables dual_v2 through the internal signing route. Existing SaaS and server-managed contracts are excluded. Missing V2 secret material never falls back to legacy-only delivery.",
    "retry": "Completed-payment delivery records the immutable original envelope before HTTP. An authorized admin retries the same destination, raw body and event/idempotency IDs; only the delivery-attempt timestamp/signature changes. The retry does not charge, create a document, reconcile a payment or write the payment. Historical rows without the verifiable original envelope return 409 EXTERNAL_WEBHOOK_ORIGINAL_BODY_UNAVAILABLE without sending.",
    "acceptance": "HTTP 2xx proves endpoint acceptance only, not downstream business completion.",
    "scope": "Ordinary external payment.completed and payment.test. Legacy owner subscriptions sending transaction.created/updated and dedicated SaaS webhook contracts remain separate."
  }
}
