{
  "openapi": "3.1.0",
  "info": {
    "title": "ePayDo API",
    "version": "1.0.0",
    "summary": "Crypto payment gateway — TRX and USDT on the TRON network",
    "description": "ePayDo exposes a REST API for accepting crypto payments on the TRON blockchain (TRX native and USDT TRC-20). Authentication is per-request HMAC-SHA256.\n\nFor LLM-optimized single-file docs see https://epaydo.com/llms-full.txt.",
    "termsOfService": "https://epaydo.com/terms",
    "contact": {
      "name": "ePayDo Support",
      "email": "support@epaydo.com",
      "url": "https://epaydo.com/contact"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://epaydo.com/terms"
    }
  },
  "servers": [
    { "url": "https://epaydo.com/api/v1", "description": "Production (live or test mode, decided by key prefix)" }
  ],
  "security": [
    { "ApiKeyAuth": [], "TimestampAuth": [], "SignatureAuth": [] }
  ],
  "tags": [
    { "name": "Payments", "description": "Create and query crypto payments" },
    { "name": "Refunds", "description": "Issue and query refunds" },
    { "name": "Payouts", "description": "Withdraw merchant balance to external TRON addresses" },
    { "name": "Balance", "description": "Merchant balance snapshot" }
  ],
  "paths": {
    "/payments": {
      "post": {
        "tags": ["Payments"],
        "summary": "Create a payment",
        "description": "Creates a new payment attempt. Returns the hosted checkout URL. Idempotent on `order_id` within 24 h.",
        "operationId": "createPayment",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreatePaymentRequest" },
              "examples": {
                "usdt": {
                  "summary": "USDT payment",
                  "value": { "amount": "10.00", "currency": "USDT", "order_id": "ord_abc", "customer_email": "c@example.com" }
                },
                "trx": {
                  "summary": "TRX payment",
                  "value": { "amount": "100.00", "currency": "TRX", "order_id": "ord_xyz", "metadata": { "cart_id": "c_42" } }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Payment created",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaymentCreatedResponse" }
              }
            }
          },
          "200": {
            "description": "Idempotent replay — same `order_id` returned unchanged",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaymentCreatedResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/AuthError" },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      },
      "get": {
        "tags": ["Payments"],
        "summary": "List payments",
        "operationId": "listPayments",
        "parameters": [
          { "name": "status", "in": "query", "schema": { "$ref": "#/components/schemas/PaymentStatus" } },
          { "name": "from_date", "in": "query", "schema": { "type": "string", "format": "date" } },
          { "name": "to_date", "in": "query", "schema": { "type": "string", "format": "date" } },
          { "name": "is_test", "in": "query", "schema": { "type": "boolean", "default": false } },
          { "name": "per_page", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 15 } },
          { "name": "page", "in": "query", "schema": { "type": "integer", "minimum": 1, "default": 1 } }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/Payment" } },
                    "meta": { "$ref": "#/components/schemas/PaginationMeta" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/AuthError" }
        }
      }
    },
    "/payments/{id}": {
      "get": {
        "tags": ["Payments"],
        "summary": "Retrieve a payment",
        "operationId": "getPayment",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Payment" } } }
          },
          "404": { "$ref": "#/components/responses/NotFound" },
          "401": { "$ref": "#/components/responses/AuthError" }
        }
      }
    },
    "/refunds": {
      "post": {
        "tags": ["Refunds"],
        "summary": "Create a refund",
        "operationId": "createRefund",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["payment_id"],
                "properties": {
                  "payment_id": { "type": "integer" },
                  "amount": { "type": "string", "pattern": "^\\d+(\\.\\d{1,8})?$", "description": "Omit for full refund" },
                  "reason": { "type": "string", "maxLength": 500 }
                }
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Refund queued for review", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Refund" } } } },
          "409": { "description": "Another refund already in flight for this payment" },
          "422": { "$ref": "#/components/responses/ValidationError" }
        }
      },
      "get": {
        "tags": ["Refunds"],
        "summary": "List refunds",
        "operationId": "listRefunds",
        "parameters": [
          { "name": "payment_id", "in": "query", "schema": { "type": "integer" } },
          { "name": "per_page", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 15 } }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/Refund" } },
                    "meta": { "$ref": "#/components/schemas/PaginationMeta" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/refunds/{id}": {
      "get": {
        "tags": ["Refunds"],
        "summary": "Retrieve a refund",
        "operationId": "getRefund",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Refund" } } } },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/payouts": {
      "post": {
        "tags": ["Payouts"],
        "summary": "Create a payout",
        "operationId": "createPayout",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreatePayoutRequest" }
            }
          }
        },
        "responses": {
          "201": { "description": "Payout queued", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Payout" } } } },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "description": "Payout rate limit (10/min) exceeded" }
        }
      },
      "get": {
        "tags": ["Payouts"],
        "summary": "List payouts",
        "operationId": "listPayouts",
        "parameters": [
          { "name": "status", "in": "query", "schema": { "$ref": "#/components/schemas/PayoutStatus" } },
          { "name": "per_page", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 15 } }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/Payout" } },
                    "meta": { "$ref": "#/components/schemas/PaginationMeta" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/payouts/{id}": {
      "get": {
        "tags": ["Payouts"],
        "summary": "Retrieve a payout",
        "operationId": "getPayout",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Payout" } } } },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/balance": {
      "get": {
        "tags": ["Balance"],
        "summary": "Get merchant balance",
        "operationId": "getBalance",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "balances": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": ["currency", "available", "pending"],
                        "properties": {
                          "currency": { "type": "string" },
                          "available": { "type": "string" },
                          "pending": { "type": "string" }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": { "type": "apiKey", "in": "header", "name": "X-API-Key" },
      "TimestampAuth": { "type": "apiKey", "in": "header", "name": "X-Timestamp" },
      "SignatureAuth": { "type": "apiKey", "in": "header", "name": "X-Signature", "description": "hex(hmac_sha256(secret, timestamp + METHOD + /path + body))" }
    },
    "schemas": {
      "PaymentStatus": {
        "type": "string",
        "enum": ["pending", "confirming", "completed", "paid_late", "partial", "review", "expired", "cancelled", "failed", "refunded"]
      },
      "PayoutStatus": {
        "type": "string",
        "enum": ["pending", "processing", "confirming", "completed", "failed", "cancelled"]
      },
      "Payment": {
        "type": "object",
        "required": ["id", "public_token", "amount", "currency", "status", "is_test", "created_at", "expiry_at"],
        "properties": {
          "id": { "type": "integer" },
          "order_id": { "type": ["string", "null"] },
          "public_token": { "type": "string" },
          "amount": { "type": "string" },
          "currency": { "type": "string" },
          "original_amount": { "type": ["string", "null"] },
          "original_currency": { "type": ["string", "null"] },
          "status": { "$ref": "#/components/schemas/PaymentStatus" },
          "payment_method": { "type": ["string", "null"], "enum": ["crypto", null] },
          "deposit_address": { "type": ["string", "null"], "description": "TRON Base58 address" },
          "received_amount": { "type": ["string", "null"], "description": "Actual on-chain received amount" },
          "tx_hash": { "type": ["string", "null"], "description": "Blockchain transaction hash" },
          "customer_email": { "type": ["string", "null"], "format": "email" },
          "customer_name": { "type": ["string", "null"] },
          "metadata": { "type": ["object", "null"], "additionalProperties": true },
          "is_test": { "type": "boolean" },
          "created_at": { "type": "string", "format": "date-time" },
          "expiry_at": { "type": "string", "format": "date-time" },
          "paid_at": { "type": ["string", "null"], "format": "date-time" },
          "success_url": { "type": ["string", "null"], "format": "uri" },
          "cancel_url": { "type": ["string", "null"], "format": "uri" },
          "return_url": { "type": ["string", "null"], "format": "uri" }
        }
      },
      "PaymentCreatedResponse": {
        "allOf": [
          { "$ref": "#/components/schemas/Payment" },
          {
            "type": "object",
            "required": ["checkout_url"],
            "properties": {
              "checkout_url": { "type": "string", "format": "uri", "description": "Hosted checkout URL to redirect the customer to" }
            }
          }
        ]
      },
      "CreatePaymentRequest": {
        "type": "object",
        "required": ["amount", "currency"],
        "properties": {
          "amount": { "type": "string", "pattern": "^\\d+(\\.\\d{1,8})?$", "description": "0.000001 to 9999999.99" },
          "currency": { "type": "string", "description": "USDT, TRX, USD, EUR, GBP, TRY (subject to project config; fiat currencies auto-convert to USDT at checkout)" },
          "order_id": { "type": "string", "maxLength": 100, "pattern": "^[A-Za-z0-9_\\-.:#]+$" },
          "customer_email": { "type": "string", "format": "email" },
          "customer_name": { "type": "string", "maxLength": 200 },
          "success_url": { "type": "string", "format": "uri" },
          "cancel_url": { "type": "string", "format": "uri" },
          "return_url": { "type": "string", "format": "uri" },
          "metadata": { "type": "object", "additionalProperties": true, "description": "Max 4 KB JSON" },
          "expiry_minutes": { "type": "integer", "minimum": 5, "maximum": 10080 }
        }
      },
      "Refund": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "payment_id": { "type": "integer" },
          "amount": { "type": "string" },
          "currency": { "type": "string" },
          "status": { "type": "string", "enum": ["pending", "approved", "rejected", "processing", "completed", "failed"] },
          "reason": { "type": ["string", "null"] },
          "tx_hash": { "type": ["string", "null"] },
          "created_at": { "type": "string", "format": "date-time" },
          "completed_at": { "type": ["string", "null"], "format": "date-time" }
        }
      },
      "Payout": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "amount": { "type": "string" },
          "currency": { "type": "string" },
          "to_address": { "type": ["string", "null"], "description": "TRON Base58 address" },
          "status": { "$ref": "#/components/schemas/PayoutStatus" },
          "tx_hash": { "type": ["string", "null"] },
          "notes": { "type": ["string", "null"] },
          "created_at": { "type": "string", "format": "date-time" },
          "processed_at": { "type": ["string", "null"], "format": "date-time" }
        }
      },
      "CreatePayoutRequest": {
        "type": "object",
        "required": ["amount", "currency", "to_address"],
        "properties": {
          "amount": { "type": "string", "pattern": "^\\d+(\\.\\d{1,8})?$" },
          "currency": { "type": "string" },
          "to_address": { "type": "string", "description": "Destination TRON Base58 address" },
          "notes": { "type": "string", "maxLength": 500 }
        }
      },
      "PaginationMeta": {
        "type": "object",
        "properties": {
          "current_page": { "type": "integer" },
          "last_page": { "type": "integer" },
          "per_page": { "type": "integer" },
          "total": { "type": "integer" }
        }
      },
      "Error": {
        "type": "object",
        "required": ["message"],
        "properties": {
          "message": { "type": "string" },
          "error_code": { "type": "string" },
          "details": { "type": "object", "additionalProperties": true }
        }
      }
    },
    "responses": {
      "AuthError": {
        "description": "Authentication failed (missing / invalid HMAC, timestamp skew, or replay)",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "ValidationError": {
        "description": "Request payload failed validation",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "NotFound": {
        "description": "Resource not found",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "RateLimited": {
        "description": "Rate limit exceeded",
        "headers": { "Retry-After": { "schema": { "type": "integer" }, "description": "Seconds until the limit resets" } },
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      }
    }
  }
}
