Skip to documentation content

Braintree API

Prepare Braintree Level 2/3 fields from a linked or inline invoice, merge them into transaction.sale or submitForSettlement, and report outcomes.

On this page

Authentication

Send a Braintree-integration Carden API key as a bearer token from a trusted server. Stripe, Square, and QuickBooks keys are rejected even if their scopes match. Every response includes x-carden-request-id; keep it for support.

Common request headers
Authorization: Bearer <CARDEN_API_KEY>
Content-Type: application/json

Prepare from a QuickBooks invoice

Endpoint
POST /api/v1/braintree/transaction-enrichment/from-invoice

Requires invoices:read and enrichment:write. Carden reads one imported, open, fully unpaid invoice and returns Braintree fields plus immutable preparation evidence.

FieldTypeRule
invoiceId | quickbooksInvoiceId | invoiceNumberstring, exactly oneinvoiceId is a Carden UUID. Use invoiceNumber only when it is unambiguous.
amountMinorpositive integerMust equal the full invoice total. Partial and combined payments are not supported.
currency"usd"Lowercase. Level 2/3 fields are prepared for USD only.
idempotencyKeystring, ≤160Characters A–Z, a–z, 0–9, and . _ : -. Persist it before the first request and reuse it only for the same request.
expectedRevisionstring, optionalRejects the request if the invoice changed since a reviewed revision.

Prepare a QuickBooks invoice for Braintree

curl https://www.cardenpay.com/api/v1/braintree/transaction-enrichment/from-invoice \
  -H "Authorization: Bearer $CARDEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"invoiceId":"7d4c2a1e-5b8f-4c3d-9a6e-2f1b0c8d7e65","amountMinor":11300,"currency":"usd","idempotencyKey":"prepare_attempt_1042_1"}'

200 OK
{
  "object": "braintree.transaction_enrichment",
  "api_version": "v1",
  "data": {
    "amount": "113.00",
    "orderId": "INV-1042",
    "purchaseOrderNumber": "PO-2081",
    "taxAmount": "8.00",
    "shippingAmount": "5.00",
    "discountAmount": "0.00",
    "lineItems": [
      {
        "kind": "debit",
        "name": "Industrial filter",
        "productCode": "FILTER-01",
        "quantity": "2",
        "unitOfMeasure": "each",
        "unitAmount": "50.00",
        "totalAmount": "100.00",
        "taxAmount": "8.00"
      }
    ]
  },
  "preparation": {
    "id": "0b6f3e2d-9c1a-4f7e-8d5b-3a2c1e0f9d84",
    "invoiceId": "7d4c2a1e-5b8f-4c3d-9a6e-2f1b0c8d7e65",
    "snapshotId": "c2e8a4f1-6d3b-4a9e-b7c5-1f0e2d3c4b5a",
    "revision": "rev_1042_3",
    "sourceIntegrationId": "5a1b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
    "sourceConnectionId": "6b2c3d4e-5f6a-4b7c-9d8e-0f1a2b3c4d5e",
    "checkedThrough": "2026-01-01T11:55:00.000Z",
    "createdAt": "2026-01-01T12:00:00.000Z",
    "amountMinor": 11300,
    "currency": "usd"
  }
}

A 409 or 422 response means the invoice is not ready. The body is {"error": {"type", "message", "issues": [...]}}. Each issue has a code, a path, and a message; see preparation issue codes.

Prepare from an inline invoice

Endpoint
POST /api/v1/braintree/transaction-enrichment

Requires enrichment:write. Send a complete, authoritative CanonicalInvoice v1. The transaction amount is the invoice total.

