In-Person
Braintree SandboxContact SalesGet Help
  • Braintree In-Person
  • About
    • Solution Architecture
    • Technical Overview
    • Solution Coverage
  • Hardware
    • Verifone P400
    • Verifone M400
    • Verifone E285
    • Verifone V400m
  • Get Started
    • Integration Checklist
    • Request Dev Kit
    • Configure Sandbox
    • Account Structure
  • Integration Guides
    • API Authentication
    • Setup Reader
    • Initiate a Sale or Refund
      • Initiate a Card Present Authorization
      • Level 2 and Level 3 Data Processing
      • Passing Lodging Data
    • Vaulting and Customers
    • PayPal and Venmo QRC
    • Display Information
    • Custom Prompts
    • Card Data Collection
    • GraphQL Error Handling
    • Offline Transactions
    • Additional API Calls
    • Receipt Printing API
    • Reporting and Reconciliation
    • Testing Your Integration
    • Ready for Launch?
  • Partner Considerations
    • Overview
  • Support
    • Reader Management System (RMS) - Available in Beta Only
    • Managing Firmware Updates
    • Troubleshooting
    • Network Connection Test
    • Support/Contact Us
  • Reference
    • Firmware Version Release Notes
    • Verifone Device Reference
    • EMV Receipt Reference
    • General Payments Terminology
    • GraphQL Docs
    • PayPal Braintree Sub-processors
    • FAQ
Powered by GitBook
On this page
  • Feature Overview
  • Initializing the Reader for Authorization
  • Checking the Reader Authorization Status
  • Capturing funds against an Authorization
  • Example Capture request
  • Using Incremental Authorizations
  • Example Update Transaction Amount request
  • Using Estimated Auth (Pre-Auth)
  • AMEX Over Capture Rules
  • Important Tips When Integrating Separate Auth from Capture

Was this helpful?

  1. Integration Guides
  2. Initiate a Sale or Refund

Initiate a Card Present Authorization

This page covers the support of separate auth from capture on the Braintree In-Person solution from a card present perspective.

PreviousInitiate a Sale or RefundNextLevel 2 and Level 3 Data Processing

Last updated 5 months ago

Was this helpful?

Feature Overview

For some use cases where a capture delay is required (ex: endless aisle, save the sale, tipping on receipt, hotel check-in), you may need to request an authorization rather than requesting a charge. This gives the API caller complete control over the authorization capture cadence rather than relying on automated Braintree capture logic. Generally, this operates similarly to e-commerce authorization flows, with some important differences.

Separate auth and capture using the API mutation is supported starting in firmware

Initializing the Reader for Authorization

When you're ready to charge a customer, you can create an In-Store Context by requesting to authorize a card on the reader. In this step, your application will specify at minimum, the readerId , merchantAccountIdand transaction.amount details to initialize the reader for payment acceptance. Note that the merchantAccountIdis not validated against in the Sandbox environment; however, this is a required value in the Production environment for all interactions with the card reader.

Authorizing is similar to charging, except that if the authorization is successful, Braintree will NOT capture the transaction. It would be up to the merchant to send a separate capture request using the transaction.id to complete the charge.

Card present authorizations only allow for a single capture request; multiple partial capture is NOT supported. Any remaining authorized funds after the first capture will automatically be voided.

To provide idempotency on the mutation, you must also include the HTTP header Idempotency-Key with a unique value. UUIDv4 is recommended. For example, if using curl to make the request, you would include

Using Idempotency-Key is an important way of preventing duplicate charges to your customer in the event of an API communication failure. For example: if you request a charge from the reader, the customer completes the charge on the reader but for some reason, the POS does not get back the result of the transaction before timing out. In this scenario, the POS could recover the original transaction using the same Idempotency-Key without accidentally creating a duplicate charge.

