{
  "openapi": "3.1.0",
  "info": {
    "title": "Insights API",
    "description": "# Overview\n[Download our postman collection here.](https://fingoal.dev/FinGoal%20Enrichment.postman_collection.json)\n\nThe Insights API provides developers with tools to enhance their transaction, account, and user data with deep enrichment. Although the information returned by the Insights API can be utilized in various ways and implementations may differ, the initial steps for using the API are consistent: \n1. Request a FinGoal developer account.\n2. Obtain API access credentials.\n3. Generate an Insights API authentication token. \n4. Submit transactions to the Insights API. \n5. Register for Webhooks.\n6. Request Enrichment.\n\n## Important Resources\n- [Complete Insights API Tag Registry](https://fingoal.com/tags-list)\n- [Complete Insights API Categorization Spreadsheet](https://docs.google.com/spreadsheets/d/1jnmw1LriclC3bO-oC7f7EkhmfCL7gw2LQLX8zay1vXw/edit?gid=0#gid=0)\n\n## Request a FinGoal Developer Account\nTo use the Insights API, you need authentication credentials. These credentials can be obtained by <a href=\"https://fingoal.com/request-developer-account\" target=\"_blank\"> requesting a FinGoal developer account</a>. FinGoal developer support will send you development environment credentials within 24 hours. These credentials are required for the quickstart. \n# Quickstart\n## Generate a JWT Authentication Token\nAll Insights API endpoints require an `Authorization` header with a `Bearer` token. This token is a JSON Web Token (JWT) generated by the Insights API authentication endpoint. To generate this token, you will need the `client_id` and `client_secret` provided when you requested a FinGoal developer account. \n\n### 1. Prepare the Request Body\nThe request body is a JSON object with the following structure:\n```json\n{\n\t\"client_id\": \"{YOUR_CLIENT_ID}\",\n\t\"client_secret\": \"{YOUR_CLIENT_SECRET}\"\n} \n```\n### 2. Make a POST Request\nMake a POST request to the Insights API authentication endpoint using the prepared JSON object.\n```js\nconst body = {\n  \"client_id\": \"{YOUR_CLIENT_ID}\",\n  \"client_secret\": \"{YOUR_CLIENT_SECRET}\"\n}\n\nconst requestOptions = {\n  method: 'POST',\n  body: body,\n};\n\ntry {\n\tconst response = await fetch(\"https://findmoney-dev.fingoal.com/v3/authentication\", requestOptions);\n  const data = response.json();\n\tconst { access_token } = data;\n\tconsole.log({ access_token });\n} catch(error) {\n\tconsole.log('AUTHENTICATION_ERROR:', error);\n}\n```\nThe JavaScript code above uses the `fetch` API to request an access token. If the request succeeds, it extracts the access_token from the response body. If an error occurs, it logs the error. \n\n### Successful Response\nIf the request is successful, the response body will contain a JSON object with the following structure:\n- `access_token`: The JWT token used to authenticate requests to the Insights API.\n- `scope`: The permissions that the token has.\n- `expires_in`: The number of seconds until the token expires (always 86400 seconds, or 24 hours). \n- `token_type`: The type of token. This value is always `Bearer`.\n```json\n{\n    \"access_token\": \"eyJh...\",\n    \"scope\": \"read:transactions write:transactions ...\",\n    \"expires_in\": 86400,\n    \"token_type\": \"Bearer\"\n}\n```\n### Best Practices \n- Store the `access_token` securely. Do not expose it in client-side code.\n- Use the `expires_in` value to determine when to refresh the token.\n- Regenerate a new token only after the current token has expired.\n\n## Include the JWT Token in Requests\nTo authenticate your requests to the Insights API, you must include the JWT token in the `Authorization` header. The header should have the following structure:\n```json\n{\n  \"Authorization\": \"Bearer {YOUR_ACCESS_TOKEN}\"\n}\n```\nThis header will successfully authenticate any request to the Insights API. You can now proceed to the enrichment, tagging, or savings recommendations quickstarts to integrate the Insights API into your application.\n\n## Tenancy \nInsights API supports the concept of tenancy. A `tenant` refers to a grouping of customer data (users, transactions, tags, accounts, etc.) that may be accessible to multiple clients. By default, a new client’s connection to the InsightsAPI does not use tenancy; however, they may enable tenancy at any time.\n\nCurrently, Insights API does not allow you to create custom tenants. The FinGoal customer support team needs to coordinate with both the client & tenant parties to set up a new connection. If a client’s request for access to a tenant is approved, FinGoal will send the client an identifier for the tenant, and authorize them to access that tenant’s resources. \n\nTo interact with the Insights API on behalf of a tenant, include a tenant_id in your Insights API token request: \n\n```js\nconst response = await fetch(\"{INSIGHTS_API_BASE_URL}/v3/authentication\", {\n\t\tmethod: \"POST\",\n\t\tdata: {\n\t\t\t\tclient_id: \"{MY_CLIENT_ID}\",\n\t\t\t\tclient_secret: \"{MY_CLIENT_SECRET}\",\n\t\t\t\ttenant_id: \"{TENANT_ID_FROM_FINGOAL}\"\n\t\t}\n});\n```\n\nBy including the `tenant_id` in your token scopes, the generated token allows you to: \n\n- Write data to the tenant’s environment.\n- Read data from the tenant’s environment.\n\n<aside>\nIf you do not include a tenant ID, your token will only allow you to access data you have created without a specific tenant association. \n</aside>\n\nAs soon as you are successfully added to a tenant’s data silo, you will begin receiving webhook updates for all activity in that silo. Note that this may include new enrichment data that is added to the environment by clients other than yourself. Refer to the webhook documentation for more information on the content of Insights API webhooks.",
    "version": "3.1.3"
  },
  "servers": [
    {
      "url": "https://findmoney-dev.fingoal.com/v3",
      "description": "Insights API Development"
    },
    {
      "url": "https://findmoney.fingoal.com/v3",
      "description": "Insights API Production"
    }
  ],
  "webhooks": {
    "enrichmentData": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Enrichment Data-Rich Webhook",
        "description": "Data-rich Transaction Enrichment webhook. When transaction enrichment completes, you will receive a POST request containing the full enriched transaction data directly in the payload.\n\nThis webhook type (`ENRICHMENT_DATA`) sends the complete enrichment results, including all enriched transactions and any failed transactions.\n\nUse this webhook type when you want to receive enrichment results directly without needing to fetch them from a separate endpoint.\n",
        "operationId": "enrichmentDataWebhook",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "enrichedTransactions": {
                    "$ref": "#/components/schemas/WebhookConfigurationsTestPostENRICHMENT_DATA"
                  },
                  "failedTransactions": {
                    "$ref": "#/components/schemas/WebhookConfigurationsTestPostENRICHMENT_DATA"
                  },
                  "tenant_id": {
                    "type": "string",
                    "description": "The ID of the tenant associated with this webhook, if from a tenant environment.",
                    "example": "TEN-123456"
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "X-Webhook-Verification",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "A SHA-256 HMAC signature of the webhook payload that can be used to verify the authenticity of the webhook."
          }
        ],
        "responses": {
          "200": {
            "description": "Success"
          },
          "201": {
            "description": "Success"
          }
        }
      }
    },
    "enrichmentNotification": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Enrichment Notification Webhook",
        "description": "Non-data-rich Transaction Enrichment webhook. When transaction enrichment completes, you will receive a POST request containing a `batch_request_id` that you can use to fetch the enriched results.\n\nThis webhook type (`ENRICHMENT_NOTIFICATION`) sends only a notification with identifiers. You must fetch the actual enrichment data from `/cleanup/{batch_request_id}` endpoint using the provided `batch_request_id`.\n\nUse this webhook type when you prefer smaller webhook payloads and want to fetch results on-demand.\n",
        "operationId": "enrichmentNotificationWebhook",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EnrichmentNotificationPostRequest"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "X-Webhook-Verification",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "A SHA-256 HMAC signature of the webhook payload that can be used to verify the authenticity of the webhook."
          }
        ],
        "responses": {
          "200": {
            "description": "Success"
          },
          "201": {
            "description": "Success"
          }
        }
      }
    },
    "userTagsData": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "User Tags Data-Rich Webhook",
        "description": "Data-rich User Tags webhook. When user tag processing completes, you will receive a POST request with a JSON payload containing the full user tags data directly in the payload.\n\nThis webhook type (`USER_TAGS_DATA`) sends the complete user tags results, including all created, deleted, and modified tags with their scores.\n\nUse this webhook type when you want to receive user tag changes directly without needing to fetch them from a separate endpoint.\n",
        "operationId": "userTagsDataWebhook",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookConfigurationsTestPostUSER_TAGS_DATA"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "X-Webhook-Verification",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "A SHA-256 HMAC signature of the webhook payload that can be used to verify the authenticity of the webhook."
          }
        ],
        "responses": {
          "200": {
            "description": "Success"
          },
          "201": {
            "description": "Success"
          }
        }
      }
    },
    "userTagsNotification": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "User Tags Notification Webhook",
        "description": "Non-data-rich User Tags webhook. When user tag processing completes, you will receive a POST request containing a `guid` that you can use to fetch the user tags.\n\nThis webhook type (`USER_TAGS_NOTIFICATION`) sends only a notification with identifiers. You must fetch the actual tag data from the `/users/tags/{guid}` endpoint using the provided `guid`.\n\nUse this webhook type when you prefer smaller webhook payloads and want to fetch results on-demand.\n",
        "operationId": "userTagsNotificationWebhook",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "guid": {
                    "type": "string",
                    "example": "3961c39e-e1c6-45ec-acd0-9a7793dabe02"
                  },
                  "tenant_id": {
                    "type": "string",
                    "description": "The ID of the tenant for the users included in this update, if they are from a tenant environment."
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "X-Webhook-Verification",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "A SHA-256 HMAC signature of the webhook payload that can be used to verify the authenticity of the webhook."
          }
        ],
        "responses": {
          "200": {
            "description": "Success"
          },
          "201": {
            "description": "Success"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "Authentication": {
        "type": "oauth2",
        "flows": {
          "clientCredentials": {
            "tokenUrl": "https://findmoney.fingoal.com/v3/authentication",
            "scopes": {
              "enrichment": "Grants access to the transaction enrichment APIs."
            }
          }
        }
      }
    },
    "schemas": {
      "WebhookConfigurationsTestPostENRICHMENT_DATA": {
        "type": "object",
        "properties": {
          "enrichedTransactions": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "accountid": {
                  "description": "The ID of the account associated with the transaction",
                  "type": "string"
                },
                "accountType": {
                  "description": "The type of account associated with the transaction (e.g., 'checking', 'savings')",
                  "type": "string"
                },
                "amountnum": {
                  "description": "The transaction's USD amount",
                  "type": "number"
                },
                "category": {
                  "description": "The most applicable categorization for the transaction",
                  "type": "string"
                },
                "categoryId": {
                  "description": "The numeric ID of the transaction's category",
                  "type": "number"
                },
                "categoryLabel": {
                  "deprecated": true,
                  "description": "A cascading hierarchy of the transaction's categories, from high-level to detail-level categorization. This field is deprecated and not recommended for use, as it may not reflect more correct information available in other 'category' fields.",
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "address": {
                  "description": "The address associated with the transaction",
                  "type": [
                    "string",
                    "null"
                  ],
                  "example": "123 Main St"
                },
                "city": {
                  "description": "The city associated with the transaction",
                  "type": [
                    "string",
                    "null"
                  ],
                  "example": "Urbana"
                },
                "client_id": {
                  "type": "string",
                  "description": "Your FinGoal client ID"
                },
                "container": {
                  "description": "A high-level categorization of the account type. Eg, 'bank'",
                  "type": [
                    "string",
                    "null"
                  ],
                  "example": "Transaction"
                },
                "date": {
                  "description": "The date on which the transaction took place",
                  "type": "string",
                  "format": "date-time"
                },
                "detailCategoryId": {
                  "description": "The numeric ID of the transaction's detail category",
                  "type": "number"
                },
                "guid": {
                  "description": "The transaction's globally unique FinSight API issued ID",
                  "type": "string"
                },
                "highLevelCategoryId": {
                  "description": "The numeric ID of the transaction's high level category",
                  "type": "number"
                },
                "isPhysical": {
                  "description": "Whether the transaction was made at a physical location, or online",
                  "type": [
                    "boolean",
                    "null"
                  ],
                  "example": true
                },
                "isRecurring": {
                  "deprecated": true,
                  "description": "This field is deprecated. Denotes whether the transaction is set to recur on a fixed interval",
                  "type": [
                    "boolean",
                    "null"
                  ],
                  "example": false
                },
                "merchantAddress1": {
                  "description": "The street address of the merchant associated with the transaction",
                  "type": [
                    "string",
                    "null"
                  ],
                  "example": "123 Main St"
                },
                "merchantCity": {
                  "description": "The name of the city where the merchant is located",
                  "type": [
                    "string",
                    "null"
                  ],
                  "example": "Urbana"
                },
                "merchantCountry": {
                  "description": "The name of the country where the merchant is located",
                  "type": [
                    "string",
                    "null"
                  ],
                  "example": "US"
                },
                "merchantLatitude": {
                  "description": "The latitude of the merchant",
                  "type": [
                    "string",
                    "null"
                  ],
                  "example": "38.9517"
                },
                "merchantLogoURL": {
                  "description": "The URL resource for the merchant's logo",
                  "type": "string"
                },
                "merchantLongitude": {
                  "description": "The longitude of the merchant",
                  "type": [
                    "string",
                    "null"
                  ],
                  "example": "-92.3341"
                },
                "merchantName": {
                  "description": "The name of the merchant associated with the transaction",
                  "type": [
                    "string",
                    "null"
                  ],
                  "example": "Dollar General"
                },
                "merchantPhoneNumber": {
                  "description": "The phone number of the merchant associated with the transaction",
                  "type": [
                    "string",
                    "null"
                  ],
                  "example": "555-555-5555"
                },
                "merchantState": {
                  "description": "The name of the state where the merchant is located",
                  "type": [
                    "string",
                    "null"
                  ],
                  "example": "MO"
                },
                "merchantType": {
                  "description": "The merchant's type",
                  "type": [
                    "string",
                    "null"
                  ],
                  "example": "retail"
                },
                "merchantZip": {
                  "description": "The ZIP code where the merchant is located",
                  "type": [
                    "string",
                    "null"
                  ],
                  "example": "65401"
                },
                "original_description": {
                  "description": "The transaction description as received. This will not change",
                  "type": "string"
                },
                "receiptDate": {
                  "description": "The date on which FinSight API first received the transaction",
                  "type": [
                    "string",
                    "null"
                  ],
                  "format": "date-time",
                  "example": "2024-05-01T12:00:00Z"
                },
                "requestId": {
                  "description": "A unique ID for the request the transaction came in with, for debugging purposes",
                  "type": [
                    "string",
                    "null"
                  ],
                  "example": "04f00a35-a8fa-40fd-a2ee-4af7be22ed0a"
                },
                "simple_description": {
                  "description": "An easy-to-understand, plain-language transaction description",
                  "type": "string",
                  "deprecated": true
                },
                "simpleDescription": {
                  "description": "An easy-to-understand, plain-language transaction description",
                  "type": "string"
                },
                "settlement": {
                  "description": "The settlement type of the transaction (e.g., 'debit' or 'credit')",
                  "type": [
                    "string",
                    "null"
                  ],
                  "example": "debit"
                },
                "sourceId": {
                  "description": "The source of the transaction",
                  "type": [
                    "string",
                    "null"
                  ],
                  "example": "1234"
                },
                "state": {
                  "description": "The state associated with the transaction",
                  "type": [
                    "string",
                    "null"
                  ],
                  "example": "MO"
                },
                "subtype": {
                  "description": "A more detailed classification of the transaction",
                  "type": [
                    "string",
                    "null"
                  ],
                  "example": "purchase"
                },
                "subType": {
                  "description": "A more detailed classification that provides further information on the type of transaction.",
                  "type": [
                    "string",
                    "null"
                  ],
                  "example": "purchase"
                },
                "tenant_id": {
                  "description": "The ID of the tenant associated with this transaction, if one was included.",
                  "type": [
                    "string",
                    "null"
                  ],
                  "example": "TNT-4b7d4b7d-4b7d-4b7d-4b7d-4b7d4b7d4b7d"
                },
                "transactionid": {
                  "description": "The ID of the transaction as it was originally submitted",
                  "type": "string"
                },
                "transactionTags": {
                  "description": "The FinSight API issued tags for the transaction",
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "transactionTagsId": {
                  "description": "The numeric IDs corresponding to the transaction tags",
                  "type": "array",
                  "items": {
                    "type": "integer"
                  }
                },
                "type": {
                  "description": "An attribute describing the nature of the intent behind the transaction.",
                  "type": "string"
                },
                "uid": {
                  "description": "The ID of the user associated with the transaction, as originally submitted",
                  "type": "string"
                },
                "website": {
                  "description": "The merchant's website URL",
                  "type": [
                    "string",
                    "null"
                  ],
                  "example": "https://links.fingoal.com/dollar-general"
                },
                "zip_code": {
                  "description": "The ZIP code associated with the transaction",
                  "type": [
                    "string",
                    "null"
                  ],
                  "example": "65401"
                }
              }
            }
          },
          "failedTransactions": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "transactionid": {
                  "description": "The ID of the transaction as received.",
                  "type": "string"
                },
                "amountnum": {
                  "description": "The transaction's USD amount as received.",
                  "type": "number"
                },
                "original_description": {
                  "description": "The transaction description as received.",
                  "type": "string"
                },
                "uid": {
                  "description": "The ID of the user associated with the transaction, as received.",
                  "type": "string"
                },
                "date": {
                  "description": "The date on which the transaction took place as received.",
                  "type": "string",
                  "format": "date-time"
                },
                "settlement": {
                  "description": "The transaction's settlement type as received.",
                  "type": "string"
                },
                "accountType": {
                  "description": "The type of account associated with the transaction as received.",
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "WebhookConfigurationsTestPostUSER_TAGS_DATA": {
        "type": "object",
        "properties": {
          "tenant_id": {
            "type": "string",
            "description": "The ID of the tenant for the users included in this update, if they are from a tenant environment."
          },
          "userTags": {
            "type": "object",
            "properties": {
              "created": {
                "description": "A list of the new user tags that were generated for this user since the last user tagging update. A full list of the user tags can be accessed [here](https://fingoal.com/tags-list).",
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "user_id": {
                      "description": "The user who received this tag. Corresponds to whatever 'uid' you initially uploaded to the enrichment.",
                      "type": "string",
                      "example": "409088"
                    },
                    "user_tag_id": {
                      "description": "The ID of the tag that has been applied.",
                      "type": "integer",
                      "example": 61
                    },
                    "tag_name": {
                      "description": "The name of the tag that has been applied.",
                      "type": "string",
                      "example": "Home Improvement Loan"
                    }
                  }
                }
              },
              "deleted": {
                "description": "A list of the user tags that were removed from this user since the last user tagging update.",
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "user_id": {
                      "description": "The user who received this tag. Corresponds to whatever 'uid' you initially uploaded to the enrichment.",
                      "type": "string",
                      "example": "409088"
                    },
                    "user_tag_id": {
                      "description": "The ID of the tag that has been removed.",
                      "type": "integer",
                      "example": 46
                    },
                    "tag_name": {
                      "description": "The name of the tag that has been removed.",
                      "type": "string",
                      "example": "Movie Goer"
                    }
                  }
                }
              },
              "modified": {
                "description": "For incremental (that is, scored) user tags. Contains all scoring changes for any incremental user tags that have received a score change since the last update.",
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "user_id": {
                      "description": "The user who received this tag. Corresponds to whatever 'uid' you initially uploaded to the enrichment.",
                      "type": "string",
                      "example": "409088"
                    },
                    "user_tag_id": {
                      "description": "The ID of the tag that has been updated.",
                      "type": "integer",
                      "example": 46
                    },
                    "tag_name": {
                      "description": "The name of the tag that has been updated.",
                      "type": "string",
                      "example": "Movie Goer"
                    },
                    "previous_value": {
                      "description": "The last value for this tag's score, prior to this update.",
                      "type": "integer",
                      "example": 50
                    },
                    "new_value": {
                      "description": "The new value for this tag's score.",
                      "type": "integer",
                      "example": 75
                    },
                    "delta": {
                      "description": "The amount by which this tag's score has changed. Can be negative or positive. Will be the difference between the new_value and previous_value fields.",
                      "type": "integer",
                      "example": 25
                    }
                  }
                }
              }
            }
          }
        }
      },
      "CleanupPostRequest": {
        "type": "object",
        "required": [
          "transactions"
        ],
        "properties": {
          "transactions": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "accountType",
                "amountnum",
                "date",
                "original_description",
                "transactionid",
                "settlement",
                "uid"
              ],
              "properties": {
                "accountType": {
                  "type": "string",
                  "description": "The type of account associated with the transaction.\n\nFor transactions from loan accounts, use 'savings'.\n",
                  "enum": [
                    "checking",
                    "savings",
                    "creditCard"
                  ],
                  "example": "checking"
                },
                "amountnum": {
                  "type": "number",
                  "maxLength": 11,
                  "description": "The transaction amount in USD. Negative amounts are automatically converted to positive amounts. Use the 'settlement' field to indicate whether the transaction was a 'debit' or 'credit'. The string representation of amount must be fewer than 11 characters.",
                  "example": 19.99
                },
                "date": {
                  "description": "The date of the transaction. Must be in the format 'YYYY-MM-DD'.",
                  "type": "string",
                  "format": "date",
                  "example": "2024-05-01"
                },
                "identifiers": {
                  "description": "A JSON representation of alternative user IDs. This field is designed exclusively for users with Banno, Salesforce, or other CRM integrations. Valid identifiers are currently limited to [`sfmc_contact_id`, `banno_end_user_id`].",
                  "type": "object",
                  "properties": {
                    "sfmc_contact_id": {
                      "type": "string",
                      "example": "sfmc-1234"
                    },
                    "banno_end_user_id": {
                      "type": "string",
                      "example": "banno-1234"
                    }
                  }
                },
                "original_description": {
                  "description": "The transaction's description. Must be between 3 and 198 characters. Descriptions longer than 198 characters are automatically truncated.\n\nFor transactions from loan accounts, prepend `LOANTRANS-` to this field.\n",
                  "minLength": 1,
                  "maxLength": 198,
                  "type": "string",
                  "example": "Cottonwood Supermarket & Deli"
                },
                "transactionid": {
                  "description": "A unique identifier for the transaction. Do not use PII or other information-rich data in this field. We strongly recommend using UUID or a similar identification system.",
                  "maxLength": 100,
                  "type": "string",
                  "example": "178b1f61-dafe-4d47-837b-54ce34dc82b2"
                },
                "settlement": {
                  "description": "Indicates whether the transaction was a 'debit' or 'credit' to the account.",
                  "type": "string",
                  "enum": [
                    "debit",
                    "credit"
                  ],
                  "example": "debit"
                },
                "uid": {
                  "description": "The ID of the user associated with the transaction. User IDs must be unique. Do not use PII or other information-rich data in this field. We strongly recommend using UUID or a similar identification system.",
                  "maxLength": 50,
                  "type": "string",
                  "example": "user123"
                },
                "accountid": {
                  "description": "The account ID associated with the transaction. This field is optional and will not affect enrichment results. Do not use the actual account number. We strongly recommend using UUID or a similar identification system.",
                  "maxLength": 50,
                  "type": "string",
                  "example": "account456"
                }
              }
            }
          }
        }
      },
      "EnrichmentNotificationPostRequest": {
        "type": "object",
        "properties": {
          "batch_request_id": {
            "type": "string",
            "description": "The ID of the request that this webhook is associated with.",
            "format": "uuid",
            "example": "5f4b1b9b-4b7d-4b7d-4b7d-4b7d4b7d4b7d"
          },
          "client_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "The ID of the client that this webhook is associated with.",
            "example": "client-123"
          },
          "tenant_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "The ID of the tenant that this webhook is associated with, if the webhook is from a tenant environment.",
            "example": "TNT-5f4b1b9b-4b7d-4b7d-4b7d-4b7d4b7d4b7d"
          }
        }
      },
      "CleanupPost200Response": {
        "type": "object",
        "properties": {
          "transactions_received": {
            "type": "boolean",
            "description": "Denotes whether FinSight API has successfully received the transactions."
          },
          "transactions_validated": {
            "type": "boolean",
            "description": "Denotes whether or not the transaction payload successfully passed FinSight API validation."
          },
          "processing": {
            "type": "boolean",
            "description": "Denotes whether the asynchronous enrichment process has commenced."
          },
          "num_transactions_processing": {
            "type": "integer",
            "description": "The number of transactions that have been received."
          },
          "batch_request_id": {
            "type": "string",
            "description": "A unique ID associated with the request for debugging."
          }
        }
      },
      "WebhookConfigurationsPut200Response": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "The unique identifier for this webhook configuration.",
            "example": 1
          },
          "client_id": {
            "type": "string",
            "description": "Your client identifier.",
            "example": "your-client-id"
          },
          "tenant_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "The tenant public ID for tenant-specific configurations. Null for default configurations.",
            "example": "TEN-123456"
          },
          "webhook_type": {
            "$ref": "#/components/schemas/WebhookConfigurationsPutRequest"
          },
          "callback_url": {
            "type": "string",
            "format": "uri",
            "description": "The HTTPS URL where webhooks will be delivered.",
            "example": "https://your-server.com/webhooks/enrichment"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "The timestamp when this configuration was created.",
            "example": "2024-01-15T10:00:00.000Z"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "The timestamp when this configuration was last updated.",
            "example": "2024-01-15T10:00:00.000Z"
          }
        }
      },
      "WebhookConfigurationsPutRequest": {
        "type": "string",
        "enum": [
          "ENRICHMENT_DATA",
          "ENRICHMENT_NOTIFICATION",
          "USER_TAGS_DATA",
          "USER_TAGS_NOTIFICATION",
          "INSIGHTS"
        ],
        "description": "The type of webhook to configure:\n- `ENRICHMENT_DATA`: Data-rich Transaction Enrichment webhooks (full payload)\n- `ENRICHMENT_NOTIFICATION`: Non-data-rich Enrichment webhooks (notification only, fetch data from the `/cleanup/{batch_request_id}` endpoint)\n- `USER_TAGS_DATA`: Data-rich User Tags webhooks (full payload)\n- `USER_TAGS_NOTIFICATION`: Non-data-rich User Tags webhooks (notification only)\n- `INSIGHTS`: Finsights/insights webhooks\n"
      }
    }
  },
  "security": [
    {
      "Authentication": []
    }
  ],
  "tags": [
    {
      "name": "Enrichment",
      "description": "The Insights API's transaction enrichment endpoints enable developers to clean and enhance their transaction data. This process includes standardizing merchant names, categorizing transactions, and adding additional metadata. It also supports transaction-level tagging. Transactions submitted to the enrichment endpoints contribute to the Insights API's user tagging capabilities. \n\nThe Insights API offers both synchronous and asynchronous flows. The synchronous flow is a direct request-response model intended for testing and development purposes only. All production requests should use the asynchronous historical and streaming transaction enrichment endpoints.\n\n<a href=\"https://docs.google.com/spreadsheets/d/1XL649eKzMZ21WGWdcUE4cvKbKb6oXzfdBv5Ob8qPpbM/edit?usp=sharing\" target=\"blank\">View Full List of FinGoal Categories</a>\n\n<a href=\"https://fingoal.com/tags-list\" target=\"blank\">View Full List of FinGoal Tags</a>\n\n\n## Enrichment Quickstart\nThis quickstart requires a JWT, which can be generated following the top-level authentication quickstart. Ensure you have a valid JWT before proceeding.\n\n### 1. Prepare the Request Body\nThe request body should be a JSON object with a single parameter, `transactions`, which must be an array. Each transaction must include the following fields:\n- `uid`: A unique user identifier.\n- `amountnum`: The transaction amount.\n- `date`: The transaction date.\n- `original_description`: The original transaction description.\n- `transactionid`: The unique transaction identifier.\n- `accountType`: The account type.\n- `settlement`: The settlement type.\n\n```json\n{\n  \"transactions\": [\n    {\n      \"uid\": \"16432789fdsa78\",\n      \"accountid\": \"1615\",\n      \"amountnum\": 12.41,\n      \"date\": \"2024-05-11\",\n      \"original_description\": \"T0064 TARGET STORE\",\n      \"transactionid\": \"988cee06-5d36-11ec-b00b-bc8d8f2303a12733\",\n      \"accountType\" : \"creditCard\",\n      \"settlement\": \"debit\"\n    }\n  ]\n}\n```\n### 2. Make a POST Request\nMake a POST request to the Insights API cleanup endpoint using the prepared JSON object. Include the JWT in the `Authorization` header.\n```js\n  const headers = new Headers();\n  headers.append(\"Authorization\", \"Bearer {YOUR_TOKEN}\");\n  headers.append(\"Content-Type\", \"application/json\");\n\n  const body = JSON.stringify({\n    \"transactions\": [\n      {\n        \"uid\": \"16432789fdsa78\",\n        \"accountid\": \"1615\",\n        \"amountnum\": 12.41,\n        \"date\": \"2024-05-11\",\n        \"original_description\": \"T0064 TARGET STORE\",\n        \"transactionid\": \"988cee06-5d36-11ec-b00b-bc8d8f2303a12733\",\n        \"accountType\" : \"creditCard\",\n        \"settlement\": \"debit\"\n      }\n    ]\n  });\n\n  const requestOptions = {\n    method: 'POST',\n    redirect: 'follow'\n    headers,\n    body,\n  };\n\n  try {\n    const response = await fetch(\"https://findmoney-dev.fingoal.com/v3/cleanup\", requestOptions);\n    const data = response.json();\n    console.log(data);\n  } catch(error) {\n    console.log('ERROR:', error);\n  }\n```\nThe JavaScript code above uses the `fetch` API to request transaction enrichment. If the request succeeds, it logs the response body. If an error occurs, it logs the error.\n### 3. Extract the Batch Request ID from a Successful Response\nIf the request is successful, the response body will contain a JSON object with a single parameter, `status`. The `status` object has the following structure:\n- `transactions_received`: Whether or not the transactions were successfully enqueued for enrichment.\n- `transactions_validated`: Whether or not the transactions were successfully validated.\n- `processing`: Whether or not the transactions are currently being processed.\n- `num_transactions_processing`: The number of transactions that are currently being processed.\n- `batch_request_id`: The unique identifier for the batch request.\n\n```json\n{\n  \"status\": {\n    \"transactions_received\": true,\n    \"transactions_validated\": true,\n    \"processing\": true,\n    \"num_transactions_processing\": 1,\n    \"batch_request_id\": \"988cee06-5d36-11ec-b00b-bc8d8f2303a12733\"\n  }\n}\n```\nThe `batch_request_id` is a unique identifier for the batch request. You will use this identifier to retrieve the enriched transactions. \n### 4. Listen for the Enrichment Completion Event \nTo receive a webhook notification for a completed enrichment batch, you must submit a webhook URL. Use the FinGoal support email (support@fingoal.com) to submit a webhook URL for registry. Once the URL is registered, you will automatically receive all future enrichment completion webhooks. \n\nWebhook notifications are sent as HTTP POST requests to the registered URL. The webhook URL must be publicly accessible and support HTTPS connections. The Insights API cannot send webhooks to a non-HTTPS URL. \n\nThe webhook payload contains a JSON object with the following structure: \n- `batch_request_id`: The unique identifier for the batch request.\n\nThe `batch_request_id` corresponds to the `batch_request_id` returned in the initial enrichment request. \n```json\n{\n  \"batch_request_id\": \"988cee06-5d36-11ec-b00b-bc8d8f2303a12733\"\n}\n```\n#### Verifying the Enrichment Webhook \nEvery enrichment complete webhook includes an `X-Webhook-Verification` header. The header contains a SHA-256 HMAC signature of the webhook payload. To verify the webhook, you must generate a SHA-256 HMAC signature using the webhook payload and your Insights API secret key. If the generated signature matches the signature in the `X-Webhook-Verification` header, the webhook is valid. If not, the webhook should be discarded. \n\nThe following snippet demonstrates how to verify the webhook signature using Node.js with the `crypto` and `express` libraries.\n```js\nconst crypto = require('crypto');\nconst express = require('express');\nconst app = express();\n\napp.use(express.json());\napp.post('/webhook-receiver', (req, res) => {\n  const { headers, body } = req;\n  const { 'x-webhook-verification': signature } = headers;\n  if (!signature) {\n    res.status(400).send('Reject the webhook if no verification header is present.');\n    return;\n  }\n\n  const secret = 'YOUR_CLIENT_SECRET';\n  const payload = JSON.stringify(body);\n  const hmac = crypto.createHmac('sha256', secret);\n  const digest = hmac.update(payload).digest('hex');\n\n  if (digest === signature) {\n    res.status(200).send('The webhook is verified. It is safe to process the payload.'); \n  } else {\n    res.status(400).send('The Webhook verification is incorrect for the payload. Reject the webhook.');\n  }\n});\n```\n\n### 5. Retrieve the Enriched Transactions\nWith the `batch_request_id`, submit a GET request to the Insights API enrichment retrieval endpoint. Include the JWT in the `Authorization` header. \n```js\n  const headers = new Headers();\n  headers.append(\"Authorization\", \"Bearer {YOUR_TOKEN}\");\n\n  const requestOptions = {\n    method: 'GET',\n    redirect: 'follow',\n    headers,\n  };\n\n  try {\n    const response = await fetch(\"https://findmoney-dev.fingoal.com/v3/cleanup/{batch_request_id}\", requestOptions);\n    const data = response.json();\n    console.log(data);\n  } catch(error) {\n    console.log('ERROR:', error);\n  }\n```\nThe JavaScript code above uses the `fetch` API to request the enriched transactions. If the request succeeds, it logs the response body. If an error occurs, it logs the error.\n### Successful Response\nIf the request is successful, the response body will contain a JSON object a single parameter, `enrichedTransactions`. The `enrichedTransactions` array will contain all available transaction-level enrichment for the data in this batch. \n\n### Best Practices \n- Group transactions by `uid` for optimal performance. \n- Provide as much information as possible in the request body to improve enrichment quality.\n- Use unique `uid` and `transactionid` values for each user and transaction. These identifiers may need to be cross-referenced with your system's data in the future.\n- Avoid using personally identifiable information (PII) in the `uid` or `transactionid` fields. We recommend using a UUID or similar anonymous identifier instead. \n"
    },
    {
      "name": "User Tagging",
      "description": "markdown/tagging.md"
    },
    {
      "name": "Webhook Configurations",
      "description": "Manage webhook callback URLs for your client. Supports default and tenant-specific configurations per webhook type."
    },
    {
      "name": "Webhooks",
      "description": "Webhook payload schemas for all webhook types. Configure which webhooks you receive using the Webhook Configurations endpoints.\n\n**Available Webhook Types:**\n- `ENRICHMENT_DATA`: Data-rich Transaction Enrichment (full payload with enriched transactions)\n- `ENRICHMENT_NOTIFICATION`: Notification-only Transaction Enrichment (batch_request_id for fetching results)\n- `USER_TAGS_DATA`: Data-rich User Tags (full payload with created/deleted/modified tags)\n- `USER_TAGS_NOTIFICATION`: Notification-only User Tags (guid for fetching results)\n- `INSIGHTS`: Financial insights and recommendations\n"
    },
    {
      "name": "Transaction Upload (SFTP)",
      "description": "# Transaction Upload Guide\n\n## Quick Start\n\nUpload CSV files to your designated SFTP folder to enrich transactions automatically.\n\n## Connection Details\n\n| Setting  | Value                                    |\n| -------- | ---------------------------------------- |\n| Host     | `sftp.fingoal.dev`                       |\n| Port     | `22`                                     |\n| Protocol | SFTP                                     |\n| Auth     | SSH Key or API Key (provided by FinGoal) |\n\n## Folder Structure\n\n```\n/{your_root_folder}/\n├── DailyBatches/          ← Upload transaction CSVs here\n├── TransactionOutput/     ← Enriched transactions returned here\n├── BatchReports/          ← Processing reports\n├── UserTags/              ← User tags export returned here\n└── ValidationErrors/      ← Check here if transactions failed\n```\n\n## CSV Format\n\n**File Requirements:**\n\n- Format: CSV (UTF-8 encoded)\n- Extension: `.csv`\n- Headers: Required (first row)\n\nAll SFTP data must comply with the JSON validator, so the headers and field values must be an exact match. Pay attention to capitalization and spacing.\n\n![CSV Format Example](/images/sftp-example-csv.png)\n\n[Download example CSV](/files/sftp-example.csv)\n\nNull is not an acceptable field for any Required Column.\n\n**Required Columns:**\n\n| Column                 | Type   | Description                                | Example             |\n| ---------------------- | ------ | ------------------------------------------ | ------------------- |\n| `uid`                  | string | User identifier (max 100 chars, no colons) | `user_12345`        |\n| `amountnum`            | number | Transaction amount                         | `45.99`             |\n| `date`                 | date   | Transaction date (YYYY-MM-DD)              | `2025-12-08`        |\n| `original_description` | string | Raw transaction description. May be a combination of multiple fields covering merchant name, location, and transaction type, concatenated and separated by a space or a pipe. | `AMAZON.COM*123ABC` |\n| `transactionid`        | string | Unique transaction ID (max 200 chars)      | `txn_abc123`        |\n| `accountType`          | string | Account type (see values below)            | `checking`          |\n| `settlement`           | string | `debit` or `credit`                        | `debit`             |\n\n**Optional Columns:**\n\n| Column                 | Type   | Description                                                                                                      |\n| ---------------------- | ------ | ---------------------------------------------------------------------------------------------------------------- |\n| `accountid`            | string | Account identifier (max 100 chars)                                                                               |\n| `identifiers`          | JSON   | Additional user identifiers as JSON. This is currently limited to `sfmc_contact_id` and `banno_end_user_id`.     |\n| `accountOwnershipType` | string | Captures how the transaction's account is owned. See enumerated values below.                                    |\n \n\n**Valid `accountType` Values:**\n\n- `checking`\n- `savings`\n- `creditCard`\n- `businessChecking`\n- `businessSavings`\n- `businessCreditCard`\n- `businessLoan`\n- `loan`\n- `investments`\n\n**Valid `accountOwnershipType` values:**\n- `business` \n- `personal` \n\n## Upload Process\n\n1. **Upload** your CSV to `DailyBatches/`\n2. **Processing** begins automatically\n3. **Check** `BatchReports/` for processing summary\n4. **Review** `ValidationErrors/` if any records failed validation\n\n## Validation Errors\n\nIf your file has issues, check `ValidationErrors/` for details. Common errors:\n\n- Missing required column\n- Invalid `settlement` value (must be `debit` or `credit`)\n- Invalid `accountType` value\n- `uid` contains `:` character\n- Empty `original_description`\n\nFailed records are saved to `BatchReports/failed_{filename}_{timestamp}.csv` - fix and re-upload.\n\n## Returned Files\n\nThis section documents every file FinGoal returns to your SFTP folders, with its filename pattern, destination folder, and column structure.\n\n### Enriched Transactions (`TransactionOutput/`)\n\nEnriched transactions are returned to your `TransactionOutput/` folder after processing.\n\n**Filename:** `tenantid_clientid_YYYY_MM_DD.csv`\n\n**Format:**\n\n| Column                 | Type       | Description                                                                                                  | Example                                                          |\n| ---------------------- | ---------- | ------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------- |\n| `id`                   | number     | FinGoal internal serial id used for troubleshooting                                                          | `1042236399`                                                     |\n| `client_id`            | string     | FinGoal client id                                                                                            | `m2m-client-live-68a12307-45d0-d5f61-9de5-dfr563454`             |\n| `uid`                  | string     | User identifier (max 100 chars, no colons)                                                                   | `user_12345`                                                     |\n| `guid`                 | string     | FinGoal unique identifier                                                                                    | `62123e27-48f9-559e-ab60-11d60qt0a4a0`                           |\n| `amountnum`            | number     | Transaction amount                                                                                           | `45.99`                                                          |\n| `date`                 | date       | Transaction date (YYYY-MM-DD)                                                                                | `2025-12-08`                                                     |\n| `simple_description`   | string     | Enriched transaction description                                                                             | `Amazon`                                                         |\n| `original_description` | string     | Raw transaction description. May be a combination of multiple fields covering merchant name, location, and transaction type, concatenated and separated by a space or a pipe. | `AMAZON.COM*123ABC`                                              |\n| `transactionid`        | string     | Client id prepended to the transactionid provided by the client                                              | `m2m-client-live-68a12307-45d0-d5f61-9de5-dfr563454-txn_abc123`  |\n| `category`             | string     | Mid-level category name                                                                                      | `General Merchandise`                                            |\n| `address`              | string     | Merchant address, if available                                                                               | `123 Main Street`                                                |\n| `city`                 | string     | Merchant city, if available                                                                                  | `Boulder`                                                        |\n| `state`                | string     | Merchant state, if available                                                                                 | `CO`                                                             |\n| `zip_code`             | number     | Merchant zip code, if available                                                                              | `80301`                                                          |\n| `detail_category`      | number     | 4 digit code for the most specific or detailed category field                                                | `1316`                                                           |\n| `high_level_category`  | number     | 8 digit code for the highest level/most general category field                                               | `10000010`                                                       |\n| `tags`                 | JSON array | An array of all tags applied to this transaction                                                             | `[\"Online Shopper\"]`                                             |\n| `merchantname`         | string     | Enriched merchant name; blank if merchant is unknown                                                         | `Amazon`                                                         |\n| `settlement`           | string     | Money out of account = `debit` or money into account = `credit`                                              | `debit`                                                          |\n| `merchantlogourl`      | string     | URL of hosted logo; specific logo or category based logo may be returned depending on the size of the merchant. | `https://links.fingoal.com/amazon`                            |\n| `created_at`           | date       | Date the transaction was enriched                                                                            | `2025-12-09`                                                     |\n\n### User Tags - Current State (`UserTags/`)\n\nUser tags are automatically exported daily to your `UserTags/` folder. This file reflects the current state of tags as of the `updated_at` date.\n\n**Filename:** `user_tags_YYYY-MM-DD.csv`\n\n**Format:**\n\n| Column       | Type       | Description                   |\n| ------------ | ---------- | ----------------------------- |\n| `uid`        | string     | User identifier               |\n| `tags`       | JSON array | List of tags assigned to user |\n| `updated_at` | datetime   | Last tag update timestamp     |\n\n### User Tags - Added (`UserTags/`)\n\nWhen diffing against the current-state user tags file, this file indicates the tags to be added.\n\n**Filename:** `tags_added_YYYY-MM-DD.csv`\n\n**Format:**\n\n| Column | Type       | Description                   |\n| ------ | ---------- | ----------------------------- |\n| `uid`  | string     | User identifier               |\n| `tags` | JSON array | List of tags assigned to user |\n\n### User Tags - Removed (`UserTags/`)\n\nWhen diffing against the current-state user tags file, this file indicates the tags to be removed.\n\n**Filename:** `tags_removed_YYYY-MM-DD.csv`\n\n**Format:**\n\n| Column | Type       | Description                   |\n| ------ | ---------- | ----------------------------- |\n| `uid`  | string     | User identifier               |\n| `tags` | JSON array | List of tags assigned to user |\n\n### Reference\n\nFor the complete list of tags and categories that may appear in the returned files, see:\n\n- [Complete Insights Tag Registry](https://cPcrZ04.na1.hs-sales-engage.com/Ctc/ZT+23284/cPcrZ04/Jks2-6qcW69sMD-6lZ3pQW5K_Zr02JkdGfV-PdfW5Pgg8XW1fvzGD5WTNBsW45tYCt2q6SClW4tRVzf4KGtPFW3CMkYp9gLXWSW5BmBF-5Xm14lW92hVDr2yT150W6Dd7wJ7rJkcGW8LWRSm3Zn0L6Vp0H4K3wK3rRN1w1Sj9Hr8P9VMDjxD9cZYNyW1SSFCQ1N2JzsW7M_zyR8xDV9gW3HJR297qsSqJVWBz-P5dFyM1W523NMj8cH0gJW8bNqSr3Fy3QLW1k4W5-2H--lHc5Xzj04)\n- [Complete Insights Categorization Spreadsheet](https://cPcrZ04.na1.hs-sales-engage.com/Ctc/ZT+23284/cPcrZ04/JlY2-6qcW95jsWP6lZ3l2N6g9SQj29DxNW4-BMDz9fhKDcW7PrLSd587pnjW55r9db1FbVFSW1N54dR47lMk6N4tVl20FhK5cW64Bz-C3PC6MvW4P_Fwt7-tF1SW7zZWh79jLjYFW4l70KQ3pFrwgW3qMMXw8k2kTtVC77kJ4T_tsvW7X8_SR7xzPhhW2P6fkF1pc0sNV5Cml33Fnt_VVljgbQ3Pm4bNW1JCNWw76R2PqW6rT1xs55qXmbW8rJLhM3FsfggW5-hplm43lyd2W30FRWl8WGN7tVHtkrM1sBqjpW87W4gr89lZjRVb0mVX6hF3ZsVM3hxh3_kBg3W70xBMN6t1TNDW3Rcc7L4dnCYRW3Yjww-2KxvHZW1njkLf1fPLSHW2kJvgz3XJ5Pyf97LBRH04)\n\n## Support\n\nContact support@fingoal.com for credentials or technical support.\n"
    }
  ],
  "paths": {
    "/cleanup/sync": {
      "post": {
        "tags": [
          "Enrichment"
        ],
        "summary": "Test Transaction Enrichment",
        "description": "The test transaction enrichment endpoint provides immediate enrichment on transaction data. This endpoint is ideal for testing API functionality and previewing enrichment results. \n\n**This endpoint is not intended for production use.** Use the historical and streaming endpoints for production-level enrichment.\n\n\nFor optimal performance, adhere to the following limits: \n  - Submit no more than 4 unique users per request. Users are distinguished by the `uid` field in each transaction. \n  - Submit no more than 16 transactions per user per request if sending multiple users. Send no more than 128 if sending a single user.\n",
        "operationId": "syncCleanupTransactions",
        "security": [
          {
            "Authentication": [
              "enrichment"
            ]
          }
        ],
        "requestBody": {
          "description": "Transactions",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CleanupPostRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "enrichedTransactions": {
                      "type": "object",
                      "properties": {
                        "enriched": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "accountid": {
                                "description": "The ID of the account associated with the transaction",
                                "type": "string"
                              },
                              "amountnum": {
                                "description": "The transaction's USD amount",
                                "type": "number"
                              },
                              "category": {
                                "description": "The most applicable categorization for the transaction",
                                "type": "string"
                              },
                              "categoryId": {
                                "description": "The numeric ID of the transaction's category",
                                "type": "number"
                              },
                              "categoryLabel": {
                                "description": "A cascading hierarchy of the transaction's categories, from high-level to detail-level categorization. This field is deprecated and not recommended for use, as it may not reflect more correct information available in other 'category' fields.",
                                "type": "array",
                                "deprecated": true,
                                "items": {
                                  "type": "string"
                                }
                              },
                              "client_id": {
                                "type": "string",
                                "description": "Your FinGoal client ID"
                              },
                              "container": {
                                "description": "A high-level categorization of the account type. Eg, 'bank'",
                                "type": "string"
                              },
                              "date": {
                                "description": "The date on which the transaction took place",
                                "type": "string",
                                "format": "date-time"
                              },
                              "detailCategoryId": {
                                "description": "The numeric ID of the transaction's detail category",
                                "type": "number"
                              },
                              "guid": {
                                "description": "The transaction's globally unique FinSight API issued ID",
                                "type": "string"
                              },
                              "highLevelCategoryId": {
                                "description": "The numeric ID of the transaction's high level category",
                                "type": "number"
                              },
                              "isPhysical": {
                                "description": "Whether the transaction was made at a physical location, or online",
                                "type": "boolean"
                              },
                              "isRecurring": {
                                "deprecated": true,
                                "description": "This field is deprecated. Denotes whether the transaction is set to recur on a fixed interval",
                                "type": "boolean"
                              },
                              "merchantAddress1": {
                                "description": "The street address of the merchant associated with the transaction",
                                "type": "string"
                              },
                              "merchantCity": {
                                "description": "The name of the city where the merchant is located",
                                "type": "string"
                              },
                              "merchantCountry": {
                                "description": "The name of the country where the merchant is located",
                                "type": "string"
                              },
                              "merchantLatitude": {
                                "description": "The latitude of the merchant",
                                "type": "string"
                              },
                              "merchantLogoURL": {
                                "description": "The URL resource for the merchant's logo",
                                "type": "string"
                              },
                              "merchantLongitude": {
                                "description": "The longitude of the merchant",
                                "type": "string"
                              },
                              "merchantName": {
                                "description": "The name of the merchant associated with the transaction",
                                "type": "string"
                              },
                              "merchantPhoneNumber": {
                                "description": "The phone number of the merchant associated with the transaction",
                                "type": "string"
                              },
                              "merchantState": {
                                "description": "The name of the state where the merchant is located",
                                "type": "string"
                              },
                              "merchantType": {
                                "description": "The merchant's type",
                                "type": "string"
                              },
                              "merchantZip": {
                                "type": "string",
                                "description": "The ZIP code where the merchant is located"
                              },
                              "original_description": {
                                "description": "The transaction description as received. This will not change",
                                "type": "string"
                              },
                              "receiptDate": {
                                "description": "The date on which FinSight API first received the transaction",
                                "type": "string",
                                "format": "date-time"
                              },
                              "requestId": {
                                "description": "A unique ID for the request the transaction came in with, for debugging purposes",
                                "type": "string"
                              },
                              "simple_description": {
                                "description": "An easy-to-understand, plain-language transaction description",
                                "type": "string",
                                "deprecated": true
                              },
                              "simpleDescription": {
                                "description": "An easy-to-understand, plain-language transaction description",
                                "type": "string"
                              },
                              "sourceId": {
                                "description": "The source of the transaction",
                                "type": "string"
                              },
                              "subType": {
                                "description": "A more detailed classification that provides further information on the type of transaction.",
                                "type": "string"
                              },
                              "tenant_id": {
                                "description": "The ID of the tenant associated with this transaction, if one was included.",
                                "type": "string"
                              },
                              "transactionid": {
                                "description": "The ID of the transaction as it was originally submitted",
                                "type": "string"
                              },
                              "transactionTags": {
                                "description": "The FinSight API issued tags for the transaction",
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "type": {
                                "description": "An attribute describing the nature of the intent behind the transaction.",
                                "type": "string"
                              },
                              "uid": {
                                "description": "The ID of the user associated with the transaction, as originally submitted",
                                "type": "string"
                              }
                            }
                          }
                        },
                        "failed": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "amountnum": {
                                "description": "The transaction's USD amount",
                                "type": "number"
                              },
                              "settlement": {
                                "description": "The settlement type of the transaction (e.g., 'debit' or 'credit')",
                                "type": "string"
                              },
                              "original_description": {
                                "description": "The transaction description as received. This will not change",
                                "type": "string"
                              },
                              "transactionid": {
                                "description": "The ID of the transaction as it was originally submitted",
                                "type": "string"
                              },
                              "date": {
                                "description": "The date on which the transaction took place",
                                "type": "string",
                                "format": "date-time"
                              },
                              "accountType": {
                                "description": "The type of account (e.g., 'checking')",
                                "type": "string"
                              },
                              "uid": {
                                "description": "The ID of the user associated with the transaction, as originally submitted",
                                "type": "string"
                              },
                              "error_message": {
                                "type": "string",
                                "description": "A message describing why the transaction failed to enrich."
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request. An array of errors in the data will be returned. Fields not allowed or incorrectly formatted will be noted."
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/cleanup": {
      "post": {
        "tags": [
          "Enrichment"
        ],
        "summary": "Historical Transaction Enrichment",
        "description": "The historical transaction enrichment endpoint is designed for enriching a large number of transactions. It is optimized to handle substantial payloads and efficiently process large backlogs of data.\n\nThis endpoint is asynchronous. A webhook will be sent to the provided URL when a batch of transactions has been enriched.\n    \nTo maximize throughput for this endpoint, follow these guidelines: \n  - Group transactions by `uid` and include all transactions for a single `uid` in the same payload.\n  - Limit each request to approximately 1,000 transactions. The payload can include multiple uids. \n",
        "operationId": "asyncCleanupTransactions",
        "security": [
          {
            "Authentication": [
              "enrichment"
            ]
          }
        ],
        "requestBody": {
          "description": "Transactions",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CleanupPostRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CleanupPost200Response"
                }
              }
            }
          },
          "400": {
            "description": "Bad request. An array of errors in the data will be returned. Fields not allowed or incorrectly formatted will be noted."
          },
          "401": {
            "description": "Unauthorized"
          }
        },
        "callbacks": {
          "enrichment_result": {
            "https://YOUR_CALLBACK_URI": {
              "post": {
                "security": [],
                "summary": "Enrichment Webhook",
                "parameters": [
                  {
                    "name": "X-Webhook-Verification",
                    "in": "header",
                    "required": true,
                    "schema": {
                      "type": "string"
                    },
                    "description": "A SHA-256 HMAC signature of the webhook payload that can be used to verify the authenticity of the webhook."
                  }
                ],
                "requestBody": {
                  "required": true,
                  "content": {
                    "application/json": {
                      "schema": {
                        "$ref": "#/components/schemas/EnrichmentNotificationPostRequest"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/cleanup/streaming": {
      "post": {
        "tags": [
          "Enrichment"
        ],
        "summary": "Streaming Transaction Enrichment",
        "description": "FinGoal's streaming transaction enrichment endpoint is designed for enriching daily user transactions or other smaller transaction batches. \n\nUnlike the historical transaction enrichment endpoint, the streaming transaction enrichment endpoint does not require any user segmentation. Requests that include many users (by uid) will not deteriorate the endpoint's performance.\n\nThis endpoint is asynchronous. A webhook will be sent to the provided URL when a batch of transactions has been enriched. For larger transaction sets, such as historical data, user the historical enrichment endpoint.\n\nTo maximize throughput for this endpoint, follow these guidelines: \n  - Group transactions by \"uid\" and include all transactions for a single user in the same payload.\n  - Limit each request to a total of approximately 1,000 transactions. \n  - Transactions can be distributed among any number of users as long as the total number of transactions does not exceed 1,000.\n",
        "operationId": "streamingCleanupTransactions",
        "security": [
          {
            "Authentication": [
              "enrichment"
            ]
          }
        ],
        "requestBody": {
          "description": "Transactions",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CleanupPostRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CleanupPost200Response"
                }
              }
            }
          },
          "400": {
            "description": "Bad request. An array of errors in the data will be returned. Fields not allowed or incorrectly formatted will be noted."
          },
          "401": {
            "description": "Unauthorized"
          }
        },
        "callbacks": {
          "enrichment_result": {
            "https://YOUR_CALLBACK_URI": {
              "post": {
                "security": [],
                "summary": "Enrichment Complete Notification",
                "parameters": [
                  {
                    "name": "X-Webhook-Verification",
                    "in": "header",
                    "required": true,
                    "schema": {
                      "type": "string"
                    },
                    "description": "A SHA-256 HMAC signature of the webhook payload that can be used to verify the authenticity of the webhook."
                  }
                ],
                "requestBody": {
                  "required": true,
                  "content": {
                    "application/json": {
                      "schema": {
                        "$ref": "#/components/schemas/EnrichmentNotificationPostRequest"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/cleanup/base": {
      "post": {
        "tags": [
          "Enrichment"
        ],
        "summary": "Base Transaction Enrichment",
        "description": "FinGoal's base transaction enrichment endpoint is a new and improved model for enriching daily user, historical, or one off user transactions. It accepts additional `accountTypes` that previous enrichment endpoints did not, including `businessChecking`, `businessSavings`, `businessCreditCard`, `businessLoan`, `loan`, `investments`.\n\nRequests that include many users (by uid) will not deteriorate the endpoint's performance and it has much higher throughput than previous enrichment endpoints. \n\nThis endpoint is asynchronous. A webhook will be sent to the provided URL when a batch of transactions has been enriched.\n\nTo maximize throughput for this endpoint, follow these guidelines: \n  - Limit each request to a total of approximately 1,000 transactions. \n  - Transactions can be distributed among any number of users as long as the total number of transactions does not exceed 1,000.\n",
        "operationId": "baseCleanupTransactions",
        "security": [
          {
            "Authentication": [
              "enrichment"
            ]
          }
        ],
        "requestBody": {
          "description": "Transactions",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "transactions"
                ],
                "properties": {
                  "transactions": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": [
                        "accountType",
                        "amountnum",
                        "date",
                        "original_description",
                        "transactionid",
                        "settlement",
                        "uid"
                      ],
                      "properties": {
                        "accountType": {
                          "type": "string",
                          "description": "The type of account associated with the transaction.\n",
                          "enum": [
                            "checking",
                            "savings",
                            "creditCard",
                            "businessChecking",
                            "businessSavings",
                            "businessCreditCard",
                            "businessLoan",
                            "loan",
                            "investments"
                          ],
                          "example": "checking"
                        },
                        "amountnum": {
                          "type": "number",
                          "maxLength": 11,
                          "description": "The transaction amount in USD. Negative amounts are automatically converted to positive amounts. Use the 'settlement' field to indicate whether the transaction was a 'debit' or 'credit'. The string representation of amount must be fewer than 11 characters.",
                          "example": 19.99
                        },
                        "date": {
                          "description": "The date of the transaction. Must be in the format 'YYYY-MM-DD'.",
                          "type": "string",
                          "format": "date",
                          "example": "2024-05-01"
                        },
                        "identifiers": {
                          "description": "A JSON representation of alternative user IDs. This field is designed exclusively for users with Banno, Salesforce, or other CRM integrations. Valid identifiers are currently limited to [`sfmc_contact_id`, `banno_end_user_id`].",
                          "type": "object",
                          "properties": {
                            "sfmc_contact_id": {
                              "type": "string",
                              "example": "sfmc-1234"
                            },
                            "banno_end_user_id": {
                              "type": "string",
                              "example": "banno-1234"
                            }
                          }
                        },
                        "original_description": {
                          "description": "The transaction's description. Must be between 3 and 198 characters. Descriptions longer than 198 characters are automatically truncated.\n",
                          "minLength": 1,
                          "maxLength": 198,
                          "type": "string",
                          "example": "Cottonwood Supermarket & Deli"
                        },
                        "transactionid": {
                          "description": "A unique identifier for the transaction. Do not use PII or other information-rich data in this field. We strongly recommend using UUID or a similar identification system.",
                          "maxLength": 100,
                          "type": "string",
                          "example": "178b1f61-dafe-4d47-837b-54ce34dc82b2"
                        },
                        "settlement": {
                          "description": "Indicates whether the transaction was a 'debit' or 'credit' to the account.",
                          "type": "string",
                          "enum": [
                            "debit",
                            "credit"
                          ],
                          "example": "debit"
                        },
                        "uid": {
                          "description": "The ID of the user associated with the transaction. User IDs must be unique. Do not use PII or other information-rich data in this field. We strongly recommend using UUID or a similar identification system.",
                          "maxLength": 50,
                          "type": "string",
                          "example": "user123"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CleanupPost200Response"
                }
              }
            }
          },
          "400": {
            "description": "Bad request. An array of errors in the data will be returned. Fields not allowed or incorrectly formatted will be noted."
          },
          "401": {
            "description": "Unauthorized"
          }
        },
        "callbacks": {
          "enrichment_result": {
            "https://YOUR_CALLBACK_URI": {
              "post": {
                "security": [],
                "summary": "Enrichment Complete Notification",
                "parameters": [
                  {
                    "name": "X-Webhook-Verification",
                    "in": "header",
                    "required": true,
                    "schema": {
                      "type": "string"
                    },
                    "description": "A SHA-256 HMAC signature of the webhook payload that can be used to verify the authenticity of the webhook."
                  }
                ],
                "requestBody": {
                  "required": true,
                  "content": {
                    "application/json": {
                      "schema": {
                        "$ref": "#/components/schemas/EnrichmentNotificationPostRequest"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/cleanup/{batch_request_id}": {
      "get": {
        "tags": [
          "Enrichment"
        ],
        "summary": "Retrieve Enrichment by Batch Request ID",
        "description": "Developers may use this endpoint in conjunction with the [asynchronous cleanup endpoints](#operation/asyncCleanupTransactions) to retrieve the results of a transaction cleanup operation by its batch operation ID.\nThe operation ID can be extracted from the webhook that the async cleanup endpoint sends when enrichment is complete.  \n",
        "operationId": "getEnrichment",
        "security": [
          {
            "Authentication": [
              "enrichment"
            ]
          }
        ],
        "parameters": [
          {
            "name": "batch_request_id",
            "in": "path",
            "description": "The Batch Request ID of the enrichment request.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookConfigurationsTestPostENRICHMENT_DATA"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "No transactions found for the given request id."
          }
        }
      }
    },
    "/users/{userId}": {
      "get": {
        "parameters": [
          {
            "name": "userId",
            "in": "path",
            "required": true,
            "description": "The ID for the user you want to retrieve.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "include_tagged_transactions",
            "in": "header",
            "required": false,
            "deprecated": true,
            "schema": {
              "type": "string",
              "description": "This field has been deprecated. Tagged transactions are received automatically from the enrichment API. Set to true to include all of the user's tagged transactions in the response. By default, tagged transactions are not included."
            }
          }
        ],
        "tags": [
          "User Tagging"
        ],
        "summary": "Get a User",
        "description": "<strong style=\"color:red;\">This endpoint runs on data sent to the Transaction Enrichment endpoints. Tagging is run in batches twice daily and thus not available immediately after posting transactions. Also, in order to receive user tags, transaction dates must be within the past 90 days.</strong>\n<br/>\n<br />\nFetches user and transaction tags for a specified user ID. Both endpoints return the same schema. Use the sync keyword to trigger a manual update on the transaction and user tags for a single user.\n",
        "operationId": "getOneUser",
        "security": [
          {
            "Authentication": [
              "read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "user"
                  ],
                  "properties": {
                    "user": {
                      "type": "object",
                      "required": [
                        "uid"
                      ],
                      "properties": {
                        "client_id": {
                          "type": "string",
                          "description": "Your client ID."
                        },
                        "id": {
                          "type": "string",
                          "description": "The user ID."
                        },
                        "uid": {
                          "type": "string",
                          "description": "The user's ID."
                        },
                        "uniqueId": {
                          "type": "string",
                          "description": "The user's unique ID in the format of `client_id:uid`."
                        },
                        "lifetimeSavings": {
                          "type": "number",
                          "description": "The user's lifetime savings, if known."
                        },
                        "registrationDate": {
                          "type": "string",
                          "format": "date-time",
                          "description": "The date on which the user was registered with FinSight API."
                        },
                        "subtenantId": {
                          "type": "string",
                          "description": "The user's subtenant ID."
                        },
                        "tags": {
                          "description": "The FinSight API tags that were applied to the user.",
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "totaltransactions": {
                          "type": "number",
                          "description": "The total number of transactions the user has in FinSight API."
                        },
                        "transactionsSinceLastUpdate": {
                          "type": "number",
                          "description": "The number of transactions since the last time insights were run for the user."
                        }
                      }
                    },
                    "transactions": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "transaction_id": {
                            "type": "string",
                            "description": "The ID of the transaction."
                          },
                          "simple_description": {
                            "type": "string",
                            "description": "A human-readable, simplified description for the transaction."
                          },
                          "original_description": {
                            "type": "string",
                            "description": "The originally-submitted description of the transaction."
                          },
                          "category": {
                            "type": "string",
                            "description": "The category of the transaction."
                          },
                          "amount": {
                            "type": "number",
                            "description": "The transaction's amount in USD."
                          },
                          "date": {
                            "type": "string",
                            "format": "date-time",
                            "description": "The date of the transaction."
                          },
                          "tags": {
                            "type": "array",
                            "items": {
                              "type": "string",
                              "description": "The tags that were applied to the transaction."
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "User ID could not be found"
          }
        }
      }
    },
    "/users/{userId}/sync": {
      "get": {
        "parameters": [
          {
            "name": "userId",
            "in": "path",
            "required": true,
            "description": "The ID for the user you want to retrieve.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "include_tagged_transactions",
            "in": "header",
            "required": false,
            "deprecated": true,
            "schema": {
              "type": "string",
              "description": "This field has been deprecated. Tagged transactions are received automatically from the enrichment API. Set to true to include all of the user's tagged transactions in the response. By default, tagged transactions are not included."
            }
          }
        ],
        "tags": [
          "User Tagging"
        ],
        "summary": "Trigger a User Tag Update",
        "description": "<strong style=\"color:red;\">This endpoint runs on data sent to the Transaction Enrichment endpoints. Tagging is run in batches twice daily and thus not available immediately after posting transactions. Also, in order to receive user tags, transaction dates must be within the past 90 days.</strong>\n<br/>\n<br />\nFetches user and transaction tags for a specified user ID. Both endpoints return the same schema. Use the sync keyword to trigger a manual update on the transaction and user tags for a single user.\n",
        "operationId": "getOneUserSync",
        "security": [
          {
            "Authentication": [
              "enrichment",
              "calls_to_action"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UsersUserIdGet200Response"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "User ID could not be found"
          }
        }
      }
    },
    "/users/tags/{guid}": {
      "get": {
        "parameters": [
          {
            "name": "guid",
            "in": "path",
            "required": true,
            "description": "The guid for the updates you want to retrieve.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "tags": [
          "User Tagging"
        ],
        "summary": "Retrieve Updated Tags",
        "description": "If you subscribe to the user tag status updates, you can retrieve them from this endpoint with the `guid` you received from the status update webhook. The tag updates will stay live at this endpoint for 24 hours. \n",
        "operationId": "getUserTagUpdates",
        "security": [
          {
            "Authentication": [
              "read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookConfigurationsTestPostUSER_TAGS_DATA"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "User ID could not be found"
          }
        }
      }
    },
    "/webhook-configurations": {
      "get": {
        "tags": [
          "Webhook Configurations"
        ],
        "summary": "List Webhook Configurations",
        "description": "Retrieve all webhook configurations for your client. Configurations are organized into:\n- **default**: Configurations without a tenant_id that apply to your client's default callback URL\n- **tenants**: Tenant-specific configurations organized by tenant_id\n",
        "operationId": "listWebhookConfigurations",
        "security": [
          {
            "Authentication": [
              "enrichment"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "Successfully retrieved webhook configurations.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "webhook_configurations": {
                      "type": "object",
                      "description": "All webhook configurations for your client, organized by scope.",
                      "properties": {
                        "client": {
                          "type": "array",
                          "description": "Default webhook configurations (no tenant_id). These apply when no tenant-specific configuration exists.",
                          "items": {
                            "$ref": "#/components/schemas/WebhookConfigurationsPut200Response"
                          }
                        },
                        "by_tenant": {
                          "type": "object",
                          "description": "Tenant-specific webhook configurations. Keys are tenant public IDs, values are arrays of configurations for that tenant.",
                          "additionalProperties": {
                            "type": "array",
                            "items": {
                              "$ref": "#/components/schemas/WebhookConfigurationsPut200Response"
                            }
                          },
                          "example": {
                            "TEN-123456": [
                              {
                                "id": 2,
                                "client_id": "your-client-id",
                                "tenant_id": "TEN-123456",
                                "webhook_type": "ENRICHMENT_DATA",
                                "callback_url": "https://tenant-specific.com/webhooks/enrichment",
                                "created_at": "2024-01-15T11:00:00.000Z",
                                "updated_at": "2024-01-15T11:00:00.000Z"
                              }
                            ]
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "client_id header is required."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Missing required `enrichment` scope."
          }
        }
      },
      "put": {
        "tags": [
          "Webhook Configurations"
        ],
        "summary": "Create or Update Webhook Configuration",
        "description": "Create a new webhook configuration or update an existing one. Your `client_id` and `tenant_id` are automatically inferred from the bearer token on this request. To set up a webhook for a specific tenant, please ensure that the bearer token on this request as a `tenant_id` claim. If your bearer token lacks a `tenant_id`, the webhook will be created for your single-tenant environment.\n\n- If a configuration already exists for the same client/tenant/webhook_type combination, it will be updated.\n- If `tenant_id` is provided, your client must have a relationship with that tenant.\n- Omit `tenant_id` to set the default callback URL for your client.\n",
        "operationId": "upsertWebhookConfiguration",
        "security": [
          {
            "Authentication": [
              "enrichment"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "webhook_type",
                  "callback_url"
                ],
                "properties": {
                  "webhook_type": {
                    "$ref": "#/components/schemas/WebhookConfigurationsPutRequest"
                  },
                  "callback_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Valid HTTPS URL for webhook delivery.",
                    "example": "https://your-server.com/webhooks/enrichment"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook configuration created or updated successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "webhook_configuration": {
                      "$ref": "#/components/schemas/WebhookConfigurationsPut200Response"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request. Possible errors:\n- `client_id header is required`\n- `webhook_type is required`\n- `Invalid webhook_type`\n- `callback_url is required`\n- `callback_url must be a valid URL`\n"
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden. Possible errors:\n- Missing `enrichment` scope\n- Client does not have a relationship with the specified tenant\n"
          }
        }
      },
      "delete": {
        "tags": [
          "Webhook Configurations"
        ],
        "summary": "Delete Webhook Configuration",
        "description": "Remove a webhook configuration.\n\n- Specify `tenant_id` to delete a tenant-specific configuration.\n- Omit `tenant_id` to delete the default configuration.\n",
        "operationId": "deleteWebhookConfiguration",
        "security": [
          {
            "Authentication": [
              "enrichment"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "webhook_type"
                ],
                "properties": {
                  "webhook_type": {
                    "$ref": "#/components/schemas/WebhookConfigurationsPutRequest"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook configuration deleted successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "boolean",
                      "description": "Whether the configuration was successfully deleted.",
                      "example": true
                    },
                    "id": {
                      "type": "integer",
                      "description": "The ID of the deleted configuration.",
                      "example": 1
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request. Possible errors:\n- `client_id header is required`\n- `webhook_type is required`\n- `Invalid webhook_type`\n"
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Missing required `enrichment` scope."
          },
          "404": {
            "description": "Webhook configuration not found."
          }
        }
      }
    },
    "/webhook-configurations/test": {
      "post": {
        "tags": [
          "Webhook Configurations"
        ],
        "summary": "Test Webhook",
        "description": "Test your webhook endpoint by triggering a sample payload. Useful for verifying your webhook receiver is working correctly.\n\nThe test payload varies by webhook type:\n- **ENRICHMENT_DATA**: Sample enriched transactions payload\n- **ENRICHMENT_NOTIFICATION**: Sample batch notification with batch_request_id\n- **USER_TAGS_DATA**: Sample user tags payload with created/deleted/modified arrays\n- **USER_TAGS_NOTIFICATION**: Sample notification with guid\n- **INSIGHTS**: Sample finsights array\n\nAll test webhooks include the `X-Webhook-Verification` header for signature verification testing.\n",
        "operationId": "testWebhook",
        "security": [
          {
            "Authentication": [
              "enrichment"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "webhook_type",
                  "callback_url"
                ],
                "properties": {
                  "webhook_type": {
                    "$ref": "#/components/schemas/WebhookConfigurationsPutRequest"
                  },
                  "callback_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "URL to send the test payload to.",
                    "example": "https://your-server.com/webhooks/enrichment"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Test webhook result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "description": "Whether the test webhook was successfully delivered.",
                      "example": true
                    },
                    "status": {
                      "type": "integer",
                      "description": "The HTTP status code returned by the callback URL.",
                      "example": 200
                    },
                    "message": {
                      "type": "string",
                      "description": "A message describing the result of the test.",
                      "example": "Test webhook sent successfully"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request. Possible errors:\n- `client_id header is required`\n- `webhook_type is required`\n- `Invalid webhook_type`\n- `callback_url is required`\n- `callback_url must be a valid URL`\n"
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Missing required `enrichment` scope."
          }
        },
        "x-webhook-payloads": {
          "ENRICHMENT_DATA": {
            "description": "Data-rich Transaction Enrichment webhook payload.",
            "schema": {
              "$ref": "#/components/schemas/WebhookConfigurationsTestPostENRICHMENT_DATA"
            }
          },
          "ENRICHMENT_NOTIFICATION": {
            "description": "Non-data-rich Enrichment notification payload.",
            "schema": {
              "type": "object",
              "properties": {
                "batch_request_id": {
                  "type": "string",
                  "format": "uuid",
                  "description": "UUID to fetch enriched data from the `/cleanup/{batch_request_id}` endpoint."
                },
                "client_id": {
                  "type": "string",
                  "description": "Your client identifier."
                },
                "tenant_id": {
                  "type": "string",
                  "description": "Tenant identifier (if tenant-specific)."
                }
              }
            }
          },
          "USER_TAGS_DATA": {
            "description": "Data-rich User Tags webhook payload.",
            "schema": {
              "$ref": "#/components/schemas/WebhookConfigurationsTestPostUSER_TAGS_DATA"
            }
          },
          "USER_TAGS_NOTIFICATION": {
            "description": "Non-data-rich User Tags notification payload.",
            "schema": {
              "type": "object",
              "properties": {
                "guid": {
                  "type": "string",
                  "format": "uuid",
                  "description": "UUID to fetch tag data from the `/users/tags/{guid}` endpoint."
                },
                "tenant_id": {
                  "type": "string",
                  "description": "Tenant identifier (if tenant-specific)."
                }
              }
            }
          },
          "INSIGHTS": {
            "description": "Finsights webhook payload.",
            "schema": {
              "type": "object",
              "properties": {
                "finsights": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "finsight_id": {
                        "type": "string",
                        "format": "uuid",
                        "description": "Unique identifier for this finsight."
                      },
                      "uniqueId": {
                        "type": "string",
                        "description": "Unique identifier linking to the source."
                      },
                      "transaction_id": {
                        "type": "string",
                        "description": "Related transaction identifier."
                      },
                      "user_id": {
                        "type": "string",
                        "description": "User identifier."
                      },
                      "insight_text": {
                        "type": "string",
                        "description": "Human-readable insight/advice text."
                      },
                      "insight_ctaurl": {
                        "type": "string",
                        "nullable": true,
                        "description": "Call-to-action URL (if applicable)."
                      },
                      "finsight_image": {
                        "type": "string",
                        "nullable": true,
                        "description": "Image URL (if applicable)."
                      },
                      "recommendation": {
                        "type": "string",
                        "nullable": true,
                        "description": "Actionable recommendation."
                      },
                      "amountFound": {
                        "type": "number",
                        "description": "Dollar amount related to the insight."
                      },
                      "category": {
                        "type": "string",
                        "description": "Transaction category."
                      },
                      "amountnum": {
                        "type": "number",
                        "description": "Transaction amount."
                      },
                      "estimatedSavingsType": {
                        "type": "string",
                        "description": "Savings estimation period (e.g., \"monthly\")."
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}