# finmid Documentation > finmid's Developer Portal ## Guides - [finmid products](https://docs.finmid.com/docs/finmid-products.md): Welcome to finmid products introduction! Dive into our API documentation to embed lending services into your product! - [Core concepts](https://docs.finmid.com/docs/b2b-payments-core-concepts.md) - [End-to-end process](https://docs.finmid.com/docs/end-to-end.md) - [Fees configuration](https://docs.finmid.com/docs/fees-config.md) - [Buyer/Seller onboarding flow](https://docs.finmid.com/docs/buyer-seller-onboarding.md) - [Payment flow](https://docs.finmid.com/docs/payment-flow.md) - [Capture flow](https://docs.finmid.com/docs/capture-flow.md) - [Webhooks](https://docs.finmid.com/docs/webhooks.md): Webhooks are used to notify your platform about events on finmid side. finmid sends these notifications to an endpoint hosted in your environment configured to receive and process them. - [Errors](https://docs.finmid.com/docs/b2b-payments-errors.md): B2B Payments API error codes and descriptions - [Capital core concepts](https://docs.finmid.com/docs/capital-core-concepts.md) - [Overview of Capital integration](https://docs.finmid.com/docs/capital-end-to-end.md) - [Pre-approved Offer generation](https://docs.finmid.com/docs/capital-preapproved-offer-generation.md): We generate pre-approved customizable Offers with over 95% payout certainty in real-time, and communicate results to the Platforms via webhook. - [Offer sharing & acceptance](https://docs.finmid.com/docs/capital-offer-sharing-and-acceptance.md): This section explains how Platforms can retrieve detailed Offer information and communicate Offers to Businesses. It also highlights how Businesses can accept Offers through an embedded widget. - [Business onboarding & payout](https://docs.finmid.com/docs/capital-business-onboarding-and-payout.md) - [Business payments](https://docs.finmid.com/docs/capital-business-payments.md): This section outlines how Business Payments are calculated as a percentage of sales and facilitated through Platform-managed flows or direct debit by finmid. - [Renewals](https://docs.finmid.com/docs/capital-renewals.md) - [Webhooks](https://docs.finmid.com/docs/capital-webhooks.md): Webhooks are used to notify your platform about events on finmid side. finmid sends these notifications to an endpoint hosted in your environment configured to receive and process them. - [Widget integration](https://docs.finmid.com/docs/capital-iframe.md): Capital API iframe widget integration - [Domain Delegation](https://docs.finmid.com/docs/domain-delegation.md) - [Setup with GoDaddy Domain Registrar](https://docs.finmid.com/docs/godaddy-domain-registrar.md) - [Setup with Amazon Domain Registrar](https://docs.finmid.com/docs/amazon-registrar.md) - [API introduction](https://docs.finmid.com/docs/api-introduction.md) ## API Reference - [API introduction](https://docs.finmid.com/reference/api-introduction.md) - [Create Buyer](https://docs.finmid.com/reference/create-buyer-v2.md): Let's create/onboard a new buyer. For this you'll need 2 things: 1. Create a new ID for this buyer (should map to your internal identifier) 2. The buyer's legal information. ⚠️ Note that one of either business_registration_number or tax_number **must** be provided on creation. > 📘 > > You should create a buyer entity for every buyer on your platform that can be part of a lending transaction. - [Get Buyer](https://docs.finmid.com/reference/get-buyer-v2.md): For getting a certain buyer's details, you'll only need the buyer's ID specified on creation. - [Update Buyer](https://docs.finmid.com/reference/update-buyer-v2.md): Update a buyer if certain data changes on your platform. For this you'll need: 1. The buyer's ID specified on creation 2. The data you want to change - [Get Buyer Limit](https://docs.finmid.com/reference/get-buyer-limit-v2.md): Get estimated buyer limit in a target currency. > 📘 > > Note: this limit is an estimate and subject to change depending on a specific payment request parameters. To verify if specific purchase can be financed please use [Check Payment Request API](../reference/check-payment-request-v2) - [Get Buyers](https://docs.finmid.com/reference/get-buyers-for-platform.md): Returns a list of buyers. Cursor-based pagination is supported and you can make use of filter parameters to change sorting or limit the results to only buyers with certain status.. - [Create Seller](https://docs.finmid.com/reference/create-seller-v2.md): Let's create/onboard a new seller. For this you'll need 2 things: 1. Create a new ID for this seller (should map to your internal identifier) 2. The seller's legal information. ⚠️ Note that one of either business_registration_number or tax_number **must** be provided on creation. > 📘 > > You should create a seller entity for every seller on your platform that can be part of a lending transaction. - [Get Seller](https://docs.finmid.com/reference/get-seller-v2.md): For getting a certain seller's details, you'll only need the seller's ID specified on creation. - [Update Seller](https://docs.finmid.com/reference/update-seller-v2.md): Update a seller if certain data changes on your platform. For this you'll need: 1. The seller's ID specified on creation 2. The data you want to change - [Update Seller Bank Account](https://docs.finmid.com/reference/update-seller-bank-account-v2.md): Update a seller's bank account details. For this you'll need: 1. The seller's ID specified on creation 2. The new bank account details. Note: This currently is only supported for sellers with a single bank account. - [Get Sellers](https://docs.finmid.com/reference/get-sellers-for-platform.md): Returns a list of sellers. Cursor-based pagination is supported and you can make use of filter parameters to change sorting or limit the results to only sellers with certain status.. - [Create Payment Request](https://docs.finmid.com/reference/create-payment-request-v2.md): The create payment request resource endpoint creates a loan and reserves the specified order amount. This process is called authorisations. When you authorise, finmid will generate a unique id that you'll use to reference the transaction moving forward. For creating a new payment request, you need the following things: 1. Create a new ID for this payment request (we recommend using the invoice number), 2. Choose repayment term days, 3. Buyer's ID specified on creation, 4. Seller ID 5. Total order amount. 7. (Optional) Invoice due date, which can be added now, or via the update endpoint. > ⚠️ Invoice Number > > Invoice number is optional upon payment request creation. However, it must be provided prior to capturing the payment request. Invoice number can be provided via the [Update Payment Request](../reference/update-payment-request-v2) endpoint - [Update Payment Request](https://docs.finmid.com/reference/update-payment-request-v2.md): Allows for the updating of invoice number and invoice due date fields. Invoice number must be provided to execute a payout. - [Cancel Payment Request](https://docs.finmid.com/reference/cancel-payment-request-v2.md): Cancels an existing payment request and releases the loan amount reserved for the payment. For this you'll only need the payment request ID specified on creation. > 📘 > > This operation is only permitted if the seller has captured no items in the order. Please note that cancelling a payment request is not reversible. - [Get Payment Requests](https://docs.finmid.com/reference/get-payment-requests-v2.md): Returns a list of payment requests. Cursor-based pagination is supported and you can make use of filter parameters to change sorting or limit the results to only payment requests with certain status. - [Get Payment Request](https://docs.finmid.com/reference/get-payment-request-v2.md): For getting a certain payment request's details, you'll only need the payment request's ID specified on creation. - [Create Payout](https://docs.finmid.com/reference/create-payment-request-payout.md): The payout payment request endpoint triggers a payment to the seller associated with the loan initially reserved during the creation of the payment request. As soon as a payout is created, the payment is processed immediately through finmid. After a payout is created, the payment request status will change to PROCESSING if the payment request amount is only partially paid. Once the max payout amount is fully paid out, the status will then change to PENDING_REPAYMENT. To create a payout for a certain payment request, you'll need four things: 1. The payment request ID specified during creation. 2. The Payout ID, a unique identifier within the payment request of your choice for this payout. 3. The payout type, which can be PERCENTAGE, AMOUNT, or MAX. 4. The payout value, which is related to the payout type and is only required for percentage and amount types. For instance, if the payout type is percentage and the value is 50, then 50% of the payment request will be paid out. The payout response body includes: - Gross amount: This is the total amount of the payout relative to the payment request including fees. - Net amount: This is the amount the seller actually receives, calculated as the gross amount minus fees. - Status: This reflects the state of the seller's payment, with three possible statuses: `PENDING`, `PAID_OUT`, and `REJECTED`. - [Upload payment documents](https://docs.finmid.com/reference/upload-payment-request-documents.md): Upload a list of documents for a task with entity type: `PAYMENT_REQUEST_TASK` the documents will then be used for the approval of payment request payouts during the spot checks process. Some documents that can be provided are: - Invoice - Order confirmation or sales contract - Shipping document or bill of lading - Other documents supporting your payment request Your documents must be in JPG, PNG, or PDF and no larger than 15.0 MB - [Get tasks](https://docs.finmid.com/reference/get-tasks.md): For getting the platform tasks, normally a task is created when there is a payment request that requires additional documents or when a buyer increase limit is requested. tasks are ordered by creation time descending meaning the newest task will be first. - [Simulate Buyer](https://docs.finmid.com/reference/simulate-buyer-v2.md): This endpoint allows you to simulate onboarding of buyers in the sandbox environment. After creation buyers have the status of `PENDING`. In a production environment finmid runs certain checks before a buyer is actually set `ACTIVE`. However, in the sandbox environment finmid does not run any checks nor sets the created buyer `ACTIVE` automatically. Use this API to onboard created buyers by setting their `status` to `ACTIVE`. Don't forget to set their `expense_limit` to a value greater `0` (e.g. `10000`) as well. You can also simulate other flows as well. For example setting the status to `REJECTED` to simulate rejection of a buyer. > 🚧 > > **Only available in sandbox environment.** - [Simulate Seller](https://docs.finmid.com/reference/simulate-seller-v2.md): This endpoint allows you to simulate onboarding of sellers in the sandbox environment. After creation sellers have the status of `PENDING`. In a production environment finmid runs certain checks before a seller is actually set `ACTIVE`. However, in the sandbox environment finmid does not run any checks nor sets the created seller `ACTIVE` automatically. Use this API to onboard created sellers by setting their `status` to `ACTIVE`. You can also simulate other flows as well. For example setting the status to `REJECTED` to simulate rejection of a seller. > 🚧 > > **Only available in sandbox environment.** - [Simulate Repayment](https://docs.finmid.com/reference/simulate-payment-request-repayment-v2.md): This endpoint simulates repayment of a payment request. The payment request status must be `PENDING_REPAYMENT`. > 🚧 > > **Only available in sandbox environment.** - [Get Funding Applications](https://docs.finmid.com/reference/get-funding-applications.md): This endpoint returns the Funding Applications for a Business. A Funding Application represents the intermediate step in the financing lifecycle: **Offer → Funding Application → Funding**. It is created when a Business accepts an Offer and captures the review process that determines whether a Funding will be issued. The lifecycle of a Funding Application is as follows: - `CREATED`: the Business has accepted an Offer and the funding application has been created. - `IN_REVIEW`: the business screening has begun and the funding application is under review - `APPROVED`: the review has passed and a Funding has been created. The `credit_id` field will contain the identifier of the resulting Funding. - `REJECTED`: the review has not passed and no Funding will be created for this application. - `CANCELLED`: the application was cancelled on business request before or after the Funding was issued. At any given time, there can be only one Funding Application that is not in a final state (APPROVED, REJECTED, or CANCELLED). ### Required Actions While a Funding Application is in `IN_REVIEW` status, the review process may require the business to take specific actions — for example, uploading documents. These are surfaced in the `required_actions` array. Each entry describes the type of action needed, the reason (which provides contextual information) and when it was requested. When required actions are present, the business automatically receives an email notification. The array is empty when no action is pending. The optional `status` query parameter allows filtering applications by their current status. - [Get Capital Max State](https://docs.finmid.com/reference/get-capital-max.md): This endpoint returns the Capital Max state for a Business. Capital Max allows a business to request additional capital beyond their standard funding. The response includes Capital Max configuration and a list of past and current applications ordered by `appliedAt DESC` The optional `application_status` query parameter allows filtering applications by their current status. The lifecycle of a Capital Max Application is as follows: - `IN_REVIEW`: the initial state of the resource. The associated offer group is deactivated to block the business from accepting previously generated offers. At any given time, there can be only one Funding Application in the `IN_REVIEW` state. - `APPROVED`: a new offer group has been generated with higher funding limits, becoming the active offer group. - `REJECTED`: the application was rejected and the offer group might or might not have been re-activated. > Hint: query the Active Offer Group to find out if it has been re-activated or not. - [Create Business](https://docs.finmid.com/reference/create-business.md): In order to access pre-approved Offers for Businesses, Platforms must first share non-PI data. This data is used to generate Offers, confirm receiving bank accounts with Businesses, and support the 2FA process used to accept Offers. - [Get Business](https://docs.finmid.com/reference/get-business.md): This endpoint allows Platforms to detect what data has been shared up to the current time for any specific Business. - [Update Business non-PI Data](https://docs.finmid.com/reference/update-business-non-pi.md): Update non-personally identifiable data for an existing Business. This endpoint can be used only for Businesses non-PI data updates. After KYB data is shared for a business this API will return an error. > 📘 > > Please note that this API is replacing all non-PI data for a Business. It is **not** a `PATCH` operation. - [Submit Business performance data](https://docs.finmid.com/reference/submit-business-performance-data.md): In order to generate Offers, finmid requires that Platforms share non-PI data on key Business performance indicators (e.g., goods sold, number of transactions, ratings, refund count, etc.). This data is used to confirm the Business's eligibility for an Offer and to determine the terms of the Offer. **Guidelines:** - Multiple data points across multiple months may be submitted in a single API call. - All data points within a single API call must be associated with the same Business ID. - An API request must include at least one performance indicator per reported date; a request with an empty indicator object will be considered invalid. - [Submit Business's KYB data](https://docs.finmid.com/reference/add-business-kyb-data.md): When a Business has accepted their Offer, the Platform is authorized to share their PI data with finmid. This data is necessary for finmid's KYB checks, which are required before the payout of the Funding to the Business. - [Upload KYB Document for a Business](https://docs.finmid.com/reference/create-kyb-business-document-upload.md): Create a document upload to provide Know Your Business (KYB) files for a business. This is a two-step flow: 1. **Create Upload** (this endpoint): Provide file metadata and receive a temporary `upload_url`. 2. **PUT File**: Upload the raw binary file contents to the returned `upload_url` with the `Content-Type` header matching `file_type`. A maximum of 10 documents per business can be uploaded. **Example:** ```bash curl -X PUT \ -H "Content-Type: $file_type" \ --upload-file ./path/to/$file_name \ "$upload_url" ``` - [Upload CSP Financial Document](https://docs.finmid.com/reference/create-csp-document-upload.md): Create a presigned upload URL for a CSP financial document. **Prerequisites:** The business must have an accepted CSP offer and an active CSP funding that has not been paid out yet. Document uploads are no longer possible once the submission has been [finalized](./finalize-csp-document-submission). This is a two-step flow: 1. **Create Upload** (this endpoint): Provide file metadata and receive a temporary `upload_url`. 2. **PUT File**: Upload the raw binary file contents to the returned `upload_url` with the `Content-Type` header matching `file_type`. A maximum of 20 documents per business can be uploaded. **Example:** ```bash curl -X PUT \ -H "Content-Type: $file_type" \ --upload-file ./path/to/$file_name \ "$upload_url" ``` **Example flow:** 1. Fetch the current state via [List CSP Financial Documents](./list-csp-documents) to check if a submission is already in progress or pick up where a previous session left off. 2. Upload one or more documents using this endpoint. 3. Optionally remove unwanted documents via [Delete CSP Financial Document](./delete-csp-document). 4. Once at least one document is uploaded, finalize via [Finalize CSP Financial Documents Submission](./finalize-csp-document-submission). - [List CSP Financial Documents](https://docs.finmid.com/reference/list-csp-documents.md): Retrieve the latest CSP financial documents for a Business. Returns the list of uploaded documents along with the submission status. Once documents have been submitted via the finalize endpoint, `is_submitted` will be `true`. - [Delete CSP Financial Document](https://docs.finmid.com/reference/delete-csp-document.md): Delete a previously uploaded CSP financial document. A document can only be deleted before the submission has been finalized. Once the submission is finalized, documents can no longer be deleted. - [Finalize CSP Financial Documents Submission](https://docs.finmid.com/reference/finalize-csp-document-submission.md): Finalize the submission of CSP financial documents for a Business. Once finalized, no further documents can be uploaded or deleted for the current submission. At least one document must have been uploaded before the submission can be finalized. - [List Funding Documents](https://docs.finmid.com/reference/list-funding-documents.md): Retrieve a list of all documents associated with a specific funding. Documents can include invoices, terms and conditions, and capital summaries related to the funding. - [Get Document Download URL](https://docs.finmid.com/reference/get-document-url.md): Retrieve a pre-signed URL for downloading a specific document. The URL is temporary and will expire after the specified timestamp. - [Get latest onboarding status](https://docs.finmid.com/reference/get-latest-onboarding.md): This endpoint retrieves the latest onboarding status for a business. The onboarding process collects information from the business to generate offers in cases when platform doesn't have enough data to create pre-approved offers. This endpoint provides information about the current state of the onboarding process, including submission and review timestamps, and rejection reasons if applicable. The status transitions as follows: - `AVAILABLE` → `IN_REVIEW` (when submitted) - `IN_REVIEW` → `APPROVED` (when approved) - `IN_REVIEW` → `REJECTED` (when rejected) - [Get current Offer](https://docs.finmid.com/reference/get-current-offer-state.md): This endpoint is used to access the status of the current Offer or Funding, as well as the embedding link for the Capital iframe. Depending on the presence and status of the current Offer and Funding, Platforms can communicate different details to the Business [in their UI](./capital-iframe). For example, a new available Offer might be highlighted with a different display. ![Offer status transitions](https://files.readme.io/a66ea5be5abb48f454441b8a21cef1957dda5af1c706600663cda834e50c44aa-image.png) > 📘 > > finmid API supports [`capital_offer.created` webhook](./capital-webhooks#capital_offercreated) to communicate when a new Offer is available for the Business. - [Get Active Offer Group](https://docs.finmid.com/reference/get-active-offer-group.md): This endpoint returns the currently active Offer Group for a Business that can be accepted. An Offer Group contains multiple offers of the same type from which the Business can choose exactly one to accept. The type of offers (flexible or fixed) is determined by the financing setup and agreements between finmid and the Platform. If no active Offer Group exists, the `offer_group` field will be `null`, indicating the Business is currently not eligible for funding. **Flexible Offers** define payment as a percentage of the Business's sales revenue. **Fixed Offers** define payment as a fixed amount paid at a regular frequency (`WEEKLY` or `MONTHLY`). ### Determining available ranges Each offer in the group represents one selectable combination of payout amount and payment period. The offers are sorted in ascending order, so you can derive the available ranges from the array: - **Payout amount range** — the `payout_amount` of the first offer is the minimum; the last offer is the maximum. - **Payment period range** — the `payment_estimated_months` of the first offer is the minimum; the last offer is the maximum. These ranges can be used, for example, to populate sliders or input constraints in a UI before the Business selects a specific offer to accept. > Related webhooks: > - [`capital_offer.created`](./capital-webhooks#capital_offercreated) to communicate when a new Offer Group is available for the Business > - [`capital_offer.opened`](./capital-webhooks#capital_offeropened) is triggered when an Offer Group is first seen by the Business, either by rendering our iframe, or by the very first call to the endpoint, that gives an access to a given Offer Group > - [`capital_offer.expired`](./capital-webhooks#capital_offerexpired) to communicate when an Offer Group has expired - [Get Fundings](https://docs.finmid.com/reference/get-fundings-for-business.md): The endpoint provides information about the Funding of the Business. Depending on the presence and status of the current Funding, Platforms can communicate different details to the Business [in their UI](./capital-iframe). > 📘 > > finmid API supports [`capital_funding.created` webhook](./capital-webhooks#capital_fundingcreated) to communicate when an Offer was accepted by a business and a Funding was created. - [Get Funding payments](https://docs.finmid.com/reference/get-payments-for-credit.md): Retrieve all payments for a specific Funding. See also: - [`payment.scheduled` webhook](./capital-webhooks#paymentscheduled) - [`payment.completed` webhook](./capital-webhooks#paymentcompleted) - [`payment.failed` webhook](./capital-webhooks#paymentfailed) - [`payment.cancelled` webhook](./capital-webhooks#paymentcancelled) - [Get Payment batch](https://docs.finmid.com/reference/get-payment-batch.md): Retrieve aggregated payment information for a specific payment batch. For every batch, it is possible to request information about the total batch payment amount and platform commission amount, as well as the payment details for each Funding. The information is aggregated by `funding_id`, meaning if multiple payments were reported for the same Funding (via [Report Payment](./report-payment) API), they will be summed together in a single entry. This endpoint provides visibility into payments that were reported using [Report Payment](./report-payment) API. Use this data to determine the total amount to collect from your businesses before completing the batch via [Report Funds Collection](./report-funds-collection) API (platform-funded) or bank transfer (finmid-funded). - [Report Payment](https://docs.finmid.com/reference/report-payment.md): Report a payment collection from a Business to finmid, grouped by a specific payment period, market, or another grouping. Use this endpoint when the platform calculates the collection amounts itself. The currently active Funding for the Business will be automatically identified by finmid. Payments are grouped into batches representing payment periods, with the `batch_id` in the path serving as a payment reference. The `payment_id` in the path serves as a unique identifier for this payment report and acts as an idempotency key to prevent duplicate submissions. > 📘 **Alternative: Sales Statements** > > If you want finmid to calculate the collection amounts for you based on sales data, use [Add Sales Statements](./add-sales-statements) API instead. ## After reporting payments After reporting payments, you can retrieve the aggregated results for a batch using the [Get Payment Batch](./get-payment-batch) API. The next step depends on your integration model: - **Platform-funded**: Collect the funds from your businesses and then confirm the collection using [Report Funds Collection](./report-funds-collection) API. - **finmid-funded**: Collect the funds from your businesses and send them to finmid's bank account via bank transfer (simulated via [Sales statements batch payment](./simulate-batch-payment) API in sandbox). ## Appending Payments to a Batch This API supports multiple submissions for the same `batch_id`. When you call this endpoint multiple times with the same `batch_id`, the reported payment amounts are **appended** to the existing batch, not replaced. Similarly, if you report multiple payments for the same Business within a batch, all reported amounts will be appended and accumulated for that Business's active Funding. > 📘 Example: Incremental Payment Reporting > > **First API call** (batch_id: `W4-2020-01`, payment_id: `report-1`): > ```json > { > "business_id": "business-123", > "payment_amount": 1000.00, > "reported_at": "2020-02-10T10:00:00.000Z" > } > ``` > **Second API call** (batch_id: `W4-2020-01`, payment_id: `report-2`): > ```json > { > "business_id": "business-123", > "payment_amount": 500.00, > "reported_at": "2020-02-10T14:00:00.000Z" > } > ``` > **Third API call** (batch_id: `W4-2020-01`, payment_id: `report-3`): > ```json > { > "business_id": "business-456", > "payment_amount": 800.00, > "reported_at": "2020-02-10T16:00:00.000Z" > } > ``` > Result: Batch `W4-2020-01` now contains: > - `business-123`: **1500.00** (1000.00 + 500.00) > - `business-456`: **800.00** - [Report Funds Collection](https://docs.finmid.com/reference/report-funds-collection.md): **Applicable only to platform-funded integrations.** Use this endpoint to notify finmid that you have collected funds from your businesses for a specific batch. In a platform-funded integration, the platform provides its own capital to businesses while finmid provides the infrastructure (e.g. underwriting model). After reporting collections via [Report Payment](./report-payment) API or [Add Sales Statements](./add-sales-statements) API, the platform collects the funds from businesses and then calls this endpoint to confirm the collection. The `batch_id` must match a batch previously used in [Report Payment](./report-payment) API or [Add Sales Statements](./add-sales-statements) API. The `amount` and `currency` should correspond to the total collected for that batch. > 📘 **Integration models** > > There are two integration models for handling collections: > - **Platform-funded**: The platform provides its own capital. After collecting from businesses, use this endpoint to report the collection to finmid. > - **finmid-funded**: finmid provides the capital. After collecting from businesses, the platform sends the funds to finmid's bank account via bank transfer (simulated via [Sales statements batch payment](./simulate-batch-payment) API in sandbox). ## Typical flow (platform-funded) 1. Report collections using [Report Payment](./report-payment) API or [Add Sales Statements](./add-sales-statements) API, grouped by `batch_id`. 2. Optionally retrieve aggregated batch data using [Get Payment Batch](./get-payment-batch) API or [Get Sales Statements](./get-sales-statements) API. 3. Collect the funds from your businesses. 4. Call this endpoint to confirm the collection to finmid (using `batch_id`, and `repayment_amount` + `platform_commission_amount` from the 2nd step as the collected `amount`). - [Execute Payment Transaction](https://docs.finmid.com/reference/execute-payment-transaction.md): This API must be implemented by platforms that provide their own capital to businesses. > ⚠️ Note that this endpoint is **not hosted by finmid**. It is called by finmid to instruct the platform to execute a bank transfer to the specified beneficiary to payout a funding. The platform must process the payment and return a successful HTTP response to acknowledge receipt of the request. Once the payment request has been processed, the platform must notify finmid of its success or failure via the [Receive Payout Confirmation](#tag/Incoming-Webhook/operation/receive-payout-confirmation) webhook. ## Idempotency The `idempotency_key` uniquely identifies each transaction request. If finmid sends a request with an `idempotency_key` that was already successfully processed, the platform should return a 409 - CONFLICT response without executing the payment again. ## Beneficiary verification We recommend that the platform verifies the beneficiary before executing the payment. Specifically, the platform should look up the business in its own system using the provided `iban` and confirm that the beneficiary is a known customer. If the IBAN does not match any registered business, the platform should reject the request with a 400 - validation error. ## Authentication & message integrity Every request from finmid is signed using **HTTP Message Signatures** ([RFC 9421](https://www.rfc-editor.org/rfc/rfc9421)), combined with **IP whitelisting**. ### What is signed finmid signs the following components of each request: | Component | Description | |---|---| | `@method` | HTTP method (POST) | | `@path` | Request path | | `content-type` | Media type of the body | | `content-digest` | SHA-256 hash of the request body (see below) | ### Request headers Each signed request includes the following additional HTTP headers: | Header | Description | |---|---| | `Content-Digest` | SHA-256 hash of the request body, formatted as `sha-256=::` | | `Signature-Input` | Describes which components are signed and includes signature metadata | | `Signature` | The cryptographic signature (base64-encoded) | ### Signature metadata The `Signature-Input` header contains the following metadata parameters: | Parameter | Description | |---|---| | `keyid` | Identifier of the public key to use for verification. finmid will provide the public key during integration setup. | | `alg` | Signing algorithm. finmid uses `ed25519`. | | `created` | Unix timestamp (seconds) when the signature was created. | | `expires` | Unix timestamp (seconds) after which the signature is no longer valid (`created` + 60 seconds) | | `nonce` | Random unique value (UUID) generated per request attempt, including retries. Used exclusively for replay attack prevention — independent from the `idempotency_key` in the request body, which serves business-level idempotency. The nonce store can use a short TTL aligned with the signature validity window (`expires - created`). | ### Example signed request ```http POST /api/v1/transaction HTTP/1.1 Host: platform.example.com Content-Type: application/json Content-Digest: sha-256=:q83vRzQK3YpS6cJ8iX9u6pHc9T6YxQZ3S8KcYpVvC8E=: Signature-Input: sig1=("@method" "@path" "content-type" "content-digest");created=1773135059;expires=1773135119;keyid="finmid-prod-key-1";alg="ed25519";nonce="f47ac10b-58cc-4372-a567-0e02b2c3d479" Signature: sig1=:dGhpcyBpcyBhbiBleGFtcGxlIHNpZ25hdHVyZQ==: {"idempotency_key":"op-fund-2026.crd-001.biz-123","business_id":"biz-123","beneficiary":{"iban":"DE89370400440532013000","bic":"COBADEFFXXX","name":"John Doe"}, ...} ``` ### Verification steps (server-side) The platform must verify each incoming request: 1. **Parse** `Signature-Input` to extract signed components and metadata. 2. **Reconstruct** the signature base — the canonical string built from the signed components in the exact order specified by `Signature-Input`. 3. **Retrieve** the public key using `keyid`. finmid will provide the public key during integration setup. 4. **Verify** the `Signature` against the reconstructed signature base using the public key and the `ed25519` algorithm. 5. **Validate** the `Content-Digest` header by computing SHA-256 of the received body and comparing. 6. **Enforce** temporal and replay policies: - Reject if `created` is in the future (allow ~30 seconds clock skew). - Reject if current time is after `expires`. - Reject if the `nonce` has already been seen within the validity window. If any step fails, return `401 Unauthorized`. ### Key exchange During integration setup, finmid will provide: - The **Ed25519 public key** for signature verification. - The **`keyid`** value that will appear in `Signature-Input`. - The list of **IP addresses** to whitelist for additional security. Key rotation will be coordinated between finmid and the platform, with advance notice. ## Base URL The base URL for this endpoint is the platform's own server URL, configured during the integration setup with finmid.
The following is a suggestion, the platform can customise it to their needs: ``` POST /api/v1/transaction ``` - [Get Sales statements of a batch](https://docs.finmid.com/reference/get-sales-statements.md): Retrieve aggregated sales statement information for a specific batch. For every batch, it is possible to request information about the total payment amount, platform commission amount, and the breakdown for each Business. The information is aggregated for each Business (and optional `group_id`) that has shared Sales statements in this batch. This endpoint provides visibility into sales statements that were reported using [Add Sales Statements](./add-sales-statements) API. Use this data to determine the total amount to collect from your businesses before completing the batch via [Report Funds Collection](./report-funds-collection) API (platform-funded) or bank transfer (finmid-funded). - [Add Sales statements to a batch](https://docs.finmid.com/reference/add-sales-statements.md): Share Business's sales data with finmid so that finmid calculates the collection amounts for you. Once a Funding Offer has been accepted, payment amounts can be calculated and collected. The platform shares the Business's sales revenue (Sales statements) with finmid, and finmid calculates the `repayment_amount` based on the `repayment_percent` specified in the terms of the accepted Offer. > 📘 **Alternative: Report Payment** > > If you calculate the collection amounts yourself, use [Report Payment](./report-payment) APIs instead. ## After adding Sales Statements The API response contains the calculated `repayment_amount` and `platform_commission_amount` for each Business. You can also retrieve the aggregated results at any time using [Get Sales Statements](./get-sales-statements) API. The next step depends on your integration model: - **Platform-funded**: Collect the funds from your businesses and then confirm the collection using [Report Funds Collection](./report-funds-collection) API. - **finmid-funded**: Collect the funds from your businesses and send the `repayment_amount` to finmid's bank account via bank transfer, using the `batch_id` as reference text (simulated via [Sales statements batch payment](./simulate-batch-payment) API in sandbox). ## Options It is possible to limit the maximum value of the `repayment_amount` calculated for the reported `sales_amount` by specifying the `net_amount`. As a result, the `repayment_amount` for the reported Sales Statement entry will not exceed the `net_amount`. Within each Business, you can additionally group Sales statements by providing a Sales Statement `group_id` value. This allows sales and payment data in the API response to be aggregated separately for each `business_id`/`group_id` pair. Sales statements should be shared periodically. The period is defined in the API as a "Batch", which aggregates the Sales statements of one or several Businesses for a given period. - [Funding creation](https://docs.finmid.com/reference/simulate-create-funding.md): This endpoint creates a Business, generates an Offer (flexible or fixed repayments) based on the provided terms, and accepts it. This allows you to immediately begin sharing revenue information (Sales statements) for the Business to initiate payment. > 🚧 > > **Only available in sandbox environment.** - [Funding payout](https://docs.finmid.com/reference/payout-credit.md): This endpoint simulates updating the KYB information and marking the funding as paid out. Endpoint can be used only for `PENDING` fundings without `paid_out_at` timestamp. In the live environment, fundings are paid out once the Business successfully completes the KYB process. > 🚧 > > **Only available in sandbox environment.** - [Funding rejection](https://docs.finmid.com/reference/reject-credit.md): This endpoint simulates updating the KYB information with rejection details and marking the funding as rejected. Endpoint can be used only for `PENDING` fundings without `paid_out_at` timestamp. In the live environment, fundings can be rejected when the Business fails the KYB process or does not meet the underwriting criteria. > 🚧 > > **Only available in sandbox environment.** - [Sales statements batch payment](https://docs.finmid.com/reference/simulate-batch-payment.md): **Applicable only to finmid-funded integrations.** Simulates a bank transfer payment for a batch in the sandbox environment. In a finmid-funded integration, after collecting funds from businesses, the platform sends the `repayment_amount` to finmid's bank account via bank transfer. This simulation endpoint replicates that bank transfer in sandbox so you can test the full flow end-to-end. > 📘 **Platform-funded integrations** use [Report Funds Collection](./report-funds-collection) instead of a bank transfer. > 🚧 > > **Only available in sandbox environment.** - [Offer creation](https://docs.finmid.com/reference/simulate-create-offers.md): While finmid creates Offers after conducting a risk assessment in the live environment, this API can be used to simulate the Offer creation process for testing purposes. > 🚧 > > **Only available in sandbox environment.** - [Offer acceptance](https://docs.finmid.com/reference/simulate-accept-offers.md): This API allows you to accept an active Offer on behalf of a Business. While a Business representative would typically accept an Offer through the UI, this API enables you to bypass the UI flow for testing purposes. > 🚧 > > **Only available in sandbox environment.** - [Offer expiration](https://docs.finmid.com/reference/simulate-expire-offers.md): This API allows you to expire an active Offer, simulating the scenario where a Business does not accept the Offer within a specified time frame. > 🚧 > > **Only available in sandbox environment.** - [Payment scheduling](https://docs.finmid.com/reference/schedule-payment.md): In the live environment, payments are being scheduled automatically to be debited from the Business bank account, when their `scheduled_at` time comes. To simulate a similar event in the sandbox environment, you can use this endpoint. > 🚧 > > **Only available in sandbox environment.** - [Payment completion](https://docs.finmid.com/reference/complete-payment.md): In the live environment, payments are being completed once the Business bank account is debited and the payment amount is reconciled. To simulate a similar event in the sandbox environment, and bring the Payment to `COMPLETED` state, you can use this endpoint. Payment will be automatically scheduled, if it has not been yet. > 🚧 > > **Only available in sandbox environment.** - [Payment failure](https://docs.finmid.com/reference/fail-payment.md): In the live environment, payments can fail when debit of Business bank account has failed, e.g. due to insufficient balance. To simulate a similar event in the sandbox environment, and bring the Payment to `FAILED` state, you can use this endpoint. Payment will be automatically scheduled, if it has not been yet. > 🚧 > > **Only available in sandbox environment.** - [Receive Incoming Webhook](https://docs.finmid.com/reference/receive-incoming-webhook.md): Endpoint for receiving incoming webhooks with generic data payloads. It acts as an initial integration point for early-stage data adoption. Once a data flow is standardized, it will be implemented as a separate, dedicated endpoint. - [Receive Payout Outcome](https://docs.finmid.com/reference/receive-payout-outcome.md): > ⚠️ This webhook is relevant only for platforms that provide their own capital to businesses. Webhook endpoint for receiving payout execution outcome from the platform. After finmid sends a payout instruction via [Execute Payment Transaction](#tag/Payment/operation/execute-payment-transaction), the platform must notify finmid of the outcome by calling this endpoint. The platform sends a confirmation with either: - **`SETTLED`**: the payment was successfully deposited into the beneficiary's bank account, including the settlement timestamp. - **`FAILED`**: the payment could not be completed, including the failure reason. ## Correlation The `finmid_idempotency_key` in the request body is the same `idempotency_key` that finmid provided in the original Execute Payment Transaction request. It is used to match this confirmation to the original payout instruction. ## Idempotency This endpoint is **idempotent on the pair `(finmid_idempotency_key, type)`**. Retransmitting the same confirmation (same key, same `type`) any number of times returns **200** and does not cause duplicate processing. Platforms can therefore safely retry on network failures, timeouts, or 5xx responses without special handling. A **409 - CONFLICT** is returned only when the platform sends an outcome (`SETTLED` or `FAILED`) that contradicts a terminal state already recorded for that `finmid_idempotency_key` — for example, `SETTLED` after finmid has already marked the payment as `FAILED`, or vice versa. 409 is therefore a **state-conflict signal**, not a duplicate-detection signal: it indicates a real divergence between the platform's view and finmid's view of the payment that requires investigation.