--header 'Idempotency-Key: 94c9ea8b-31b0-488e-a231-57e32f0bfd70' 
mutation RequestAuthorizeFromInStoreReader($input: RequestAuthorizeFromInStoreReaderInput!) {
    requestAuthorizeFromInStoreReader(input: $input) {
        clientMutationId
        id
        status
        reader {
            id
            name                
            status
        }
    }
}
{
  "input": {
      "clientMutationId": "your event/request reference",
      "readerId": "your reader ID",
      "transaction": {
		"amount": "any amount",            
      "orderId": "Your Order Id",
      "merchantAccountId": "your merchant account ID"
   }
  }
}
{
    "data": {
        "requestAuthorizeFromInStoreReader": {
            "clientMutationId": "your event/request reference",
            "id": "aW5zdI2U3NzY3NTQ4YjM2Mzk0MGExNzU1Yjk5YWM3I1ZFUklGT05FLTgwNS0wMTctNDU0I3VzLXdlc3QtMg",
            "status": "PENDING",
            "reader": {
                "id": "aW5z3B3c2Y0Mmh3hjbiNWRVJJRk9ORS04MDUtMDE3LTQ1NA",
                "name": "Your P400",
                "status": "ONLINE"
            }
        }
    },
    "extensions": {
        "requestId": "1b170326-3523-47c1-add6-b079b1ab0"
    }
}

Checking the Reader Authorization Status

When the RequestAuthorizeInStoreContext.status changes to "COMPLETE", you will also receive a transaction object RequestAuthorizeInStoreContext.transactionin the response. Save the completed RequestAuthorizeInStoreContext.transaction.id in your database for referencing the transaction in subsequent operations (ie. capture, adjust auth, void, etc...).

{
 node(id: "{{last_braintree_instore_context}}") {
  ... on RequestAuthorizeInStoreContext {
   id
   status
   statusReason
   reader {
    id
    name
    status
   }
   transaction {
    id
    orderId
    status
    statusHistory {
     ... on PaymentStatusEvent {
      status
      timestamp
      terminal
      ... on AuthorizedEvent {
       authorizationExpiresAt
       processorResponse {
        authorizationId
        emvData
        message
        legacyCode
        retrievalReferenceNumber
       }
      }
      ... on GatewayRejectedEvent {
       gatewayRejectionReason
      }
      ... on FailedEvent {
       processorResponse {
        retrievalReferenceNumber
        emvData
        message
        legacyCode
       }
       networkResponse {
        message
        code
       }
      }
      ... on ProcessorDeclinedEvent {
       processorResponse {
        legacyCode
        message
        authorizationId
        additionalInformation
        retrievalReferenceNumber
        emvData
       }
       declineType
       networkResponse {
        code
        message
       }
      }
     }
    }
    merchantAddress {
     company
     streetAddress
     addressLine1
     extendedAddress
     addressLine2
     locality
     adminArea2
     region
     adminArea1
     postalCode
     countryCode
     phoneNumber
    }
    amount {
     value
     currencyIsoCode
    }
    merchantAccountId
    merchantName
    createdAt
    channel
    customFields {
     name
     value
    }
    paymentMethodSnapshot {
     ... on CreditCardDetails {
      origin {
       details {
        ... on EmvCardOriginDetails {
         applicationPreferredName
         applicationIdentifier
         terminalId
         inputMode
         pinVerified
        }
       }
      }
      brandCode
      last4
      bin
      expirationMonth
      expirationYear
      cardholderName
      binData {
       issuingBank
       countryOfIssuance
       prepaid
       healthcare
       debit
       commercial
      }
     }
    }
   }
  }
 }
}
{
    "data": {
        "node": {
            "id": "aW5zdG9yZWNTQ4YjM2ZTRlZDRhMzk0MGExNzU1Yjk5YWM3I1ZFUklGT05FLTgwNS0wMTctNDU0I3VzLXdlc3QtMg",
            "status": "COMPLETE",
            "reader": {
                "id": "aW5zdG9yZXJlYWRY0Mmh3OWo1OWhjbiNWRVJJRk9ORS04MDUtMDE3LTQ1NA",
                "name": "Your P400",
                "status": "ONLINE"
            },
            "transaction": {
                "id": "dHJhb25fYjNhc2VqY2E",
                "legacyId": "bsejca",
                "orderId": "Your Order Id",
                "status": "AUTHORIZED",
                "statusHistory": [
                    {
                        "__typename": "AuthorizedEvent",
                        "status": "AUTHORIZED",
                        "timestamp": "2023-06-16T18:24:07.000000Z",
                        "terminal": false,
                        "processorResponse": {
                            "authorizationId": "G5TJ7V",
                            "emvData": "9F240512345678908A023030",
                            "message": "Approved",
                            "legacyCode": "1000",
                            "retrievalReferenceNumber": "1234567"
                        }
                    }
                ],
                "merchantAddress": {
                    "company": null,
                    "streetAddress": null,
                    "addressLine1": null,
                    "extendedAddress": null,
                    "addressLine2": null,
                    "locality": "Braintree",
                    "adminArea2": "Braintree",
                    "region": "MA",
                    "adminArea1": "MA",
                    "postalCode": "02184",
                    "countryCode": null,
                    "phoneNumber": "5555555555"
                },
                "amount": {
                    "value": "792.00",
                    "currencyIsoCode": "USD"
                },
                "merchantAccountId": "OverCapture_AdjustAuth",
                "merchantName": "DESCRIPTORNAME",
                "createdAt": "2023-06-16T18:24:06.000000Z",
                "channel": null,
                "customFields": null,
                "paymentMethodSnapshot": {
                    "__typename": "CreditCardDetails",
                    "origin": {
                        "type": "IN_STORE_READER",
                        "details": {
                            "__typename": "EmvCardOriginDetails",
                            "authorizationMode": "ISSUER",
                            "inputMode": "CONTACTLESS",
                            "pinVerified": false,
                            "terminalId": "9c3b9fc0",
                            "applicationPreferredName": "Braintree Credit",
                            "applicationIdentifier": "A000000003101001",
                            "terminalVerificationResult": "0000000000",
                            "cardSequenceNumber": null,
                            "applicationInterchangeProfile": null,
                            "terminalTransactionDate": null,
                            "terminalTransactionType": null,
                            "cashbackAmount": null,
                            "applicationUsageControl": null,
                            "terminalCountryCode": null,
                            "applicationCryptogram": null,
                            "cryptogramInformationData": null,
                            "cardholderVerificationMethodResults": null,
                            "applicationTransactionCounter": null,
                            "unpredictableNumber": null,
                            "issuerActionCodeDefault": null,
                            "issuerActionCodeDenial": null,
                            "issuerActionCodeOnline": null
                        }
                    },
                    "brandCode": "VISA",
                    "last4": "8885",
                    "bin": "421212",
                    "expirationMonth": "12",
                    "expirationYear": "2025",
                    "cardholderName": "BRAINTREE TEST",
                    "binData": {
                        "issuingBank": null,
                        "countryOfIssuance": null,
                        "prepaid": "UNKNOWN",
                        "healthcare": "UNKNOWN",
                        "debit": "UNKNOWN",
                        "commercial": "UNKNOWN"
                    }
                }
            }
        }
    },
    "extensions": {
        "requestId": "75004704-898e-4621-a37c-8ead03b1"
    }
}

