Tradesmen Technologies Tradesmen Technologies

API reference Payments

Payments API (TalusPay Connect)

The Payments API handles payment processing via TalusPay Connect, including transactions, merchant onboarding, and customer vault management.

Base Path

/prod/payments

Endpoints

Create Merchant (Automated Onboarding)

Creates a new merchant account via the TalusPay Onboarding API and generates an onboarding link. Admin-only.

  • Path: /payments/merchants
  • Method: POST
  • Auth Required: Yes (Bearer token, Admin role)

Request Body

{
  "phone": "1500500500",
  "redirectUrl": "https://example.com/onboarding-complete",
  "merchant": {
    "legal_business_name": "string",
    "legal_phone": "string",
    "business_phone": "string",
    "business_type": "Sole Proprietor",
    "tin": "string",
    "tin_type": "EIN",
    "doing_business_as": "string",
    "business_established_date": "string",
    "bank_account": {
      "bank_name": "string",
      "routing_number": "string",
      "account_holder_name": "string",
      "account_number": "string",
      "account_number_confirm": "string"
    },
    "legal_business_address": {
      "address": "string",
      "city": "string",
      "state": "string",
      "zip": "string"
    },
    "dba_address": {
      "address": "string",
      "city": "string",
      "state": "string",
      "zip": "string"
    },
    "owner_one": {
      "first_name": "string",
      "last_name": "string",
      "middle_name": "string",
      "contact_phone": "string",
      "job_title": "President",
      "ownership_percentage": "25",
      "email": "string",
      "date_of_birth": "string",
      "home_address": {
        "address": "string",
        "city": "string",
        "state": "string",
        "zip": "string"
      },
      "ssn": "string"
    },
    "owner_two": {},
    "owner_three": {},
    "owner_four": {},
    "main_product": {
      "description": "string",
      "website": "string",
      "category": "Construction",
      "subcategory": "Special Trade Contractors, not otherwise listed"
    },
    "main_contact_person": {
      "name": "string",
      "email": "string"
    },
    "current_sales": {
      "average_monthly_in_credit_card": "string",
      "average_ticket_value": "string",
      "highest_amount_to_date": "string",
      "sales_percentage": {
        "card_swipe_percentage": "string (required, must sum to 100 with online + keyed)",
        "online_percentage": "string (required)",
        "keyed_percentage": "string (required)",
        "moto_percentage": "string (optional, do not include in sum)"
      },
      "average_amex_monthly_sales": "string",
      "average_amex_ticket_value": "string"
    },
    "capabilities": {
      "types": ["two_tiered", "ach"],
      "options": {}
    },
    "fees": {
      "monthly": {
        "minimum_processing_fee": 35,
        "merchant_advance_service_charge": 35
      }
    }
  },
  "device": {
    "imei": "357111112222333"
  },
  "agent": 0
}

Note: phone and redirectUrl are required. The top-level phone field accepts any common US phone format (10 digits, with or without +1, dashes, dots, parentheses, or spaces) and is normalized to digits only (10 or 11 digits, e.g. 3035551234 or 13035551234) before being sent to TalusPay — TalusPay's top-level validator caps the value at 11 characters, so E.164 is not accepted here. Phone fields supplied inside the merchant prefill (legal_phone, business_phone, dba_phone, and owner_*.contact_phone) are normalized to E.164 (e.g. +13035551234), which is what TalusPay's merchant form requires. The request returns 400 Bad Request if any phone value can't be parsed to a 10- or 11-digit US number. All other fields are optional and are used to prefill the merchant's TalusPay onboarding application. redirectUrl is where TalusPay redirects the merchant after they complete the onboarding form. How prefill is applied: the merchant is created at TalusPay with phone only — TalusPay rejects any partial merchant payload on create, so we don't supply one. Immediately after, the caller's merchant fields are sent to TalusPay via PATCH /v1/merchants/{merchant_id}. If the PATCH fails, the merchant record still exists and the response still returns the onboardingUrl; the failure is logged and the merchant can fill in everything via TalusPay's hosted form. See the TalusPay Create Merchant API docs for full field details. owner_two, owner_three, and owner_four follow the same structure as owner_one.

If a merchant record already exists for the company, the endpoint returns 409 Conflict unless the existing status is REJECTED, in which case a new merchant is created (re-application).