FieldTypeRule
invoiceCanonicalInvoice v1Required. Line-level tax and discount are explicit on every line.
options.shipsFromPostalCodestring, optionalUp to 10 letters, digits, spaces, or hyphens. Your fulfillment postal code; invoices do not carry it.
options.purchaseOrderNumberSource"purchase_order" | "invoice_number"Default purchase_order uses the buyer's PO. invoice_number is your attestation that buyers use the invoice number as their reference.
Request
{
  "invoice": {
    "invoiceNumber": "INV-1042",
    "purchaseOrderReference": "PO-2081",
    "status": "open",
    "currency": "USD",
    "subtotalAmountMinor": 10000,
    "taxAmountMinor": 800,
    "shippingAmountMinor": 500,
    "discountAmountMinor": 0,
    "totalAmountMinor": 11300,
    "balanceAmountMinor": 11300,
    "issuedAt": null,
    "dueAt": null,
    "voidedAt": null,
    "lineItems": [
      {
        "sequence": 1,
        "productName": "Industrial filter",
        "description": null,
        "productCode": "FILTER-01",
        "commodityCode": null,
        "quantity": "2",
        "unitOfMeasure": "each",
        "unitAmountMinor": 5000,
        "subtotalAmountMinor": 10000,
        "taxAmountMinor": 800,
        "discountAmountMinor": 0,
        "totalAmountMinor": 10800
      }
    ]
  },
  "options": {
    "shipsFromPostalCode": "60601",
    "purchaseOrderNumberSource": "purchase_order"
  }
}

200 OK
{
  "object": "braintree.transaction_enrichment",
  "api_version": "v1",
  "data": {
    "amount": "113.00",
    "orderId": "INV-1042",
    "purchaseOrderNumber": "PO-2081",
    "taxAmount": "8.00",
    "shippingAmount": "5.00",
    "discountAmount": "0.00",
    "lineItems": [
      {
        "kind": "debit",
        "name": "Industrial filter",
        "productCode": "FILTER-01",
        "quantity": "2",
        "unitOfMeasure": "each",
        "unitAmount": "50.00",
        "totalAmount": "100.00",
        "taxAmount": "8.00"
      }
    ],
    "shipsFromPostalCode": "60601"
  }
}

StatusMeaning
400The body does not match the contract, or it contains credentials or card data.
422{"error": {"type": "validation_error", "issues": [{code, path, message}]}}. The invoice cannot produce valid Level 2/3 fields.

Enrichment fields

Amounts are Braintree decimal strings, such as "107.50". These keys are accepted unchanged by both gateway.transaction.sale and gateway.transaction.submitForSettlement.

FieldRule
amountTransaction amount; the full invoice total.
orderIdThe invoice number.
purchaseOrderNumberThe buyer's PO, up to 17 characters.
taxAmount / shippingAmount / discountAmountTransaction-level amounts from the invoice.
shipsFromPostalCodePresent only when you supplied it.
lineItems[].kindAlways "debit".
lineItems[].nameUp to 35 characters.
lineItems[].descriptionOptional, up to 127 characters.
lineItems[].productCodeSKU, up to 12 characters.
lineItems[].commodityCodeOptional, up to 12 characters.
lineItems[].quantityDecimal string with at most 4 fraction digits.
lineItems[].unitOfMeasureUp to 12 characters.
lineItems[].unitAmountUnit price.
lineItems[].totalAmountquantity × unitAmount, before tax and discount.
lineItems[].taxAmountOnly when the invoice has line-level tax.
lineItems[].discountAmountOnly when the line has a discount.

Up to 249 line items. Carden checks that line totals plus tax and shipping minus discount equal amount.

Merge into your Braintree call

Spread data into your own gateway.transaction.sale request alongside your paymentMethodNonce. For auth-then-capture, pass data.amount as the settlement amount and the remaining fields as options to gateway.transaction.submitForSettlement. Carden never receives your nonce, card data, or gateway credentials.

  • Save preparation.id with the payment attempt and send it as enrichmentRequestId when you report.
  • Do not merge the preparation object into the Braintree request.
  • A Carden error never justifies retrying a Braintree sale. Reconcile Braintree state first.

Report a payment outcome

Endpoint
POST /api/v1/braintree/payment-reports

