Skip to content

At the center of Flute's payments model is the transaction. A transaction is a record created every time money moves through a merchant's account.

A transaction is created with a single call:
POST /v2/transactions

Every transaction carries the same core shape regardless of payment type:

  • paymentProcessorId specifies the processor handling the transaction.
  • baseAmount and currencyCode specify the transaction amount.
  • referenceId specifies a value the merchant chooses for their own bookkeeping.
  • transactionDetails specifies an object holding either the cardData or achData depending on how the customer is paying.

Each transaction goes through the same endpoint. It comes back with the same response envelope, just populated with different processorResponse details. This includes whether someone is charging a saved card, running a brand-new card number inline, or debiting a bank account through ACH.

Card transactions carry an extra decision point that ACH doesn't: captureMethod. This is set to either Auto or Manual.

  • Auto capture means the authorization and the capture happen in one step, and the transaction lands in an Approved state immediately, ready to settle.
  • Manual capture splits it into two steps: the initial call only authorizes the funds and returns a Pending transaction, and a separate call to POST /v2/transactions/{transactionId}/capture later finalizes it.

This distinction matters most for merchants who need to confirm inventory or finalize an order total. For example, a restaurant might close a tab with tips added before actually pulling the money. It's why the API treats "money authorized" and "money captured" as two different states rather than collapsing them into one.

Once a transaction is captured or approved, several other endpoints act on it rather than creating a new one.

  • POST /v2/transactions/{transactionId}/reversal reverses a transaction outright.
  • POST /v2/transactions/{transactionId}/tip-adjustment lets a merchant amend the tip on an existing charge, common in card-present environments where the tip is added after the initial swipe.
  • POST /v2/transactions/reversal for pulling money back after settlement.
  • POST /v2/transactions/credit for issuing money without tying it to a prior reference.
  • POST /v2/transactions/{transactionId}/ach-hold for placing a hold on a pending ACH transaction.

Every transaction also comes back with a rich amountDetails and processorResponse breakdown rather than just a status code.

  • amountDetails separates baseAmount from tipAmount, tipRate, surchargeAmount, and discountAmount. A merchant can see exactly how a processedAmount was assembled instead of just the final total.
  • processorResponse reports which underlying processor ran the transaction, TSYS, for instance, on the card examples in the spec, or a plain ACH label for bank debits, along with a response code and a human-readable message. For card transactions there's also an addressVerificationServiceResponse, showing whether the billing address and the postal or ZIP code the customer supplied matched what the card issuer has on file. This is one of the signals merchants use to judge fraud risk on a given charge.

The following is an example of a basic transaction. A merchant charges $100 on a saved card with auto-capture, and the customer adds a $15 tip at checkout.

Request
POST /v2/transactions

{
    "paymentProcessorId": "a2f2c2e7-0b23-4682-8f99-ab7707205461",
    "baseAmount": 100.00,
    "currencyCode": "USD",
    "referenceId": "REF-CARD-SALE-001",
    "isCustomerInitiatedTransaction": true,
    "pricingType": "Card",
    "transactionDetails": {
        "cardData": {
            "captureMethod": "Auto",
            "paymentMethodId": "e397e367-bc4a-4b69-bd78-32e3e12327c2"
        }
    }
}

Because the captureMethod is Auto, Flute authorizes and captures the charge in the same call. The response comes back already settled from the API's perspective:

Response

{
    "transactionId": "5f6f782f-37af-44e1-bb18-2bc35e411899",
    "transactionStatus": "Approved",
    "processedAmount": 115.5,
    "currencyCode": "USD",
    "amountDetails":
    {
        "baseAmount": 100.00,
        "tipAmount": 15,
        "surchargeAmount": 3,
        "discountAmount": 2.5
    },
    "processorResponse":
    {
        "processorName": "TSYS",
        "responseCode": "00",
        "responseMessage": "Approved",
        "responseDefinition": "Approved and completed"
    },
    "addressVerificationServiceResponse":
    {
        "action": "Allow",
        "responseCode": "Y",
        "description": "Address and ZIP match"
    }
}

The processedAmount ($115.50) reflects the base charge plus the tip and a surcharge, minus a discount. This is exactly as itemized in amountDetails.

The transaction is done. There is no separate capture call needed. This merchant chose the auto-capture path rather than the authorize-then-capture flow used for something like a restaurant tab.