Response

  • Success: 201 Created
    {
      "merchantId": "string",
      "onboardingUrl": "string"
    }
    
  • Error: 400 Bad Request, 401 Unauthorized, 403 Forbidden, 409 Conflict, or 500 Internal Server Error

Get Merchant Status

Retrieves the onboarding status of the company's merchant account from TalusPay. Admin-only.

  • Path: /payments/merchants/status
  • Method: GET
  • Auth Required: Yes (Bearer token, Admin role)

Response

  • Success: 200 OK
    {
      "merchantId": "string",
      "onboardingStatus": "PENDING",
      "paymentEnabled": false,
      "talusPayPublicKey": "string",
      "details": {}
    }
    

onboardingStatus values: PENDING, IN_REVIEW, APPROVED, REJECTED

paymentEnabled is true only when onboardingStatus is APPROVED.

talusPayPublicKey is only included when paymentEnabled is true and the key exists. Used by the app to initialize the payment tokenizer.

  • Error: 401 Unauthorized, 403 Forbidden, 404 Not Found, or 500 Internal Server Error

Generates a new onboarding link for an existing merchant. Useful for resuming an incomplete onboarding flow. Admin-only.

  • Path: /payments/merchants/onboarding-link
  • Method: POST
  • Auth Required: Yes (Bearer token, Admin role)

Request Body

{
  "redirectUrl": "https://example.com/onboarding-complete"
}

Note: redirectUrl is required. This is where TalusPay redirects the merchant after they complete the onboarding form.

Response

  • Success: 200 OK
    {
      "onboardingUrl": "string"
    }
    
  • Error: 400 Bad Request (missing redirectUrl), 401 Unauthorized, 403 Forbidden, 404 Not Found, or 500 Internal Server Error

Save Merchant Credentials (manual onboarding)

Stores a merchant's TalusPay gateway credentials directly, for merchants set up outside the automated onboarding flow. Overwrites the company's merchant record (a record created by Create Merchant loses its onboardingStatus). Admin-only; intended for platform operations, not the app.

  • Path: /payments/onboard
  • Method: POST
  • Auth Required: Yes (Bearer token, Admin role)

Request Body

{
  "talusPayApiKey": "string",
  "talusPayPublicKey": "string",
  "merchantId": "string"
}

Note: all three fields are required.

Response

  • Success: 200 OK
    {
      "message": "Merchant credentials saved successfully"
    }
    
  • Error: 400 Bad Request, 401 Unauthorized, 403 Forbidden, or 500 Internal Server Error

Create Transaction

Creates a payment transaction. Supports card, token, vault, card-present, and EMV payment methods.

  • Path: /payments/transaction
  • Method: POST
  • Auth Required: Depends on payment method (see below)

Request Body

Card (keyed) — No auth required:

{
  "companyId": "string",
  "documentId": "string",
  "documentCode": "string",
  "amount": 100.50,
  "paymentMethod": "card",
  "number": "4111111111111111",
  "expiration_date": "1225",
  "cvc": "123"
}

Token (card) — No auth required:

{
  "companyId": "string",
  "documentId": "string",
  "documentCode": "string",
  "amount": 110.50,
  "paymentMethod": "token",
  "token": "string",
  "cardholderName": "string",
  "source": "docWebClient",
  "tipAmount": 10.00,
  "tipPercentage": 10,
  "saveCard": true,
  "customerId": "string",
  "billingAddress": {
    "firstName": "string",
    "lastName": "string",
    "addressLine1": "string",
    "city": "string",
    "state": "string",
    "postalCode": "string",
    "phone": "string",
    "email": "string"
  }
}

Note: billingAddress is optional for card tokens; when present it is forwarded to TalusPay for AVS. The doc web client collects these fields inside the TalusPay tokenizer frame and returns them on the tokenization response.

Token (ACH) — No auth required:

{
  "companyId": "string",
  "documentId": "string",
  "documentCode": "string",
  "amount": 100.50,
  "paymentMethod": "token",
  "paymentType": "ach",
  "token": "string",
  "billingAddress": {
    "firstName": "string",
    "lastName": "string",
    "addressLine1": "string",
    "city": "string",
    "state": "string",
    "postalCode": "string",
    "phone": "string",
    "email": "string"
  }
}

Card-present (swiped/tapped) — Bearer token required:

