{
  "openapi": "3.0.3",
  "info": {
    "title": "DeboPay Public API",
    "version": "1.0.0",
    "description": "DeboPay merchant REST API \u2014 payments, refunds, payouts, settlements, subscriptions, Debo Fund campaigns, and webhooks.\n## Idempotency All money-moving POST endpoints require an Idempotency-Key (header) or idempotency_key (JSON body). Keys must match `^[A-Za-z0-9_-]{16,128}$`. Safe retries with the same key and payload return the original response without creating another payment. Different payloads with the same key return 409 idempotency_conflict. Keys expire after 24 hours.\n",
    "contact": {
      "name": "DeboPay Developers",
      "url": "https://debopay.com/developers"
    }
  },
  "servers": [
    {
      "url": "https://api.debopay.com/v1",
      "description": "Production"
    },
    {
      "url": "https://debopay.com/v1",
      "description": "Sandbox (same app, sandbox keys)"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Payments"
    },
    {
      "name": "Refunds"
    },
    {
      "name": "Payouts"
    },
    {
      "name": "Subscriptions"
    },
    {
      "name": "Fund"
    },
    {
      "name": "Webhooks"
    }
  ],
  "paths": {
    "/payments/initialize": {
      "post": {
        "tags": [
          "Payments"
        ],
        "summary": "Initialize a payment",
        "description": "Creates a checkout session. Requires Idempotency-Key. Retries with the same key and canonical payload replay the original 201 response.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "amount",
                  "currency",
                  "reference"
                ],
                "properties": {
                  "amount": {
                    "type": "number",
                    "example": 250.0
                  },
                  "currency": {
                    "type": "string",
                    "example": "ETB"
                  },
                  "reference": {
                    "type": "string",
                    "example": "order_1001"
                  },
                  "email": {
                    "type": "string",
                    "example": "customer@example.com"
                  },
                  "callback_url": {
                    "type": "string"
                  },
                  "idempotency_key": {
                    "type": "string",
                    "minLength": 16,
                    "maxLength": 128,
                    "pattern": "^[A-Za-z0-9_-]{16,128}$",
                    "description": "Alternative to Idempotency-Key header (must match if both sent)",
                    "example": "pay_ord1001_20260729a1b2"
                  }
                }
              },
              "examples": {
                "withHeader": {
                  "summary": "Key in header only",
                  "value": {
                    "amount": 250,
                    "currency": "ETB",
                    "reference": "order_1001"
                  }
                },
                "withBody": {
                  "summary": "Key in JSON body",
                  "value": {
                    "amount": 250,
                    "currency": "ETB",
                    "reference": "order_1001",
                    "idempotency_key": "pay_ord1001_20260729a1b2"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Checkout created (or exact replay of original success)",
            "headers": {
              "Idempotency-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                },
                "description": "Present when this response is a safe replay"
              },
              "Idempotency-Status": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "stored",
                    "replayed",
                    "processing"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payment"
                }
              }
            }
          },
          "202": {
            "$ref": "#/components/responses/IdempotencyProcessing"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "description": "Idempotency conflict, key mismatch, or duplicate merchant reference",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "conflict": {
                    "value": {
                      "status": "error",
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "Idempotency key was already used with a different request payload."
                      }
                    }
                  },
                  "mismatch": {
                    "value": {
                      "status": "error",
                      "error": {
                        "code": "idempotency_key_mismatch",
                        "message": "Idempotency-Key header and body idempotency_key must match."
                      }
                    }
                  },
                  "duplicate_reference": {
                    "value": {
                      "status": "error",
                      "error": {
                        "code": "duplicate_reference",
                        "message": "Reference already used for this merchant with a different idempotency key."
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Missing or invalid idempotency key / validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "required": {
                    "value": {
                      "status": "error",
                      "error": {
                        "code": "idempotency_key_required",
                        "message": "Idempotency-Key is required."
                      }
                    }
                  },
                  "invalid": {
                    "value": {
                      "status": "error",
                      "error": {
                        "code": "invalid_idempotency_key",
                        "message": "Idempotency-Key must be 16\u2013128 characters matching [A-Za-z0-9_-]."
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payments": {
      "post": {
        "tags": [
          "Payments"
        ],
        "summary": "Initialize a payment (alias)",
        "description": "Alias for POST /payments/initialize. Idempotency-Key required.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "amount",
                  "currency",
                  "reference"
                ],
                "properties": {
                  "amount": {
                    "type": "number"
                  },
                  "currency": {
                    "type": "string"
                  },
                  "reference": {
                    "type": "string"
                  },
                  "idempotency_key": {
                    "type": "string",
                    "minLength": 16,
                    "maxLength": 128
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Checkout created or replayed"
          },
          "202": {
            "$ref": "#/components/responses/IdempotencyProcessing"
          },
          "409": {
            "description": "idempotency_conflict / duplicate_reference / mismatch"
          },
          "422": {
            "description": "idempotency_key_required / invalid_idempotency_key"
          }
        }
      }
    },
    "/charges": {
      "post": {
        "tags": [
          "Payments"
        ],
        "summary": "Create a direct charge",
        "description": "Direct charge. Idempotency-Key required; safe retries replay the original result.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "amount",
                  "currency",
                  "reference",
                  "payment_method"
                ],
                "properties": {
                  "amount": {
                    "type": "number"
                  },
                  "currency": {
                    "type": "string"
                  },
                  "reference": {
                    "type": "string"
                  },
                  "payment_method": {
                    "type": "string",
                    "enum": [
                      "telebirr",
                      "cbebirr",
                      "mpesa",
                      "card",
                      "bank_transfer"
                    ]
                  },
                  "phone": {
                    "type": "string"
                  },
                  "idempotency_key": {
                    "type": "string",
                    "minLength": 16,
                    "maxLength": 128
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Charge result or replay"
          },
          "202": {
            "$ref": "#/components/responses/IdempotencyProcessing"
          },
          "409": {
            "description": "idempotency_conflict / duplicate_reference"
          },
          "422": {
            "description": "Missing/invalid idempotency key"
          }
        }
      }
    },
    "/refunds": {
      "post": {
        "tags": [
          "Refunds"
        ],
        "summary": "Refund a payment by DeboPay transaction id",
        "description": "Refund a successful payment fully or partially using the DeboPay transaction id (`debo_reference` from initialize/charge), e.g. `DPX-20260717-A1B2C3`. Do not use merchant order references or DeboFund campaign numbers. Legacy field `transaction_reference` is accepted as an alias for `transaction_id`.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "transaction_id"
                ],
                "properties": {
                  "transaction_id": {
                    "type": "string",
                    "description": "DeboPay transaction id (debo_reference)",
                    "example": "DPX-20260717-A1B2C3"
                  },
                  "transaction_reference": {
                    "type": "string",
                    "description": "Legacy alias for transaction_id (DeboPay id only)"
                  },
                  "amount": {
                    "type": "number",
                    "description": "Omit for full refund"
                  },
                  "reason": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Refund completed"
          },
          "404": {
            "description": "Transaction not found"
          }
        }
      }
    },
    "/transactions/{reference}": {
      "get": {
        "tags": [
          "Payments"
        ],
        "summary": "Verify a transaction",
        "parameters": [
          {
            "name": "reference",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Payment status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payment"
                }
              }
            }
          }
        }
      }
    },
    "/payouts": {
      "get": {
        "tags": [
          "Payouts"
        ],
        "summary": "List payouts",
        "responses": {
          "200": {
            "description": "Payout list"
          }
        }
      },
      "post": {
        "tags": [
          "Payouts"
        ],
        "summary": "Send a payout to a bank or wallet",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "amount",
                  "destination_type",
                  "destination"
                ],
                "properties": {
                  "amount": {
                    "type": "number"
                  },
                  "destination_type": {
                    "type": "string",
                    "enum": [
                      "bank",
                      "wallet"
                    ]
                  },
                  "destination": {
                    "type": "string"
                  },
                  "bank_code": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Payout queued"
          }
        }
      }
    },
    "/balance": {
      "get": {
        "tags": [
          "Payouts"
        ],
        "summary": "Get settlement balance",
        "responses": {
          "200": {
            "description": "Balance",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "available": {
                      "type": "number"
                    },
                    "pending": {
                      "type": "number"
                    },
                    "currency": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/webhooks/endpoints": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Register a webhook endpoint",
        "responses": {
          "201": {
            "description": "Endpoint registered"
          }
        }
      }
    },
    "/subscriptions": {
      "get": {
        "tags": [
          "Subscriptions"
        ],
        "summary": "List recurring subscriptions",
        "responses": {
          "200": {
            "description": "List"
          }
        }
      },
      "post": {
        "tags": [
          "Subscriptions"
        ],
        "summary": "Create a recurring subscription",
        "responses": {
          "201": {
            "description": "Subscription created"
          }
        }
      }
    },
    "/subscriptions/{reference}": {
      "get": {
        "tags": [
          "Subscriptions"
        ],
        "summary": "Retrieve a subscription",
        "parameters": [
          {
            "name": "reference",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Subscription"
          }
        }
      }
    },
    "/fund/campaigns": {
      "get": {
        "tags": [
          "Fund"
        ],
        "summary": "List Debo Fund campaigns",
        "responses": {
          "200": {
            "description": "Campaign list"
          }
        }
      },
      "post": {
        "tags": [
          "Fund"
        ],
        "summary": "Create a campaign",
        "responses": {
          "201": {
            "description": "Campaign created"
          }
        }
      }
    }
  },
  "components": {
    "parameters": {
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": true,
        "description": "Client-generated unique key for safe retries (16\u2013128 chars, [A-Za-z0-9_-]). Header takes precedence over JSON idempotency_key; both must match if sent. Replays return the exact original success response for up to 24 hours.\n",
        "schema": {
          "type": "string",
          "minLength": 16,
          "maxLength": 128,
          "pattern": "^[A-Za-z0-9_-]{16,128}$"
        },
        "example": "pay_ord1001_20260729a1b2"
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Use your secret API key as a Bearer token (sk_test_/sk_live_ or legacy dp_test_/dp_live_)."
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing or invalid API key",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ValidationError": {
        "description": "Validation failed",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "IdempotencyProcessing": {
        "description": "Twin request still processing \u2014 do not start a new payment; retry the same key",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "status": {
                  "type": "string",
                  "example": "processing"
                },
                "message": {
                  "type": "string"
                },
                "error": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "string",
                      "example": "processing"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Idempotency key creation rate exceeded",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            },
            "example": {
              "status": "error",
              "error": {
                "code": "too_many_requests",
                "message": "Too many idempotency keys created. Retry later."
              }
            }
          }
        }
      }
    },
    "schemas": {
      "Payment": {
        "type": "object",
        "properties": {
          "reference": {
            "type": "string"
          },
          "amount": {
            "type": "number"
          },
          "currency": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "success",
              "failed",
              "refunded"
            ]
          },
          "checkout_url": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string"
          },
          "errors": {
            "type": "object"
          }
        }
      },
      "ApiError": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "example": "error"
          },
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "param": {
                "type": "string"
              },
              "doc_url": {
                "type": "string"
              }
            }
          }
        }
      }
    }
  }
}