Create transaction
Create a single transaction on an account. `amountValue` is a signed decimal string: negative for money leaving the account, positive for money arriving. `categorizations` can be supplied inline to book it in one call, and their amounts must sum to the transaction amount or the row counts as open. Accounts owned by an integration that does not allow manual edits reject this with 422, and an account that already has an opening balance rejects a second initial-balance row with 409. For more than a handful of rows, use `/transactions/import`.
Authentication
sf_… API key in the bearerAuth field below.A SaaSFlow API key (format sf_…) or an OAuth bearer token. Paste only the key — the proxy adds the Bearer prefix. Create an API key in Settings → Company settings → API keys — see API keys.
In: header
Path Parameters
1 <= lengthRequest Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
curl -X POST "https://example.com/companies/string/transactions" \ -H "Content-Type: application/json" \ -d '{ "accountId": "string", "date": "string", "amountValue": "string", "amountCurrency": "string" }'{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "companyId": "8bb73d03-06b4-47c7-80c7-59301f770eda", "accountId": "3d07c219-0a88-45be-9cfc-91e9d095a1e9", "date": "string", "fromTo": "string", "description": "string", "amountValue": "string", "amountCurrency": "EUR", "categorizationsAutoAssigned": true, "excludeFromAutoCategorization": true, "notes": "string", "source": "string", "assignedUserId": "string", "finApiTransactionId": "string", "plaidTransactionId": "string", "stripeBalanceTransactionId": "string", "stripeInvoiceId": "string", "stripeCreditNoteId": "string", "stripePaymentIntentId": "string", "stripeBillingEmail": "string", "hubspotPortalId": "string", "hubspotInvoiceId": "string", "hubspotCategorizationResolved": true, "finwayExpenseNumber": "string", "finwayInvoiceNumber": "string", "pleoExpenseId": "string", "createdVendorId": "91002d41-22cb-48a3-bc93-148a8439ef7f", "integrationId": "497a18ca-284e-40c0-985d-f72be35d468e", "pending": true, "createdTime": "2019-08-24T14:15:22Z", "createdUserId": "string", "lastUpdatedTime": "2019-08-24T14:15:22Z", "lastUpdatedUserId": "string", "categorizations": { "property1": { "counterparty": { "type": "customer", "id": "string" }, "categoryId": "string", "usingDateRule": { "type": "transactionDate" }, "computedStartDate": "2019-08-24", "computedEndDate": "2019-08-24", "plSplit": { "revenue": 0, "cogs": 0, "cac": 0, "pd": 0, "ga": 0, "no": 0, "neutral": 0 }, "passThroughTax": 0, "transferCounterPosition": { "transactionId": "string", "categorizationId": "string" }, "internalTransitLink": { "transactionId": "string", "categorizationId": "string" }, "sourceNote": "string", "externalInvoiceUrn": "string" }, "property2": { "counterparty": { "type": "customer", "id": "string" }, "categoryId": "string", "usingDateRule": { "type": "transactionDate" }, "computedStartDate": "2019-08-24", "computedEndDate": "2019-08-24", "plSplit": { "revenue": 0, "cogs": 0, "cac": 0, "pd": 0, "ga": 0, "no": 0, "neutral": 0 }, "passThroughTax": 0, "transferCounterPosition": { "transactionId": "string", "categorizationId": "string" }, "internalTransitLink": { "transactionId": "string", "categorizationId": "string" }, "sourceNote": "string", "externalInvoiceUrn": "string" } }}List transactions
List transactions, paginated, with their categorizations attached. This is the simple listing: filter by account, or by `status: "uncategorized"` for rows with no categorization at all. For anything richer (date ranges, amounts, counterparties, categories, free text, sorting) use `POST /transactions/search`, whose `open` status is also broader than `uncategorized` here. Do not aggregate by paging through this endpoint; the `data` slices compute totals server-side.
Search
Search transactions with sorting and a composable filter set. It is a POST because the filter array is too structured for a query string, not because it changes anything. Each entry in `filters` is active simply by being present, and they combine with AND. This is the endpoint behind the transactions table in the app, so use it whenever the plain list is not enough. `balanceByDate` gives the running end-of-day balance and is only filled in when the page covers a single account and `sortBy` is `date`.