Requires payments:write. Report each change in the attempt with cumulative amounts. Reuse eventId only for identical retries; use a new eventId for each new observation of the same attemptId.

FieldRule
eventId / attemptIdRequired stable references, up to 160 characters.
transactionIdOptional Braintree transaction ID, lowercase letters and digits.
merchantAccountIdOptional Braintree merchant account ID.
statusauthorized, captured, partially_refunded, refunded, failed, canceled, or unknown.
currencyLowercase three-letter code.
amountMinor / capturedAmountMinor / refundedAmountMinorCumulative integer minor units. Captured cannot exceed amount; refunded cannot exceed captured.
occurredAtISO 8601 timestamp with offset.
enrichmentRequestIdOptional preparation.id from the enrichment response.
invoiceReference / errorCode / providerEventIdOptional references; errorCode is a lowercase snake_case code.
source"merchant_webhook" or "api".
Braintree statusCarden status
authorizedauthorized
submitted_for_settlement, settling, settlement_pending, settledcaptured, or partially_refunded / refunded from cumulative refunds
voidedcanceled
processor_declined, gateway_rejected, settlement_declined, failedfailed

Report a Braintree payment outcome

curl https://www.cardenpay.com/api/v1/braintree/payment-reports \
  -H "Authorization: Bearer $CARDEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"eventId":"report_attempt_1042_captured_1","attemptId":"attempt_1042_1","transactionId":"k7m2p9qx","status":"captured","currency":"usd","amountMinor":11300,"capturedAmountMinor":11300,"refundedAmountMinor":0,"occurredAt":"2026-01-01T12:01:00.000Z","enrichmentRequestId":"0b6f3e2d-9c1a-4f7e-8d5b-3a2c1e0f9d84","invoiceReference":"INV-1042","source":"api"}'

200 OK
{
  "object": "braintree.payment_report",
  "api_version": "v1",
  "data": {
    "id": "report_example",
    "duplicate": false
  }
}

duplicate: true acknowledges an identical retry. A 409 means the eventId already identifies a different report, or the currency or cumulative amounts conflict with earlier reports.

Preparation issue codes

CodeMeaning
missing_purchase_order_numberThe invoice has no buyer PO.
purchase_order_number_too_longThe PO is longer than 17 characters.
purchase_order_number_invalidThe PO is not printable ASCII.
missing_product_codeA line has no SKU or merchant-confirmed product code.
missing_unit_of_measureA line has no merchant-confirmed unit.
identifier_too_longA product code, commodity code, or unit exceeds Braintree's limit.
identifier_invalidAn identifier is not printable ASCII.
invalid_quantityA quantity is not positive or needs more than 4 fraction digits.
unsupported_currencyThe invoice is not in USD.
missing_item_referenceA QuickBooks line has no item reference.
missing_line_taxLine-level tax is missing on a line.
arithmetic_mismatchLine, tax, shipping, discount, or total amounts do not reconcile.
payment_amount_mismatchamountMinor does not equal the invoice total.
invoice_not_openThe invoice is not open or was voided.
invoice_balance_not_fullPart of the invoice is already paid.
  • Identifiers (PO number, SKU, commodity code, unit) are rejected when too long, never truncated.
  • Descriptive names and descriptions are shortened to Braintree's limits.
  • Carden never invents a PO number, SKU, unit, or tax amount.
  • For checkout readiness, a PO, SKU, or unit gap downgrades the payment to ordinary (no Level 2/3 fields) instead of blocking it.

Braintree webhook endpoint

Endpoint
POST /api/integrations/braintree/webhooks/{endpointId}

Braintree posts form-encoded bt_signature and bt_payload values. Carden verifies the signature with the merchant's restricted API key and records the notification once. You configure this URL in Braintree; you do not call it.

StatusBody or code
200{"received": true, "kind", "status", "duplicate"}
400invalid_signature or invalid_event
404endpoint_not_found
409credentials_required or connection_unavailable
410endpoint_disabled