Capturing funds against an Authorization

The transaction must be in an Authorized state to allow for funds capture

Example Capture request

mutation CaptureTransaction($input: CaptureTransactionInput!) {
  captureTransaction(input: $input) {
    transaction {
      id
      status
    }
  }
}
{
  "input": {
    "transactionId": "transaction ID from successful authorization",
    "transaction": {
      "amount": "input amount to be captured"
    }
  }
}
{
    "data": {
        "captureTransaction": {
            "transaction": {
                "id": "dHJhbnNhYfYWt6Zmp5ODM",
                "status": "SUBMITTED_FOR_SETTLEMENT"
            }
        }
    },
    "extensions": {
        "requestId": "39f948cb-96f2-406e-9f9f-21787452f"
    }
}

Using Incremental Authorizations

The transaction must be in an Authorized state to be eligible for adjustment

Example Update Transaction Amount request

mutation updateTransactionAmount($input: UpdateTransactionAmountInput!) {
  updateTransactionAmount(input: $input) {
    transaction {
      id
      status
      customer{
          email
          firstName
          lastName
          id
      }
    }
  }
}
{
  "input": {
    "transactionId": "transaction ID from successful authorization",
    "amount": "new desired authorization amount"
    }
  }
{
    "data": {
        "updateTransactionAmount": {
            "transaction": {
                "id": "dHJhbnNhY3bTVwZWZla3M",
                "status": "AUTHORIZED",
                "customer": null
            }
        }
    },
    "extensions": {
        "requestId": "f7e636cb-5da5-45dd-ac73-c94b404d"
    }
}

Using Estimated Auth (Pre-Auth)

