{
  "openapi": "3.0.3",
  "info": {
    "title": "BankConv API",
    "version": "1.0.0",
    "description": "Convert bank statement PDFs into structured data. Upload a PDF, poll the conversion until it completes, then read the transactions as JSON or download them as CSV, OFX, QFX, QBO or Xero CSV. Each converted page uses one page of your plan's allowance.",
    "termsOfService": "https://bankconv.com/terms",
    "contact": {
      "name": "BankConv support",
      "url": "https://bankconv.com/contact",
      "email": "support@bankconv.com"
    },
    "x-logo": {
      "url": "https://bankconv.com/logo.png"
    }
  },
  "externalDocs": {
    "description": "API documentation",
    "url": "https://bankconv.com/api-docs"
  },
  "servers": [
    {
      "url": "https://bankconv.com/api/v1"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "tags": [
    {
      "name": "Conversions",
      "description": "Upload statements, check their status and read the results."
    },
    {
      "name": "Credits",
      "description": "Your team's page balance and usage."
    }
  ],
  "paths": {
    "/conversions": {
      "post": {
        "tags": ["Conversions"],
        "operationId": "createConversion",
        "summary": "Upload a PDF and start a conversion",
        "description": "Starts the conversion and returns straight away. Poll `GET /conversions/{conversion}` until `status` is `completed` or `failed`. The team needs enough pages left for the whole document.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": ["file"],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "The statement PDF, up to 30 MB."
                  },
                  "password": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "Password for a protected PDF."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The conversion was created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConversionResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "402": {
            "description": "`payment_failed`: the last subscription payment failed and the plan is paused. `billing_url` opens the billing portal.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "`validation_error`: invalid parameters, such as a missing file or a wrong password. `insufficient_credits`: not enough pages left for the whole document.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "get": {
        "tags": ["Conversions"],
        "operationId": "listConversions",
        "summary": "List your team's conversions",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "description": "Page number.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "description": "Results per page.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 15
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Only return conversions with this status.",
            "schema": {
              "$ref": "#/components/schemas/ConversionStatus"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Sort field. A leading `-` sorts descending.",
            "schema": {
              "type": "string",
              "enum": ["-created_at", "created_at", "-pages_count", "pages_count"],
              "default": "-created_at"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of conversions.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConversionList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/conversions/{conversion}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ConversionId"
        }
      ],
      "get": {
        "tags": ["Conversions"],
        "operationId": "getConversion",
        "summary": "Get a conversion's status",
        "responses": {
          "200": {
            "description": "The conversion.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConversionResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "tags": ["Conversions"],
        "operationId": "deleteConversion",
        "summary": "Delete a conversion",
        "responses": {
          "204": {
            "description": "The conversion was deleted."
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/conversions/{conversion}/transactions": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ConversionId"
        }
      ],
      "get": {
        "tags": ["Conversions"],
        "operationId": "getConversionTransactions",
        "summary": "Get the transactions as clean JSON rows",
        "description": "Returns real dates and one signed amount per row: money in is positive, money out is negative. Amounts and balances are decimal strings.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Tables"
          }
        ],
        "responses": {
          "200": {
            "description": "The statement and its transactions.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionsResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "410": {
            "$ref": "#/components/responses/Gone"
          },
          "422": {
            "$ref": "#/components/responses/NotDownloadable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/conversions/{conversion}/download": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ConversionId"
        }
      ],
      "get": {
        "tags": ["Conversions"],
        "operationId": "downloadConversion",
        "summary": "Download as JSON, CSV, OFX, QFX, QBO or Xero CSV",
        "description": "Works once the conversion is `completed`. The default JSON holds every extracted page with its blocks, so you can map columns yourself. For ready-made rows, use the transactions endpoint.",
        "parameters": [
          {
            "name": "format",
            "in": "query",
            "description": "Output format. `qfx` is for Quicken, `qbo` is QuickBooks Web Connect and `xero` is a CSV for Xero.",
            "schema": {
              "type": "string",
              "enum": ["json", "csv", "ofx", "qfx", "qbo", "xero"],
              "default": "json"
            }
          },
          {
            "name": "view",
            "in": "query",
            "description": "For `csv`. `raw` keeps each table as extracted, page by page. `merged` joins tables with the same columns into one list.",
            "schema": {
              "type": "string",
              "enum": ["raw", "merged"],
              "default": "raw"
            }
          },
          {
            "$ref": "#/components/parameters/Tables"
          }
        ],
        "responses": {
          "200": {
            "description": "The converted statement in the requested format.",
            "headers": {
              "X-BankConv-Warnings": {
                "description": "On `ofx`, `qfx`, `qbo` and `xero` downloads: any warnings, as a JSON array.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentResponse"
                }
              },
              "text/csv": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "application/x-ofx": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "application/vnd.intu.qbo": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "410": {
            "$ref": "#/components/responses/Gone"
          },
          "422": {
            "$ref": "#/components/responses/NotDownloadable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/credits": {
      "get": {
        "tags": ["Credits"],
        "operationId": "getCredits",
        "summary": "Check your page balance",
        "responses": {
          "200": {
            "description": "The team's page balance for the current period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreditsResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/credits/usage": {
      "get": {
        "tags": ["Credits"],
        "operationId": "getCreditsUsage",
        "summary": "Pages used in the current period",
        "responses": {
          "200": {
            "description": "The pages used since the start of the period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UsageResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "A team API key, created in the BankConv app under team settings. It starts with `sk_live_`."
      }
    },
    "parameters": {
      "ConversionId": {
        "name": "conversion",
        "in": "path",
        "required": true,
        "description": "The conversion's id.",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "Tables": {
        "name": "tables",
        "in": "query",
        "description": "For transactions and for `ofx`, `qfx`, `qbo` and `xero` downloads: the tables to read, as comma-separated `page:table` pairs counted from 0. Without it, BankConv picks the group of tables that reads into the most transactions.",
        "schema": {
          "type": "string",
          "pattern": "^\\d+:\\d+(,\\d+:\\d+)*$",
          "example": "0:1,1:0"
        }
      }
    },
    "responses": {
      "Unauthenticated": {
        "description": "`unauthenticated`: the API key is missing or invalid.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "NotFound": {
        "description": "`not_found`: the conversion does not exist or belongs to another team.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "Gone": {
        "description": "`gone`: the conversion was deleted under your retention policy.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "ValidationError": {
        "description": "`validation_error`: invalid parameters. `fields` lists the problems per field.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "NotDownloadable": {
        "description": "`validation_error`: invalid parameters. `not_ready`: the conversion is still processing, or its statement details are still being read (transactions and accounting formats only, for up to five minutes after completion). `unreadable_statement`: the tables can't be read as transactions, and `failure_class` says why.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "RateLimited": {
        "description": "`rate_limited`: each API key can make 60 requests per minute. Wait for the number of seconds in `Retry-After`.",
        "headers": {
          "Retry-After": {
            "description": "Seconds to wait before trying again.",
            "schema": {
              "type": "integer"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      }
    },
    "schemas": {
      "ConversionStatus": {
        "type": "string",
        "enum": ["pending", "no_credits", "processing", "completed", "failed"]
      },
      "Conversion": {
        "type": "object",
        "required": ["id", "status", "pages_count", "expired", "created_at", "completed_at"],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "$ref": "#/components/schemas/ConversionStatus"
          },
          "pages_count": {
            "type": "integer",
            "nullable": true
          },
          "expired": {
            "type": "boolean",
            "description": "True once the results were deleted under your retention policy."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "completed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "input": {
            "type": "object",
            "properties": {
              "filename": {
                "type": "string"
              },
              "pages_count": {
                "type": "integer",
                "nullable": true
              }
            }
          }
        }
      },
      "ConversionResponse": {
        "type": "object",
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Conversion"
          }
        }
      },
      "ConversionList": {
        "type": "object",
        "required": ["data", "links", "meta"],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Conversion"
            }
          },
          "links": {
            "type": "object",
            "properties": {
              "first": {
                "type": "string",
                "format": "uri",
                "nullable": true
              },
              "last": {
                "type": "string",
                "format": "uri",
                "nullable": true
              },
              "prev": {
                "type": "string",
                "format": "uri",
                "nullable": true
              },
              "next": {
                "type": "string",
                "format": "uri",
                "nullable": true
              }
            }
          },
          "meta": {
            "type": "object",
            "properties": {
              "current_page": {
                "type": "integer"
              },
              "last_page": {
                "type": "integer"
              },
              "per_page": {
                "type": "integer"
              },
              "total": {
                "type": "integer"
              }
            }
          }
        }
      },
      "Transaction": {
        "type": "object",
        "required": ["date", "description", "reference", "amount", "balance"],
        "properties": {
          "date": {
            "type": "string",
            "format": "date"
          },
          "description": {
            "type": "string"
          },
          "reference": {
            "type": "string",
            "nullable": true
          },
          "amount": {
            "type": "string",
            "description": "Signed decimal: money in is positive, money out is negative.",
            "example": "-4.80"
          },
          "balance": {
            "type": "string",
            "nullable": true,
            "description": "The running balance, when the statement shows one.",
            "example": "4445.20"
          }
        }
      },
      "TransactionsResponse": {
        "type": "object",
        "required": ["data"],
        "properties": {
          "data": {
            "type": "object",
            "required": ["tables", "transaction_count", "transactions", "warnings"],
            "properties": {
              "tables": {
                "type": "string",
                "description": "The tables that were read, as `page:table` pairs counted from 0.",
                "example": "0:1,1:0"
              },
              "institution": {
                "type": "string",
                "nullable": true
              },
              "country": {
                "type": "string",
                "nullable": true
              },
              "account_type": {
                "type": "string",
                "nullable": true
              },
              "account_number": {
                "type": "string",
                "nullable": true,
                "example": "XXXX4821"
              },
              "currency": {
                "type": "string",
                "nullable": true,
                "example": "USD"
              },
              "period": {
                "type": "object",
                "properties": {
                  "start": {
                    "type": "string",
                    "format": "date",
                    "nullable": true
                  },
                  "end": {
                    "type": "string",
                    "format": "date",
                    "nullable": true
                  }
                }
              },
              "transaction_count": {
                "type": "integer"
              },
              "transactions": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Transaction"
                }
              },
              "warnings": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "DocumentResponse": {
        "type": "object",
        "required": ["data"],
        "properties": {
          "data": {
            "type": "object",
            "required": ["pages"],
            "properties": {
              "pages": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": ["page", "blocks"],
                  "properties": {
                    "page": {
                      "type": "integer",
                      "description": "Page number, from 1."
                    },
                    "blocks": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": ["block_type", "html"],
                        "properties": {
                          "block_type": {
                            "type": "string"
                          },
                          "html": {
                            "type": "string",
                            "nullable": true
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "CreditsResponse": {
        "type": "object",
        "required": ["data"],
        "properties": {
          "data": {
            "type": "object",
            "required": ["total", "remaining", "bonus", "bonusRemaining"],
            "properties": {
              "total": {
                "type": "integer"
              },
              "remaining": {
                "type": "integer"
              },
              "bonus": {
                "type": "integer"
              },
              "bonusRemaining": {
                "type": "integer"
              }
            }
          }
        }
      },
      "UsageResponse": {
        "type": "object",
        "required": ["data"],
        "properties": {
          "data": {
            "type": "object",
            "required": ["period_start", "period_end", "pages_used"],
            "properties": {
              "period_start": {
                "type": "string",
                "format": "date"
              },
              "period_end": {
                "type": "string",
                "format": "date"
              },
              "pages_used": {
                "type": "integer"
              }
            }
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "object",
            "required": ["code", "message", "status"],
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "unauthenticated",
                  "not_found",
                  "gone",
                  "validation_error",
                  "insufficient_credits",
                  "payment_failed",
                  "not_ready",
                  "unreadable_statement",
                  "rate_limited",
                  "error"
                ]
              },
              "message": {
                "type": "string"
              },
              "status": {
                "type": "integer"
              },
              "fields": {
                "type": "object",
                "description": "On `validation_error`: the problems per field.",
                "additionalProperties": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              },
              "remaining": {
                "type": "integer",
                "description": "On `insufficient_credits`: the pages left."
              },
              "required": {
                "type": "integer",
                "description": "On `insufficient_credits`: the pages the document needs."
              },
              "billing_url": {
                "type": "string",
                "format": "uri",
                "description": "On `payment_failed`: opens the billing portal."
              },
              "failure_class": {
                "type": "string",
                "description": "On `unreadable_statement`: why the tables can't be read."
              },
              "row": {
                "type": "integer",
                "nullable": true,
                "description": "On `unreadable_statement`: the row that failed, when known."
              }
            }
          }
        }
      }
    }
  }
}