{
  "documentId": "string",
  "documentCode": "string",
  "amount": 100.50,
  "paymentMethod": "cardPresent",
  "track1": "string",
  "track2": "string",
  "encryptedTrack1": "string",
  "encryptedTrack2": "string",
  "ksn": "string",
  "expirationDate": "string",
  "cvc": "string"
}

Note: companyId is derived from the auth token. At least one of track1/track2 (decrypted) or encryptedTrack1/encryptedTrack2 (encrypted) is required. ksn is needed for encrypted readers. expirationDate and cvc are optional.

EMV (chip-dip/NFC tap) — Bearer token required:

{
  "documentId": "string",
  "documentCode": "string",
  "amount": 100.50,
  "paymentMethod": "emv",
  "tlvData": {
    "9F26": "AABBCCDDEE112233",
    "9F27": "80",
    "9F10": "0110A00003240000"
  },
  "deviceSerialNumber": "string"
}

Note: companyId is derived from the auth token. tlvData is a required map of EMV tag IDs to hex-encoded TLV packet values. deviceSerialNumber is optional.

Payment Methods:

  • card — keyed card number entry; requires number, expiration_date, optional cvc
  • token — requires token (from TalusPay tokenization). For ACH tokens (paymentType: "ach"), billingAddress (account holder's name, address, phone, and email) is required by the ACH processor. For card tokens it is optional and used for AVS. The doc web client collects these fields in the tokenizer frame for both payment types.
  • customer — requires customer_id, optional payment_method_id and payment_method_type
  • cardPresent — swiped/tapped card via card reader; requires Bearer token authentication
  • emv — chip-dip or NFC tap via EMV reader; requires Bearer token authentication

documentId / documentCode (paying a document): both are optional, but documentCode is required whenever documentId is sent (400 otherwise, before anything is charged) and must match the document's code (403 "Invalid document code"). An approved payment that names a document marks it PAID, so the request has to prove possession of the document's link; a payment without a documentId is recorded against the company only.

Optional tip fields (tipAmount, tipPercentage): When the payer adds a tip on the doc web client (invoices only), include tipAmount (the tip in dollars, already folded into amount) and optionally tipPercentage (the chosen percentage). On an approved transaction the tip is recorded on the payment record and on the document (tipAmount, tipPercentage). tipAmount must be a non-negative number; tipPercentage, when present, must be in (0, 100]. amount is always the full charge, inclusive of any tip and additional charges — the server does not re-derive it.

Optional payment-time fee fields (paymentFees, paymentFeeAmount): A company charge configured with appliesTo: "PAYMENT" (see Update Company in accounts-endpoints.md) is a fee added only when the customer pays electronically — a card (keyed, tapped, saved or on the emailed document page), a bank account unless the charge is waivedForAch, or "Pay over time". The caller computes each applicable fee as its percentage of the amount due being paid (before any tip), folds the total into amount, and reports them here: paymentFees is an array of { type, label, percentage, amount } (each amount in dollars, rounded to cents; same type/label rules as additionalCharges), and paymentFeeAmount (optional) is their sum in dollars — when sent it must equal the sum to the cent (400 otherwise). The document page lists the company's current fees under paymentFeeSchedule (see Publicly View Document in jobs-endpoints.md). On an approved transaction the fees are recorded on the payment record (paymentFeeAmount, in cents) and on the document (paymentFeeAmount in dollars plus the paymentFees list), where they stay once the document is paid; a declined transaction records nothing. Omitted by older clients and by payments that carry no fee. paymentType (card or ach, also accepted as payment_method_type on customer payments) is stored on the payment record when sent.

Optional cardholderName field (token card payments): When the tokenizer is configured to collect the cardholder name, the client sends the entered name here. It is stored verbatim on the payment record (returned by GET /payments/transactions) and does not affect the transaction result. Optional — omitted by older clients and by flows that don't collect a name.

Optional saveCard + customerId fields (save-card-on-charge, card tokens only): When saveCard is true and a customerId is supplied, the keyed card is saved to that client's vault and the charge runs against the saved method — the card is both stored on file and charged in one request. Because TalusPay tokenizer tokens are single-use, the token is consumed by vaulting and the sale runs against the resulting vault payment method (equivalent to a subsequent paymentMethod: "customer" charge). Saving reuses the client's existing vault customer if present, otherwise creates one (so the card later appears in GET /payments/customers/{customerId}/payment-methods). Ignored for ACH tokens (paymentType: "ach"). Best-effort: if vaulting fails the charge falls back to the raw token so the payment still goes through (the card just isn't saved). Both fields are optional and omitted by older clients.

Optional source field (company notifications): When a payment is made from the customer-facing doc web client, include "source": "docWebClient" in the request body. On an approved transaction this triggers a notification email to the company (the business that owns the document) with the customer's contact details (name, email, phone, address) and a link to the document — "deposit paid" for an estimate, or "invoice paid" for an invoice. Omit the field (or send any other value) for in-app/in-person payments to suppress the email. The notification is best-effort and never affects the transaction result. A parallel "estimate accepted" notification is sent automatically when a customer accepts an estimate via POST /jobs/documents/{documentId}/public/accept (always from the doc web client, so no flag is needed there).

Response

  • Success: 200 OK
    {
      "approved": true,
      "transactionId": "string",
      "responseCode": "100",
      "responseText": "APPROVED",
      "authCode": "string"
    }
    
  • Error: 400 Bad Request, 401 Unauthorized (card-present/EMV only), 403 Forbidden, or 500 Internal Server Error

Refund Transaction

Refunds a previously approved transaction. Supports partial refunds.

  • Path: /payments/transaction/{transactionId}/refund
  • Method: POST
  • Auth Required: Yes (Bearer token)

Request Body

{
  "amount": 50.00
}

Note: amount is optional. If omitted, the full transaction amount is refunded.

Pay over time (Stripe) payments use this same endpoint with their pi_… transaction id: the refund is issued on the company's Stripe account instead of TalusPay, amount must be positive and at most the unrefunded remainder (omit it for the full remainder), responseCode is null and responseText is the Stripe refund status. Extra errors on that path: 404 (not one of this company's Stripe payments) and 409 (already fully refunded). See stripe-endpoints.md.

Response

  • Success: 200 OK
    {
      "success": true,
      "transactionId": "string",
      "responseCode": "100",
      "responseText": "APPROVED"
    }
    
  • Error: 400 Bad Request, 401 Unauthorized, or 500 Internal Server Error

Void Transaction

Voids a transaction that has not yet settled.

  • Path: /payments/transaction/{transactionId}/void
  • Method: POST
  • Auth Required: Yes (Bearer token)

Request Body

None required.

Response

  • Success: 200 OK
    {
      "success": true,
      "message": "string"
    }
    
  • Error: 400 Bad Request, 401 Unauthorized, or 500 Internal Server Error

Pay over time (Stripe, pi_… ids) payments cannot be voided: 400 with "Pay over time payments cannot be voided; refund them instead".


Capture Transaction

Captures a previously authorized transaction.

  • Path: /payments/transaction/{transactionId}/capture
  • Method: POST
  • Auth Required: Yes (Bearer token)

Request Body

{
  "amount": 100.00
}

Note: amount is optional. If omitted, the full authorized amount is captured.

Pay over time (Stripe, pi_… ids) payments are captured immediately: 400 with "Pay over time payments cannot be captured; refund them instead".

Response

  • Success: 200 OK
    {
      "approved": true,
      "transactionId": "string",
      "responseCode": "100",
      "responseText": "APPROVED"
    }
    
  • Error: 400 Bad Request, 401 Unauthorized, or 500 Internal Server Error

Create Vault Customer

Creates a tokenized customer in TalusPay's vault.

  • Path: /payments/vault/customers
  • Method: POST
  • Auth Required: Yes (Bearer token)

Request Body

{
  "customerId": "string",
  "firstName": "string",
  "lastName": "string",
  "email": "string",
  "phone": "string"
}

Note: Only customerId is required. All other fields are optional.

Response

  • Success: 201 Created
    {
      "vaultCustomerId": "string",
      "customerId": "string"
    }
    
  • Error: 400 Bad Request, 401 Unauthorized, or 500 Internal Server Error

Get Vault Customer

Retrieves a vault customer's details and stored payment methods.

  • Path: /payments/vault/customers/{vaultCustomerId}
  • Method: GET
  • Auth Required: Yes (Bearer token)

Response

  • Success: 200 OK
    {
      "companyId": "string",
      "vaultCustomerId": "string",
      "customerId": "string",
      "firstName": "string",
      "lastName": "string",
      "email": "string",
      "phone": "string",
      "createdAt": "2025-03-15T10:00:00.000Z",
      "vaultData": {}
    }
    
    Note: firstName, lastName, email and phone are the values given at creation (null when omitted). vaultData contains the full customer record and stored payment methods from TalusPay.
  • Error: 400 Bad Request, 401 Unauthorized, 404 Not Found, or 500 Internal Server Error

Add Card to Vault

Adds a card payment method to a vault customer.

  • Path: /payments/vault/customers/{vaultCustomerId}/card
  • Method: POST
  • Auth Required: Yes (Bearer token)

Request Body

{
  "number": "4111111111111111",
  "expiration_date": "1225"
}

Note: Both number and expiration_date are required.

Response

  • Success: 201 Created
    {
      "success": true,
      "paymentMethodId": "string",
      "data": {}
    }
    
    Note: data contains the full response from TalusPay.
  • Error: 400 Bad Request, 401 Unauthorized, 404 Not Found, or 500 Internal Server Error

Add ACH to Vault

Adds an ACH payment method to a vault customer.

  • Path: /payments/vault/customers/{vaultCustomerId}/ach
  • Method: POST
  • Auth Required: Yes (Bearer token)

Request Body

{
  "routing_number": "string",
  "account_number": "string",
  "account_type": "checking"
}

Note: routing_number, account_number, and account_type are required. account_type must be either "checking" or "savings". An optional sec_code field may also be provided.

Response

  • Success: 201 Created
    {
      "success": true,
      "paymentMethodId": "string",
      "data": {}
    }
    
    Note: data contains the full response from TalusPay.
  • Error: 400 Bad Request, 401 Unauthorized, 404 Not Found, or 500 Internal Server Error

Delete Vault Customer

Deletes a vault customer and all stored payment methods.

  • Path: /payments/vault/customers/{vaultCustomerId}
  • Method: DELETE
  • Auth Required: Yes (Bearer token)

Response

  • Success: 200 OK
    {
      "message": "Vault customer deleted successfully"
    }
    
  • Error: 400 Bad Request, 401 Unauthorized, 404 Not Found, or 500 Internal Server Error

Save Customer Payment Method (Card)

Saves a tokenized card payment method for a customer. If the customer does not yet have a vault record, one is created automatically using the customer's profile data.

  • Path: /payments/customers/{customerId}/payment-methods/card
  • Method: POST
  • Auth Required: Yes (Bearer token)

Request Body

Either supply a tokenizer-generated token:

{
  "token": "string"
}

Or supply raw card fields:

{
  "number": "4111111111111111",
  "expiration_date": "1225"
}

Note: token is preferred (produced by the TalusPay Tokenizer in the web client). Raw fields are accepted for server-to-server use.

Response

  • Success: 201 Created
    {
      "success": true,
      "vaultCustomerId": "string",
      "paymentMethodId": "string",
      "type": "card"
    }
    
  • Error: 400 Bad Request, 401 Unauthorized, 404 Not Found, 500 Internal Server Error, or 502 Bad Gateway (TalusPay vault creation failure)

Save Customer Payment Method (ACH)

Saves a tokenized ACH payment method for a customer. Creates a vault record for the customer if one does not already exist.

  • Path: /payments/customers/{customerId}/payment-methods/ach
  • Method: POST
  • Auth Required: Yes (Bearer token)

Request Body

Either supply a tokenizer-generated token:

{
  "token": "string"
}

Or supply raw ACH fields:

{
  "routing_number": "string",
  "account_number": "string",
  "account_type": "checking"
}

Note: account_type must be "checking" or "savings". An optional sec_code may also be provided.

Response

  • Success: 201 Created
    {
      "success": true,
      "vaultCustomerId": "string",
      "paymentMethodId": "string",
      "type": "ach"
    }
    
  • Error: 400 Bad Request, 401 Unauthorized, 404 Not Found, 500 Internal Server Error, or 502 Bad Gateway

List Customer Payment Methods

Returns all saved payment methods for a customer (cards and ACH accounts). Returns an empty list if the customer has no vault record.

  • Path: /payments/customers/{customerId}/payment-methods
  • Method: GET
  • Auth Required: Yes (Bearer token)

Response

  • Success: 200 OK
    {
      "vaultCustomerId": "string",
      "customerId": "string",
      "paymentMethods": [
        {
          "id": "string",
          "type": "card",
          "card_type": "visa",
          "masked_number": "411111******1111",
          "expiration_date": "02/27",
          "last_four": "1111"
        },
        {
          "id": "string",
          "type": "ach",
          "last_four": "2222"
        }
      ]
    }
    
    Note: Each payment method carries a type field ("card" or "ach") plus the full payment-method object from TalusPay. For cards this includes card_type, masked_number (e.g. "411111******1111"), and expiration_date; ACH methods carry the masked account details. TalusPay has no discrete last-4 field, so the API adds a normalized last_four (derived from the masked number) for convenience; it is omitted when it can't be determined. When no vault record exists yet, the response is {"vaultCustomerId": null, "paymentMethods": []} (no customerId field).
  • Error: 400 Bad Request, 401 Unauthorized, or 500 Internal Server Error

Delete Customer Payment Method

Deletes a single saved payment method from a customer's vault.

  • Path: /payments/customers/{customerId}/payment-methods/{paymentMethodId}
  • Method: DELETE
  • Auth Required: Yes (Bearer token)

Query Parameters

Parameter Required Description
type Yes "card" or "ach" — the type of the payment method being deleted

Response

  • Success: 200 OK
    {
      "message": "Payment method deleted successfully"
    }
    
  • Error: 400 Bad Request, 401 Unauthorized, 404 Not Found, or 500 Internal Server Error

Get Transactions

Retrieves transaction history and webhook events for the company within a date range. Admin-only.

  • Path: /payments/transactions
  • Method: GET
  • Auth Required: Yes (Bearer token, Admin role)

Query Parameters

Parameter Required Description
startDate Yes Start of the date range (ISO-8601)
endDate Yes End of the date range (ISO-8601)

Response

  • Success: 200 OK
    {
      "period": {
        "startDate": "2025-01-01T00:00:00.000Z",
        "endDate": "2025-12-31T23:59:59.999Z"
      },
      "transactions": [
        {
          "paymentId": "TXN#abc-123",
          "transactionId": "string",
          "amount": 10000,
          "status": "APPROVED",
          "responseCode": "100",
          "responseText": "APPROVED",
          "documentId": "string",
          "jobId": "string",
          "paymentMethod": "card",
          "originalTransactionId": null,
          "refundedAmount": null,
          "refundCount": null,
          "processor": "TALUSPAY",
          "disputeStatus": null,
          "createdAt": "2025-03-15T10:00:00.000Z"
        }
      ],
      "webhookEvents": [
        {
          "paymentId": "WEBHOOK#1234567890",
          "eventType": "transaction_create",
          "merchantId": "string",
          "transactionId": "string",
          "amount": 40000,
          "documentId": "string",
          "jobId": "string",
          "data": {},
          "apiVersion": "2024-07-06",
          "webhookCreatedAt": 1234567890,
          "createdAt": "2025-03-18T10:00:00.000Z"
        }
      ]
    }
    

Note: amount is in cents (integer). Transactions are sorted by createdAt descending (newest first). The paymentId prefix indicates the record type: TXN# (sale), REFUND#, VOID#, or CAPTURE#. The originalTransactionId field is present on refund, void, and capture records. On TXN# rows, refundedAmount (cents) and refundCount are populated once the sale has been refunded (partially or fully) and are null otherwise; the sale's status transitions to PARTIALLY_REFUNDED once any refund is recorded against it, REFUNDED when the cumulative refunded amount reaches the sale amount, or VOIDED when the sale is voided. paymentMethod is the value sent to Create Transaction (card, token, customer, cardPresent, emv; card when omitted) or tapToPay for a sale recorded by Record Tap to Pay Transaction (such a row has no transactionId when the device reported no gateway id). A TXN# row also carries tipAmount (cents) when the payer added a tip, paymentFeeAmount (cents) when a payment-time fee was charged (see Create Transaction), and paymentType (card or ach) when the caller reported it (card for Tap to Pay sales). processor is TALUSPAY or STRIPE. Stripe ("Pay over time") sales have paymentId TXN#stripe:{paymentIntentId}, transactionId = the Stripe PaymentIntent id (pi_…) and paymentMethod = the method the customer used (affirm, klarna, afterpay_clearpay, zip, sunbit); their refunds are REFUND#stripe:{paymentIntentId}:{cumulativeRefundedCents} rows. disputeStatus is the Stripe dispute status (needs_response, under_review, won, lost, …) on a disputed Stripe sale and null otherwise. Webhook events include the full TalusPay payload in the data field. The transactionId field on webhook events links the event to the corresponding transaction (null for non-transaction events like merchant onboarding). The documentId field is resolved by looking up the matching transaction record and is null if no match is found or for non-transaction events.

  • Error: 400 Bad Request, 401 Unauthorized, 403 Forbidden, or 500 Internal Server Error

Enums

MerchantOnboardingStatus

Value Description
PENDING Merchant created, onboarding not yet started or in progress
IN_REVIEW Merchant submitted onboarding, under review by TalusPay
APPROVED Merchant verified and approved for payment processing
REJECTED Merchant verification was rejected

TransactionStatus

Returned on transaction records from GET /payments/transactions.

Value Description
APPROVED Sale approved by the processor
DECLINED Sale declined by the processor
PENDING Sale is pending
ERROR Processor returned an error
PARTIALLY_REFUNDED Sale has been partially refunded; see refundedAmount and refundCount
REFUNDED Sale has been fully refunded, or the record is itself a successful refund
VOIDED Sale was voided before settlement, or the record is itself a successful void

TalusPay Response Codes

Code Meaning
100 Approved
200 Declined
300 Gateway Error

Tap to Pay (Android)

On-device contactless acceptance (Phos SDK via TalusPay). These two endpoints are served under the same base path as the rest of this API (/prod/payments/...).

No payment credential is embedded in the app binary: the app fetches Phos credentials from the credentials endpoint, runs the sale on-device with the Phos SDK (the third credential, license, is a static client-side string supplied by TalusPay), then reports the result to the record endpoint.

Get Tap to Pay Credentials

Returns the Tap-to-Pay credentials for the caller's merchant. Any authenticated employee of a payment-enabled company may call it (not admin-gated).

  • Path: /payments/tap-to-pay/credentials
  • Method: GET
  • Auth Required: Yes (Bearer token)

Response

{
  "token": "string",
  "issuer": "string",
  "merchantId": "string",
  "apiKey": "string"
}

Field notes:

  • apiKey — the credential the on-device Phos SDK needs for its fetchPhosCredentials(merchantId) call. Treat as a secret: keep it in memory only, never persist or log it.
  • token / issuer — a pre-minted Phos token, kept for older app builds that consumed it directly. Newer builds ignore it and fetch credentials on-device using apiKey + merchantId.

400 if the company has no merchant set up; 409 if the merchant is not enabled for Tap to Pay; 502 if TalusPay returns no token/issuer.

Record Tap to Pay Transaction

Records an already-charged on-device sale: writes the payment row, marks the document PAID, advances the job, and increments the job's denormalized paid-amount counter. It does not call the gateway (the Phos SDK already charged). The paid-amount ADD is keyed on SALE:<gatewayTransactionId> — the same key the TalusPay transaction webhook uses — so a webhook echo of the same sale is counted only once.

  • Path: /payments/tap-to-pay/transaction
  • Method: POST
  • Auth Required: Yes (Bearer token)

Request Body

{
  "documentId": "string",
  "documentCode": "string",
  "amount": 11.80,
  "tipAmount": 1.50,
  "tipPercentage": 15,
  "paymentFeeAmount": 0.30,
  "paymentFees": [
    { "type": "CONVENIENCE", "label": "Card Processing Fee", "percentage": 3, "amount": 0.30 }
  ],
  "gatewayTransactionId": "string"
}

amount is dollars and includes any tip and payment-time fee. gatewayTransactionId is the gateway transaction id reported by the on-device sale (used as the dedupe key against the webhook). documentId/documentCode/tip*/paymentFee* are optional; paymentFees / paymentFeeAmount follow the same rules as on Create Transaction (a tap is a card payment, so every PAYMENT charge applies) and are recorded on the payment row and the document the same way.

Response

{ "success": true, "paymentId": "TXN#<uuid>" }

400 for an invalid amount/tip/fee; 403 for an invalid document code.