mutation RequestAuthorizeFromInStoreReader($input: RequestAuthorizeFromInStoreReaderInput!) {
    requestAuthorizeFromInStoreReader(input: $input) {
        clientMutationId
        inStoreContext {
            id
            status
            transaction {
                id
                orderId
                status
                customer{
                    id
                }
                paymentMethodSnapshot{
                    __typename
                    ... on CreditCardDetails {
                        brandCode
                        bin
                        last4
                        cardholderName
                        expirationMonth
                        expirationYear     
                    }
                }
            }
            reader {
                id
                name                
                status
                softwareVersion
            }
        }
    }
}
{
            "input": {
		"readerId": "your reader ID",
		"transaction": {
			"amount": "any amount",      
            		"orderId": "your order ID",
            		"merchantAccountId": "your merchant account ID",
            		"paymentInitiator": "ESTIMATED"  
		}
    	}
}

AMEX Over Capture Rules

MCC codes such as 4821 (Taxi Cabs and Rideshares) and 5812 (Restaurants) are allowed to capture up to 20% more than the authorized amount.

MCC codes such as 7011 (Lodging), 7512/7513/7519 (Vehicle Rentals), as well as Cruise Lines, Grocery merchants, and Retailers are allowed to capture up to 15% more than the authorized amount.

If you have a direct contract with AMEX, you may need to reach out to them to have them configure your account to allow for over-captures.

Important Tips When Integrating Separate Auth from Capture

  • Some MCC codes are allowed to capture more (aka over capture) than the authorized amount (typically used by restaurant merchants for tipping purposes)

  • Some MCC codes are allowed to use incremental authorizations (adjust auth) in order to incrementally increase the auth amount (typically used by Hotel & Hospitality merchants)

  • To enable over-captures or incremental authorizations, your Braintree account must be configured accordingly. Please work with your Solutions Engineer or Integration Engineer to facilitate this

  • Incremental Auth is not supported for AMEX transactions. For some use cases, you may need to perform an over-capture for an AMEX transaction

After the reader is initialized for payment, your application must wait for the customer to interact with it (i.e. insert a test card) and for the payment attempt to be processed. Your application should use to poll on a 2-second interval between responses for the current status of the payment using the RequestChargeInStoreContext.id received at charge initialization and monitor the RequestAuthorizeInStoreContext.statusfield as the transaction goes through the lifecycle.

All successful test transactions should have a transaction amount value below $2,000 for testing. For more info on using amounts to simulate various transaction outcomes, take a look at .

To capture the authorized funds, you must use the within a 24-hour window of the funds being authorized (except for eligible Lodging MCC codes, which have expiry windows of up to 30 days). For a card-present authorization, you are allowed only a single capture attempt. Any remaining authorized funds not captured after the initial capture request will be voided. You may capture a lesser amount than what was authorized or an amount up to the maximum over-capture threshold (subject to eligibility). For merchants processing on MCC codes ineligible for over-capture, the maximum amount allowed for capture is the amount authorized.

For some merchants, for example, those in the Hotels & Hospitality or some other industries, incremental authorizations (aka adjust auth) are an important feature for use cases such as tipping adjustment, hotel room damages, or hotel mini-bar charges, etc... This feature is subject to merchant eligibility based on MCC code, and it is also not supported for AMEX transactions and some other transaction types. This feature leverages the with Braintree's GraphQL API.

Using an estimated authorization or a "pre-auth" can help avoid issuer rejections and improve authorization rates for scenarios when you may not know the final charge amount at the time of authorization. Some industries where this may be common are hotels, vehicle rentals, bars, etc... It is recommended that you use this feature if you are using incremental auth. To trigger an estimated authorization you must pass the flag with a value of "ESTIMATED". See example below:

is supported for

transactions are NOT supported for separate auth from capture

Passing of is not supported in the authorization request; however, you may pass this data in the request

the node query
Testing Your Integration
Capture Transaction mutation
updateTransactionAmount API mutation
paymentInitiator
PayPal and Venmo QRC
offline transactions
Request Authorization
L2/L3 data
separate capture
requestAuthorization
requestAuthorize
version 5.1.0
COMPLETE context status will indicate an "Authorized" transaction status, not "SUBMITTED_FOR_SETTLEMENT" when using the Request Authorize mutation