Skip to content

Gifting API

API reference

Every endpoint, field and webhook event in the Backer Gifting API: 26 endpoints, version 2026-11-06.

Basics

Base URLhttps://backer.com/restapi/v2. A sandbox host comes with your credentials.
AuthenticationOAuth2 client credentials: POST /v2/oauth/token, then Authorization: Bearer <accessToken> on every other call.
FormatJSON request and response bodies with camelCase keys. Money in integer cents.
Rate limits300 requests per minute and 20 requests per second per partner; over either, 429 Too Many Requests.
Version2026-11-06
ExamplesThe request and response bodies below are illustrative, built from the schemas: real IDs, amounts and dates differ.

REST API for integrating Backer's 529 gifting platform into a partner product. Partners manage customers, accounts, payment methods, contributions, and transactions via this API, and redirect customers to Backer-hosted pages (payment-method collection) via short-lived signed URLs.

All requests and responses are JSON with camelCase keys.

Authentication uses OAuth2 client_credentials. Partners exchange a clientId + clientSecret at POST /v2/oauth/token for a short-lived bearer access token, then pass it via Authorization: Bearer <accessToken> on every subsequent call. The access-token TTL is configured server-side; when expiresIn elapses or the API returns invalid_token, partners reauthenticate by calling POST /v2/oauth/token again with their clientId + clientSecret.

Rate limiting: 300 requests per minute and 20 requests per second per partner. Exceeding either limit returns 429 Too Many Requests.

Authentication

POST /v2/oauth/token

Exchange credentials for a bearer access token

Implements RFC 6749 §4.4 (client_credentials). Returns a short-lived JWT access token. When the token expires, call this endpoint again with the same clientId + clientSecret to obtain a new one.

  • grantType=client_credentials: supply clientId + clientSecret (provisioned out-of-band by Backer).

Errors follow RFC 6749 §5.2 and use HTTP 400:

  • invalid_client: unknown clientId or wrong clientSecret.
  • unsupported_grant_type: grantType is not one of the supported values.
  • invalid_request: grantType missing or otherwise malformed.

This endpoint is unauthenticated – do not send the Authorization header.

Request body – OAuthTokenRequest

POST /v2/oauth/token request body
Field Type Description
grantType Required string OAuth2 grant type. One of client_credentials
clientId Required string Partner's public client id.
clientSecret Required string Partner's secret.
Example request
{
  "grantType": "client_credentials",
  "clientId": "string",
  "clientSecret": "string"
}

Responses

Example 200 response
{
  "accessToken": "string",
  "tokenType": "Bearer",
  "expiresIn": 0
}

Customers

POST /v2/customers

Register a customer with Backer

Registers a partner customer (registry owner or gift giver) with Backer. Must be called before creating an account or submitting a payment on behalf of the customer.

clientCustomerId is optional. When provided, it must be unique within the partner's namespace.

Request body – CreateCustomerRequest

POST /v2/customers request body
Field Type Description
clientCustomerId string Partner's unique identifier for the customer. Optional; when provided, it must be unique within the partner's namespace.
email Required string (email)
firstName string
lastName string
Example request
{
  "clientCustomerId": "string",
  "email": "giver@example.com",
  "firstName": "string",
  "lastName": "string"
}

Responses

Example 200 response
{
  "customerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "clientCustomerId": "string",
  "email": "giver@example.com",
  "firstName": "string",
  "lastName": "string",
  "status": "active"
}
GET /v2/customers

Get a customer by clientCustomerId

Looks up a customer by the partner-supplied clientCustomerId, scoped to the calling partner. To fetch by the Backer customer ID instead, use GET /v2/customers/{customerId}.

Parameters

clientCustomerId query, string , required – Partner-supplied customer identifier (clientCustomerId on CreateCustomerRequest).

Responses

Example 200 response
{
  "customerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "clientCustomerId": "string",
  "email": "giver@example.com",
  "firstName": "string",
  "lastName": "string",
  "status": "active"
}
GET /v2/customers/{customerId}

Get a customer by Backer customer id

Parameters

customerId path, string (uuid) , required – Backer customer UUID.

Responses

Example 200 response
{
  "customerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "clientCustomerId": "string",
  "email": "giver@example.com",
  "firstName": "string",
  "lastName": "string",
  "status": "active"
}
POST /v2/customers/{customerId}

Update a customer's details

Updates mutable fields on an existing customer. All fields are optional; at least one must be provided.

Supported updates:

  • clientCustomerId – partner's unique identifier for the customer
  • email
  • firstName
  • lastName

Parameters

customerId path, string (uuid) , required – Backer customer UUID.

Request body – UpdateCustomerRequest

POST /v2/customers/{customerId} request body
Field Type Description
clientCustomerId string Updated partner-unique identifier for the customer.
email string (email)
firstName string
lastName string
Example request
null

Responses

Example 200 response
{
  "customerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "clientCustomerId": "string",
  "email": "giver@example.com",
  "firstName": "string",
  "lastName": "string",
  "status": "active"
}
POST /v2/customers/{customerId}/status

Activate, deactivate, or put a customer on hold

Sets a customer's status.

  • active – reactivates a customer that is inactive or on hold. Reactivates their accounts (when coming from inactive) or their pending contributions (when coming from on hold).
  • inactive – deactivates the customer: cancels their contributions and deactivates their accounts. The customer is not emailed.
  • hold – places the customer on hold and opens an internal Backer support ticket for review.

statusReason is required when setting inactive or hold; it is ignored when setting active. A missing reason returns 422 with a statusReason field error (errorCode=missing_value); an unsupported status returns 422 with errorCode=invalid_value.

Parameters

customerId path, string (uuid) , required – Backer customer UUID.

Request body – SetCustomerStatusRequest

POST /v2/customers/{customerId}/status request body
Field Type Description
status Required string Target status for the customer. One of active inactive hold
statusReason string Reason for the status change. Required when status is inactive or hold.
Example request
{
  "status": "active",
  "statusReason": "string"
}

Responses

Example 200 response
{
  "customerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "clientCustomerId": "string",
  "email": "giver@example.com",
  "firstName": "string",
  "lastName": "string",
  "status": "active",
  "statusReason": "string"
}

Payment methods

POST /v2/customers/{customerId}/add-payment-method-sessions

Create a signed URL to the hosted payment-method page

Returns a short-lived signed URL that authenticates the customer's session on the Backer-hosted payment-method page. Redirect the customer to this URL to collect a card or bank account.

Once collected, the payment method appears in GET /v2/customers/{customerId}/payment-methods.

Customer eligibility:

  • Returns 422 with error.errorCode=customer_on_hold when the customer is on hold.
  • Returns 422 with error.errorCode=customer_inactive when the customer is inactive.

Parameters

customerId path, string (uuid) , required – Backer customer UUID.

Request body – CreatePaymentMethodSessionRequest

POST /v2/customers/{customerId}/add-payment-method-sessions request body
Field Type Description
successUrl Required string (uri) Absolute http(s) URL the hosted page redirects to on completion.
cancelUrl Required string (uri) Absolute http(s) URL the hosted page redirects to on exit/cancel.
type Required string Payment method type to collect. Locks the hosted page to a single rail – ACH shows only the bank-account form; card shows only the card form. Switching between rails is not permitted once the session is created. One of ach card
metadata string Optional opaque partner-defined string echoed back to successUrl as the metadata query parameter when the customer finishes adding a payment method. Useful for correlating the resulting payment method with a partner-side order, cart, or wishlist. The value is passed through verbatim – partners are free to choose its format (e.g. JSON, base64, opaque token) and parse it on successUrl.
platformFeeInCents integer Platform fee in cents shown on the hosted payment-method page (e.g. "$1.99 convenience fee"). Omit or set to 0 to hide the convenience fee line on ACH; card pages still show the 3% processing fee disclaimer.
Example request
{
  "successUrl": "https://example.com",
  "cancelUrl": "https://example.com",
  "type": "ach",
  "metadata": "string",
  "platformFeeInCents": 0
}

Responses

Example 200 response
{
  "url": "https://example.com"
}
GET /v2/customers/{customerId}/payment-methods

List saved payment methods for a customer

Parameters

customerId path, string (uuid) , required – Backer customer UUID.

Responses

Example 200 response
[
  {
    "paymentMethodId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "type": "ach",
    "bankAccount": {
      "lastFour": "string",
      "bankInstitutionName": "string",
      "bankAccountType": "string",
      "accountHolderName": "string"
    }
  }
]
GET /v2/customers/{customerId}/payment-methods/{paymentMethodId}

Get a saved payment method by id

Parameters

customerId path, string (uuid) , required – Backer customer UUID.
paymentMethodId path, string (uuid) , required – Backer payment method UUID.

Responses

Example 200 response
{
  "paymentMethodId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "type": "ach",
  "bankAccount": {
    "lastFour": "string",
    "bankInstitutionName": "string",
    "bankAccountType": "string",
    "accountHolderName": "string"
  }
}
DELETE /v2/customers/{customerId}/payment-methods/{paymentMethodId}

Delete a saved payment method

Removes a saved payment method (card or bank account). Returns the deleted payment method – same shape as GET /v2/customers/{customerId}/payment-methods/{paymentMethodId}.

Parameters

customerId path, string (uuid) , required – Backer customer UUID.
paymentMethodId path, string (uuid) , required – Backer payment method UUID.

Responses

Example 200 response
{
  "paymentMethodId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "type": "ach",
  "bankAccount": {
    "lastFour": "string",
    "bankInstitutionName": "string",
    "bankAccountType": "string",
    "accountHolderName": "string"
  }
}

Plans and brokers

GET /v2/plans

List 529 plans

By default returns plans currently supported for direct linking (isSupported=true). Pass includeUnsupported=true to also include unsupported plans (isSupported=false). Soft-deleted plans are never returned.

Parameters

includeUnsupported query, boolean – When true, include plans that are not supported for direct linking. Defaults to false.

Responses

  • 200 Plans (supported only by default; all alive when includeUnsupported=true). – Plan[]
  • 401 Missing or invalid bearer token. – ActionErrorEnvelope
  • 429 Rate limit exceeded (300 requests/minute and 20 requests/second per partner). – ActionErrorEnvelope
Example 200 response
[
  {
    "planId": "string",
    "stateName": "string",
    "displayName": "string",
    "isSupported": true,
    "programManager": "string",
    "programDistributor": "string"
  }
]
GET /v2/brokers

List brokerage partners

By default returns brokerage partners currently supported and enabled for partner linking (isSupported=true). Each broker includes the plans associated with that broker for informational use during broker link flows.

Pass includeUnsupported=true to also include unsupported brokers (isSupported=false), such as partners that are configured but not yet enabled, and catalog-only brokers that are not yet launched. Unsupported brokers cannot be used with validate-account-number / link-account until launched.

Broker-held accounts validate and link against broker-level account number rules. An optional planId on validate-account-number and link-account identifies which underlying 529 plan the customer holds; the plan may have isSupported: false as long as it is in the selected broker's plan catalog and the broker itself has isSupported: true.

Parameters

includeUnsupported query, boolean – When true, also include unsupported brokers. Defaults to false.

Responses

  • 200 Brokers (supported/enabled only by default; full catalog when includeUnsupported=true). – Broker[]
  • 401 Missing or invalid bearer token. – ActionErrorEnvelope
  • 429 Rate limit exceeded (300 requests/minute and 20 requests/second per partner). – ActionErrorEnvelope
Example 200 response
[
  {
    "brokerId": "string",
    "name": "string",
    "isSupported": true,
    "plans": [
      {
        "planId": "string",
        "stateName": "string",
        "displayName": "string",
        "isSupported": true,
        "programManager": "string",
        "programDistributor": "string"
      }
    ]
  }
]

Accounts

POST /v2/customers/{customerId}/validate-account-number

Validate a 529 account number

Checks whether an account number matches the format expected for a direct 529 plan link and/or a brokerage-held 529 account before calling POST /v2/customers/{customerId}/link-account. Uses the same account-number validation rules as link-account.

At least one of brokerId or planId is required:

  • Plan only – planId + accountNumber (the plan must have isSupported: true in GET /v2/plans).
  • Broker only – brokerId + accountNumber (the broker must have isSupported: true in GET /v2/brokers).
  • Broker + plan – brokerId, optional planId, and accountNumber. planId may be any plan in the broker's catalog from GET /v2/brokers, regardless of the plan's own isSupported value; the broker must have isSupported: true.

Returns 422 with error.errorCode=broker_not_found when brokerId is unknown.

Returns 422 with error.errorCode=broker_not_available when the broker is not currently enabled.

Returns 422 with error.errorCode=broker_plan_mismatch when both brokerId and planId are sent but the plan is not serviced by the broker.

Returns 422 with error.errorCode=plan_not_found when planId is sent but does not match a known plan, or when a plan-only request references a plan whose isSupported value is false.

Returns 422 with error.errorCode=invalid_account_number when the account number does not match the expected format.

Parameters

customerId path, string (uuid) , required – Backer customer UUID.

Request body – ValidateAccountNumberRequest

POST /v2/customers/{customerId}/validate-account-number request body
Field Type Description
brokerId string Backer broker ID (from GET /v2/brokers).
planId string Backer plan ID. Required for plan-only validation. Optional with brokerId to identify the underlying 529 plan.
accountNumber Required string 529 account number to validate.
Example request
null

Responses

Example 200 response
{
  "valid": true
}
POST /v2/customers/{customerId}/link-account

Create an account backed by an existing 529 account

Creates a new account for the registry owner identified by customerId and links it to an existing 529 account that the owner has already opened. Use this when the partner has collected the account number out-of-band.

At least one of brokerId or planId is required (same rules as POST /v2/customers/{customerId}/validate-account-number).

Returns 422 with error.errorCode=broker_not_found, broker_not_available, or broker_plan_mismatch for broker validation failures.

Returns 422 with error.errorCode=invalid_account_number when the account number does not match the expected format.

Returns 422 with error.errorCode=plan_not_found when a plan-only link references an unknown or unsupported plan.

If the account number turns out to be invalid (delivered later via a transaction.failed webhook whose failureDetails.code indicates an invalid 529 account number), correct it via POST /v2/accounts/{accountId} once the registry owner provides the right number.

Customer eligibility:

  • Returns 422 with error.errorCode=customer_on_hold when the customer is on hold.
  • Returns 422 with error.errorCode=customer_inactive when the customer is inactive.

Parameters

customerId path, string (uuid) , required – Backer customer UUID.

Request body – LinkAccountRequest

POST /v2/customers/{customerId}/link-account request body
Field Type Description
brokerId string Backer broker ID with isSupported: true from GET /v2/brokers.
planId string Backer plan ID. Required with isSupported: true for direct plan linking. Optional with brokerId for brokerage-held accounts, where the plan's own isSupported value does not restrict broker linking.
accountNumber Required string Customer's existing 529 account number.
beneficiary Beneficiary
accountOwner AccountOwnerInput
isAccountOwnerBeneficiary boolean When true, the registry owner is also the beneficiary of the 529. beneficiary must be omitted in that case (422 if both are set). The owner's first/last name (resolved from existing customer data or the supplied accountOwner) becomes the account owner's first/last name.
Example request
null

Responses

Example 200 response
{
  "accountId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "broker": {
    "brokerId": "string",
    "name": "string",
    "isSupported": true
  },
  "plan": {
    "planId": "string",
    "name": "string",
    "stateName": "string"
  },
  "beneficiary": {
    "firstName": "string",
    "lastName": "string"
  },
  "accountOwner": {
    "email": "giver@example.com",
    "firstName": "string",
    "lastName": "string"
  },
  "isAccountOwnerBeneficiary": true,
  "status": "active",
  "userName": "string"
}
GET /v2/accounts/{accountId}/details

Get a linked 529 account by id

Parameters

accountId path, string (uuid) , required – Backer linked-account UUID.

Responses

Example 200 response
{
  "accountId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "broker": {
    "brokerId": "string",
    "name": "string",
    "isSupported": true
  },
  "plan": {
    "planId": "string",
    "name": "string",
    "stateName": "string"
  },
  "beneficiary": {
    "firstName": "string",
    "lastName": "string"
  },
  "accountOwner": {
    "email": "giver@example.com",
    "firstName": "string",
    "lastName": "string"
  },
  "isAccountOwnerBeneficiary": true,
  "status": "active",
  "userName": "string"
}
POST /v2/accounts/{accountId}

Update linked 529 account details

Updates mutable details on a linked 529 account.

Supported updates:

  • planId (Backer plan ID with isSupported: true from GET /v2/plans; re-validates the stored account number against the new plan)
  • accountNumber (re-validates against the current or updated plan)
  • beneficiary.firstName and beneficiary.lastName
  • accountOwner.firstName, accountOwner.lastName, and accountOwner.email (overwrites existing values)

At least one update field must be provided.

Returns 422 with error.errorCode=transactions_still_processing when the request changes planId or accountNumber while a contribution push to the 529 plan is scheduled or processing.

Returns 422 with error.errorCode=invalid_account_number when accountNumber or planId fails account-number validation against the target plan.

Parameters

accountId path, string (uuid) , required – Backer linked-account UUID.

Request body – UpdateAccountRequest

POST /v2/accounts/{accountId} request body
Field Type Description
planId string Backer plan ID with isSupported: true from GET /v2/plans.
accountNumber string Updated 529 account number.
beneficiary Beneficiary
accountOwner AccountOwnerInput
Example request
null

Responses

Example 200 response
{
  "accountId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "broker": {
    "brokerId": "string",
    "name": "string",
    "isSupported": true
  },
  "plan": {
    "planId": "string",
    "name": "string",
    "stateName": "string"
  },
  "beneficiary": {
    "firstName": "string",
    "lastName": "string"
  },
  "accountOwner": {
    "email": "giver@example.com",
    "firstName": "string",
    "lastName": "string"
  },
  "isAccountOwnerBeneficiary": true,
  "status": "active",
  "userName": "string"
}
POST /v2/accounts/{accountId}/status

Activate or deactivate a linked 529 account

Sets an account's status.

  • active – reactivates a deactivated account.
  • inactive – deactivates the account: cancels its contributions. The customer is not emailed.

Deactivating the customer's last account also deactivates the customer.

statusReason is required when setting inactive; it is ignored when setting active. A missing reason returns 422 with a statusReason field error (errorCode=missing_value); an unsupported status returns 422 with errorCode=invalid_value.

Parameters

accountId path, string (uuid) , required – Backer linked-account UUID.

Request body – SetAccountStatusRequest

POST /v2/accounts/{accountId}/status request body
Field Type Description
status Required string Target status for the account. One of active inactive
statusReason string Reason for the status change. Required when status is inactive.
Example request
{
  "status": "active",
  "statusReason": "string"
}

Responses

Example 200 response
{
  "accountId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "broker": {
    "brokerId": "string",
    "name": "string",
    "isSupported": true
  },
  "plan": {
    "planId": "string",
    "name": "string",
    "stateName": "string"
  },
  "beneficiary": {
    "firstName": "string",
    "lastName": "string"
  },
  "accountOwner": {
    "email": "giver@example.com",
    "firstName": "string",
    "lastName": "string"
  },
  "isAccountOwnerBeneficiary": true,
  "status": "active",
  "userName": "string",
  "statusReason": "string"
}
GET /v2/contribution-limits

Get 529 contribution limits for a linked account

Returns the minimum, one-time maximum, and recurring (monthly, annually) maximum contribution amounts (in cents) accepted by the linked 529 plan, for both ACH and card payment methods. Use these to validate amounts client-side before calling POST /v2/payments.

Card maximums are capped at 50000 cents ($500) to reflect the per-transaction card limit; ACH entries return the plan's native limits unchanged.

Parameters

accountId query, string (uuid) , required – Backer linked-account UUID.

Responses

Example 200 response
{
  "limits": [
    {
      "paymentMethodType": "ach",
      "minimumInCents": 2500,
      "maximumInCents": 2500,
      "maximumMonthlyInCents": 2500,
      "maximumAnnuallyInCents": 2500
    }
  ]
}

Contributions and transactions

GET /v2/contribution-fees

Quote fees for a prospective contribution

Returns the platform and processing fees that would be charged for a contribution with the given method and amount, plus the total amount the contributor would be charged (amountInCents + platformFeeInCents + processingFeeInCents).

Parameters

paymentMethodType query, string , required – How the contributor would pay; drives processingFeeInCents (card only).
amountInCents query, integer , required – Contribution amount in cents.
platformFeeInCents query, integer , required – Platform fee in cents to apply to this contribution.

Responses

Example 200 response
{
  "platformFeeInCents": 2500,
  "processingFeeInCents": 2500,
  "totalAmountInCents": 2500
}
POST /v2/contribution-quotes

Quote fees for a contribution, including optional extra items

Returns the platform and processing fees that would be charged for a contribution with the given method and amount, plus the total amount the contributor would be charged. Optional extraItems (amount + tax) are added to totalAmountInCents. Extra-item processing is returned on each item and is not included in totalAmountInCents.

Request body – QuoteContributionRequest

POST /v2/contribution-quotes request body
Field Type Description
frequency string Optional, as on POST /v2/contributions; defaults to onetime. Send the frequency the contribution will be created with: the quote applies the same rule, so extraItems with monthly, annually, or other return 422 here instead of at creation. One of onetime monthly annually other
paymentMethodType Required string How the contributor would pay; drives processing fees (card only). One of ach card
amountInCents Required integer Contribution amount in cents (sent to the 529 plan).
platformFeeInCents Required integer Platform fee in cents to apply to this contribution.
extraItems ExtraItemRequest[] Optional add-on items charged to the giver and not sent to the 529. At most one item. An empty array is treated as omitted. Extra-item processing is computed from the payment rail and returned on each item; it is not charged to the giver.
Example request
{
  "frequency": "onetime",
  "paymentMethodType": "ach",
  "amountInCents": 2500,
  "platformFeeInCents": 2500,
  "extraItems": [
    {
      "sku": "string",
      "amountInCents": 2500,
      "taxAmountInCents": 2500
    }
  ]
}

Responses

Example 200 response
{
  "amountInCents": 2500,
  "platformFeeInCents": 2500,
  "processingFeeInCents": 2500,
  "totalAmountInCents": 2500,
  "extraItems": [
    {
      "sku": "string",
      "amountInCents": 2500,
      "taxAmountInCents": 2500,
      "processingFeeInCents": 2500
    }
  ]
}
POST /v2/contributions

Submit a contribution

Charges the contributor via the selected payment method and transfers the contribution to the 529 plan.

Response behavior depends on payment method:

  • Card: the response immediately indicates success (status: processing) or failure (4xx error envelope).
  • ACH: the response confirms the contribution was accepted (status: processing). Collection failures arrive later via a transaction.failed webhook.

Contribution fees:

  • Platform Fee is set by the platformFeeInCents parameter.
  • Processing Fee is 3% of the amountInCents when the payment method is a card or a digital wallet.

Simulation support (non-production environments only):

  • Pass X-Backer-Simulate or use a magic amountInCents value to force deterministic outcomes for partner QA. When both are provided, the amount takes precedence.
  • Magic amounts: 4200 successful contribution, 4210 card declined (credit card), 4211 funding insufficient funds (bank account), 4221 provider invalid account number, 4222 provider plan not available, 4230 refund succeeded (any payment method; payout fails, refund succeeds async – refund_processing, refunded), 4231 refund card expired (credit card; payout fails, refund fails async – refund_processing, refunded, refund_failed, code card_expired), 4232 refund account closed (bank account; payout fails, ACH return – refund_processing, refund_failed, code account_closed). Settled, invalid account number, and plan not available work with any payment method.
  • Supported header values (same scenarios as magic amounts, plus immediate card decline):
  • card_declined: returns an immediate 422 error with error.errorCode=card_declined.
  • ach_insufficient_funds: returns a normal 200 processing response, then transitions to failed a few seconds later and emits transaction.failed webhook.
  • settled: returns a normal 200 processing response, then a few seconds later simulates settling collecting the funds successfully, sending the funds to the 529 plan successfully and settle the transaction, which emits a transaction.settled webhook.
  • invalid_account_number: returns a normal 200 processing response, then a few seconds later simulates collecting the funds successfully but the transfer to the 529 plan fails, which emits a transaction.failed webhook with failureDetails.code=invalid_account_number.
  • plan_not_available: returns a normal 200 processing response, then a few seconds later simulates a provider payout rejection with failureDetails.code=plan_not_available.
  • refund_succeeded: same as 4230.
  • refund_card_expired: same as 4231.
  • refund_account_closed: same as 4232.
  • In production environments, simulation triggers return 403.

Account/owner eligibility:

  • Returns 422 with error.errorCode=account_inactive when the linked account is inactive.
  • Returns 422 with error.errorCode=account_owner_on_hold when the account owner is on hold.
  • Returns 422 with error.errorCode=account_owner_inactive when the account owner is inactive.
  • Returns 422 with error.errorCode=customer_on_hold when the contributing customer (the funding customer) is on hold.
  • Returns 422 with error.errorCode=customer_inactive when the contributing customer (the funding customer) is inactive.

Parameters

X-Backer-Simulate header, string – Optional non-production simulation scenario for partner testing. Allowed values: card_declined, ach_insufficient_funds, settled, invalid_account_number, plan_not_available, refund_succeeded, refund_card_expired, refund_account_closed. Alternatively, pass a magic amountInCents; amount takes precedence when both are set.

Request body – CreateContributionRequest

POST /v2/contributions request body
Field Type Description
accountId Required string (uuid) Backer linked-account UUID the contribution is sent to.
amountInCents Required integer Contribution amount in cents (sent to the 529 plan).
platformFeeInCents Required integer Platform fee in cents charged to the contributor on top of amountInCents. Obtain the correct value for the contributor via GET /v2/contribution-fees before submitting.
funding Required ContributionFundingRequest
clientContributionId string Optional partner-supplied identifier for this contribution. Must be unique across the partner's contributions; a duplicate returns 409. Echoed back on the transaction and usable with GET /v2/transactions?clientContributionId=....
frequency string Optional partner-declared schedule intent. Omit or set to onetime for a one-time contribution (default). Set to monthly, annually, or other when the partner considers this part of a recurring schedule they manage externally. extraItems are rejected when frequency is monthly, annually, or other. One of onetime monthly annually other
extraItems ExtraItemRequest[] Optional add-on items charged to the giver and not sent to the 529. At most one item. An empty array is treated as omitted. Extra-item processing is computed from the payment rail and returned on each item; it is not charged to the giver.
Example request
{
  "accountId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "amountInCents": 2500,
  "platformFeeInCents": 2500,
  "funding": {
    "type": "CUSTOMER",
    "customerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "paymentMethodId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  },
  "clientContributionId": "string",
  "frequency": "onetime",
  "extraItems": [
    {
      "sku": "string",
      "amountInCents": 2500,
      "taxAmountInCents": 2500
    }
  ]
}

Responses

Example 200 response
{
  "transactionId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "accountId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "amountInCents": 2500,
  "status": "processing",
  "type": "contribution",
  "createdAt": "2026-11-06T17:00:00Z",
  "updatedAt": "2026-11-06T17:00:00Z",
  "contribution": {
    "clientContributionId": "string",
    "frequency": "onetime",
    "funding": {
      "type": "customer",
      "customerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "paymentMethodId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    },
    "processingFeeInCents": 2500,
    "platformFeeInCents": 2500,
    "extraItems": [
      {
        "sku": "string",
        "amountInCents": 2500,
        "taxAmountInCents": 2500,
        "processingFeeInCents": 2500
      }
    ],
    "totalAmountInCents": 2500
  }
}
GET /v2/transactions/{transactionId}

Get a transaction by id

Returns a single transaction by its UUID. The response shape is identical to an item in GET /v2/accounts/{accountId}/transactions.

Parameters

transactionId path, string (uuid) , required – Backer transaction UUID.

Responses

Example 200 response
{
  "transactionId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "accountId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "amountInCents": 2500,
  "status": "processing",
  "type": "contribution",
  "createdAt": "2026-11-06T17:00:00Z",
  "updatedAt": "2026-11-06T17:00:00Z",
  "cancellableUntil": "2026-11-06T17:00:00Z",
  "contribution": {
    "clientContributionId": "string",
    "funding": {
      "type": "customer",
      "customerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "paymentMethodId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    },
    "processingFeeInCents": 2500,
    "platformFeeInCents": 2500,
    "extraItems": [
      {
        "sku": "string",
        "amountInCents": 2500,
        "taxAmountInCents": 2500,
        "processingFeeInCents": 2500
      }
    ],
    "totalAmountInCents": 2500
  },
  "failureDetails": {
    "phase": "funding",
    "category": "funding_card_failure",
    "code": "string",
    "message": "string",
    "failedAt": "2026-11-06T17:00:00Z"
  }
}
GET /v2/transactions

Get a transaction by clientContributionId

Looks up a transaction by the partner-supplied clientContributionId provided when the contribution was created. To fetch by the Backer transaction ID instead, use GET /v2/transactions/{transactionId}.

Parameters

clientContributionId query, string , required – Partner-supplied contribution identifier (clientContributionId on CreateContributionRequest).

Responses

Example 200 response
{
  "transactionId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "accountId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "amountInCents": 2500,
  "status": "processing",
  "type": "contribution",
  "createdAt": "2026-11-06T17:00:00Z",
  "updatedAt": "2026-11-06T17:00:00Z",
  "cancellableUntil": "2026-11-06T17:00:00Z",
  "contribution": {
    "clientContributionId": "string",
    "funding": {
      "type": "customer",
      "customerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "paymentMethodId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    },
    "processingFeeInCents": 2500,
    "platformFeeInCents": 2500,
    "extraItems": [
      {
        "sku": "string",
        "amountInCents": 2500,
        "taxAmountInCents": 2500,
        "processingFeeInCents": 2500
      }
    ],
    "totalAmountInCents": 2500
  },
  "failureDetails": {
    "phase": "funding",
    "category": "funding_card_failure",
    "code": "string",
    "message": "string",
    "failedAt": "2026-11-06T17:00:00Z"
  }
}
GET /v2/accounts/{accountId}/transactions

List transactions for an account

Returns the transaction history for a linked 529 account, ordered by descending createdAt. Results are paginated.

Parameters

accountId path, string (uuid) , required – Backer linked-account UUID.
page query, integer – Page number (1-based). Defaults to 1.
pageSize query, integer – Number of transactions per page. Defaults to 10.

Responses

Example 200 response
{
  "items": [
    {
      "transactionId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "accountId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "amountInCents": 2500,
      "status": "processing",
      "type": "contribution",
      "createdAt": "2026-11-06T17:00:00Z",
      "updatedAt": "2026-11-06T17:00:00Z",
      "cancellableUntil": "2026-11-06T17:00:00Z",
      "contribution": {
        "clientContributionId": "string",
        "funding": {
          "type": "customer",
          "customerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
          "paymentMethodId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
        },
        "processingFeeInCents": 2500,
        "platformFeeInCents": 2500,
        "extraItems": [
          {
            "sku": "string",
            "amountInCents": 2500,
            "taxAmountInCents": 2500,
            "processingFeeInCents": 2500
          }
        ],
        "totalAmountInCents": 2500
      },
      "failureDetails": {
        "phase": "funding",
        "category": "funding_card_failure",
        "code": "string",
        "message": "string",
        "failedAt": "2026-11-06T17:00:00Z"
      }
    }
  ],
  "total": 0,
  "page": 0,
  "pageSize": 0
}
POST /v2/transactions/{transactionId}/cancel

Cancel a contribution transaction

Cancels a contribution transaction within the cancellation window.

  • ACH: cancels the scheduled bank pull; no refund is needed because funds have not been collected.
  • Card: initiates a refund because funds were collected synchronously.

A transaction is cancellable when:

  • The current time is within 1 hour 5 minutes of createdAt (cancellableUntil plus a 5-minute backend grace period).

Error codes:

  • 409 not_cancellable: transaction is outside the window or otherwise not eligible.

Parameters

transactionId path, string (uuid) , required – Backer transaction UUID.

Responses

Example 200 response
{
  "transactionId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "accountId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "amountInCents": 2500,
  "status": "processing",
  "type": "contribution",
  "createdAt": "2026-11-06T17:00:00Z",
  "updatedAt": "2026-11-06T17:00:00Z",
  "cancellableUntil": "2026-11-06T17:00:00Z",
  "contribution": {
    "clientContributionId": "string",
    "funding": {
      "type": "customer",
      "customerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "paymentMethodId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    },
    "processingFeeInCents": 2500,
    "platformFeeInCents": 2500,
    "extraItems": [
      {
        "sku": "string",
        "amountInCents": 2500,
        "taxAmountInCents": 2500,
        "processingFeeInCents": 2500
      }
    ],
    "totalAmountInCents": 2500
  },
  "failureDetails": {
    "phase": "funding",
    "category": "funding_card_failure",
    "code": "string",
    "message": "string",
    "failedAt": "2026-11-06T17:00:00Z"
  }
}

Webhooks

POST /v2/webhook-subscription

Update the partner's webhook subscription

Updates the webhook subscription for the authenticated partner. If the partner has no subscription, returns 404.

All fields are optional; at least one must be provided.

Request body – UpdateWebhookSubscriptionRequest

POST /v2/webhook-subscription request body
Field Type Description
url string (uri) Delivery endpoint URL (must be http or https).
eventTypes string[] Non-empty list of event types to subscribe to. One of transaction.settled transaction.failed transaction.refund_initiated transaction.refunded transaction.refund_failed
secret string Signing secret used to verify webhook payloads.
description string Human-readable description for the subscription.
Example request
null

Responses

Example 200 response
{
  "url": "https://example.com",
  "eventTypes": [
    "string"
  ],
  "secret": "string",
  "description": "string",
  "status": "enabled"
}

Webhook events

Backer POSTs each event to the URL set with POST /v2/webhook-subscription, signed in the Webhook-Signature header.

Event transaction.settled

Contribution settled to the 529 plan

Emitted when a contribution reaches its terminal success state: funds collected from the contributor's payment method and dispatched to the 529 plan. data.object.failureDetails is always null for this event. Payload is signed via the Webhook-Signature header (HMAC-SHA256). Delivery is retried with exponential backoff up to 20 attempts.

Payload – TransactionSettledEvent

Event transaction.failed

Contribution failed

Emitted when a contribution transitions to failed (ACH return, plan rejection, card decline, etc.). data.object.failureDetails describes failure phase, category, and reason.

Payload – TransactionFailedEvent

Event transaction.refund_initiated

Refund initiated for a contribution

Emitted when a refund is requested for a contribution – for both card and bank (ACH) refunds. This is followed by either transaction.refunded (success) or transaction.refund_failed (failure): card refunds resolve synchronously, while ACH refunds resolve a few business days later once the refund transaction settles or is returned. Payload is signed via the Webhook-Signature header (HMAC-SHA256). Delivery is retried with exponential backoff up to 20 attempts.

Payload – TransactionRefundInitiatedEvent

Event transaction.refunded

Refund settled for a contribution

Emitted when a refund completes successfully and the contribution is refunded. Card refunds emit this as soon as the refund succeeds; ACH refunds emit it when the refund transaction settles (a few business days later). data.status is refunded and data.failureDetails is absent.

Payload – TransactionRefundedEvent

Event transaction.refund_failed

Refund failed for a contribution

Emitted when a refund attempt fails – a card refund error, or an ACH refund returned by the bank. data.status is always refund_failed. data.failureDetails describes the refund failure (phase=refund).

Payload – TransactionRefundFailedEvent

Schemas

Request schemas mark required fields; response schemas mark fields that can be null.

OAuthTokenRequest

OAuth2 token request. Supply clientId + clientSecret with grantType=client_credentials.

OAuthTokenRequest
Field Type Description
grantType Required string OAuth2 grant type. One of client_credentials
clientId Required string Partner's public client id.
clientSecret Required string Partner's secret.

OAuthTokenResponse

OAuthTokenResponse
Field Type Description
accessToken string Signed JWT bearer token. Pass as Authorization: Bearer <accessToken>.
tokenType string
expiresIn integer Lifetime of accessToken in seconds. The server's TTL is configurable; do not hard-code.

OAuthErrorEnvelope

OAuth2 error envelope per RFC 6749 §5.2. Distinct from the ActionErrorEnvelope / FieldErrorsEnvelope returned by every non-OAuth endpoint.

OAuthErrorEnvelope
Field Type Description
error string One of invalid_request invalid_client unsupported_grant_type

CreateCustomerRequest

CreateCustomerRequest
Field Type Description
clientCustomerId string Partner's unique identifier for the customer. Optional; when provided, it must be unique within the partner's namespace.
email Required string (email)
firstName string
lastName string

Customer

Customer
Field Type Description
customerId string (uuid) Backer's UUID for the customer.
clientCustomerId string Nullable Partner's unique identifier for the customer (echoed back).
email string (email)
firstName string Nullable
lastName string Nullable
status string Customer status. active when the customer has no status or is active; inactive when deactivated; hold when placed on hold. One of active inactive hold

UpdateCustomerRequest

Fields that can be updated on an existing customer. At least one must be provided.

UpdateCustomerRequest
Field Type Description
clientCustomerId string Updated partner-unique identifier for the customer.
email string (email)
firstName string
lastName string

SetCustomerStatusRequest

Sets the customer's status. statusReason is required when status is inactive or hold, and is ignored when status is active.

SetCustomerStatusRequest
Field Type Description
status Required string Target status for the customer. One of active inactive hold
statusReason string Reason for the status change. Required when status is inactive or hold.

CustomerWithStatus

SetAccountStatusRequest

Sets the account's status. statusReason is required when status is inactive, and is ignored when status is active.

SetAccountStatusRequest
Field Type Description
status Required string Target status for the account. One of active inactive
statusReason string Reason for the status change. Required when status is inactive.

AccountWithStatus

UpdateAccountRequest

Fields that can be updated on a linked 529 account.

At least one of planId, accountNumber, beneficiary, or accountOwner must be provided.

Changing planId re-validates the stored account number against the new plan. Changing accountNumber re-validates against the current or updated plan.

UpdateAccountRequest
Field Type Description
planId string Backer plan ID with isSupported: true from GET /v2/plans.
accountNumber string Updated 529 account number.
beneficiary Beneficiary
accountOwner AccountOwnerInput

LinkAccountRequest

beneficiary is required when the registry owner is gifting on behalf of someone else (the default). When the registry owner is the beneficiary of their own 529, set isAccountOwnerBeneficiary: true and omit beneficiary – Backer copies the owner's first and last name onto the account instead.

accountOwner may be supplied to set the customer's first and last name during linking. Supplied values overwrite any existing names on the customer.

At least one of brokerId or planId is required. For brokerage-held accounts, send brokerId and optionally planId from the broker's catalog (GET /v2/brokers). The selected broker must have isSupported: true.

LinkAccountRequest
Field Type Description
brokerId string Backer broker ID with isSupported: true from GET /v2/brokers.
planId string Backer plan ID. Required with isSupported: true for direct plan linking. Optional with brokerId for brokerage-held accounts, where the plan's own isSupported value does not restrict broker linking.
accountNumber Required string Customer's existing 529 account number.
beneficiary Beneficiary
accountOwner AccountOwnerInput
isAccountOwnerBeneficiary boolean When true, the registry owner is also the beneficiary of the 529. beneficiary must be omitted in that case (422 if both are set). The owner's first/last name (resolved from existing customer data or the supplied accountOwner) becomes the account owner's first/last name.

ValidateAccountNumberRequest

At least one of brokerId or planId is required. See POST /v2/customers/{customerId}/validate-account-number.

ValidateAccountNumberRequest
Field Type Description
brokerId string Backer broker ID (from GET /v2/brokers).
planId string Backer plan ID. Required for plan-only validation. Optional with brokerId to identify the underlying 529 plan.
accountNumber Required string 529 account number to validate.

ValidateAccountNumberResponse

ValidateAccountNumberResponse
Field Type Description
valid boolean Always true on success.

Beneficiary

Beneficiary
Field Type Description
firstName string
lastName string

AccountOwnerInput

Optional first/last name and email for the customer. Any field may be omitted. Supplied values overwrite existing ones.

AccountOwnerInput
Field Type Description
firstName string Nullable
lastName string Nullable
email string (email) Nullable

AccountOwner

Customer who owns the linked 529 account.

AccountOwner
Field Type Description
email string (email)
firstName string Nullable
lastName string Nullable

LinkAccountResponse

LinkAccountResponse
Field Type Description
accountId string (uuid) Backer's UUID for the linked account.
broker LinkedAccountBroker
plan LinkedAccountPlan
beneficiary Beneficiary
accountOwner AccountOwner
isAccountOwnerBeneficiary boolean true when the registry owner is also the beneficiary of the 529 (the account's beneficiary first/last name mirrors the account owner's). false otherwise.
status string Account status. active when the account is active or pending; inactive when deactivated. One of active inactive
userName string Nullable 529 plan login username, present when the account was opened through a Backer-hosted flow; omitted for link-account-only accounts.

LinkedAccountBroker

Brokerage partner for a linked account. Omitted when the account is not linked via a broker.

LinkedAccountBroker
Field Type Description
brokerId string Backer broker ID (e.g. br_1).
name string Broker display name.
isSupported boolean Whether the broker is currently available for account linking.

LinkedAccountPlan

Underlying 529 plan for a linked account. Omitted when the account is not linked to a plan (broker-only links).

LinkedAccountPlan
Field Type Description
planId string
name string
stateName string

Broker

Broker
Field Type Description
brokerId string Backer broker ID (e.g. br_1).
name string Broker display name.
isSupported boolean Whether the broker is currently available for account linking (has account-number validation configured and is enabled). Catalog-only brokers returned with includeUnsupported=true are always false until launched.
plans Plan[] Plans associated with this broker (informational).

Plan

Plan
Field Type Description
planId string Backer's plan ID.
stateName string
displayName string
isSupported boolean Whether the plan is currently available for direct account linking.
programManager string Nullable Name of the 529 program manager (e.g. "Vanguard").
programDistributor string Nullable Name of the 529 program distributor.

ContributionLimitsResponse

Contribution amount limits for the account's 529 plan, in cents. Returns one entry per supported payment method (ach, card). minimumInCents and maximumInCents are the one-time contribution bounds; maximumMonthlyInCents and maximumAnnuallyInCents are the recurring caps for the matching frequency.

ContributionLimitsResponse
Field Type Description
limits ContributionLimitsEntry[]

ContributionLimitsEntry

ContributionLimitsEntry
Field Type Description
paymentMethodType string One of ach card
minimumInCents integer Minimum one-time contribution amount in cents.
maximumInCents integer Maximum one-time contribution amount in cents. Capped at 50000 ($500) for card.
maximumMonthlyInCents integer Maximum recurring monthly contribution amount in cents. Capped at 50000 ($500) for card.
maximumAnnuallyInCents integer Maximum recurring annual contribution amount in cents. Capped at 50000 ($500) for card.

PaymentMethod

Saved payment method. type discriminates the shape: ACH methods carry a bankAccount object; card methods carry a creditCard object.

AchPaymentMethod

AchPaymentMethod
Field Type Description
paymentMethodId string (uuid)
type string
bankAccount object

CardPaymentMethod

CardPaymentMethod
Field Type Description
paymentMethodId string (uuid)
type string
creditCard object

CreatePaymentMethodSessionRequest

CreatePaymentMethodSessionRequest
Field Type Description
successUrl Required string (uri) Absolute http(s) URL the hosted page redirects to on completion.
cancelUrl Required string (uri) Absolute http(s) URL the hosted page redirects to on exit/cancel.
type Required string Payment method type to collect. Locks the hosted page to a single rail – ACH shows only the bank-account form; card shows only the card form. Switching between rails is not permitted once the session is created. One of ach card
metadata string Optional opaque partner-defined string echoed back to successUrl as the metadata query parameter when the customer finishes adding a payment method. Useful for correlating the resulting payment method with a partner-side order, cart, or wishlist. The value is passed through verbatim – partners are free to choose its format (e.g. JSON, base64, opaque token) and parse it on successUrl.
platformFeeInCents integer Platform fee in cents shown on the hosted payment-method page (e.g. "$1.99 convenience fee"). Omit or set to 0 to hide the convenience fee line on ACH; card pages still show the 3% processing fee disclaimer.

HostedSession

HostedSession
Field Type Description
url string (uri) Signed, short-lived URL to redirect the customer to.

CreateContributionRequest

CreateContributionRequest
Field Type Description
accountId Required string (uuid) Backer linked-account UUID the contribution is sent to.
amountInCents Required integer Contribution amount in cents (sent to the 529 plan).
platformFeeInCents Required integer Platform fee in cents charged to the contributor on top of amountInCents. Obtain the correct value for the contributor via GET /v2/contribution-fees before submitting.
funding Required ContributionFundingRequest
clientContributionId string Optional partner-supplied identifier for this contribution. Must be unique across the partner's contributions; a duplicate returns 409. Echoed back on the transaction and usable with GET /v2/transactions?clientContributionId=....
frequency string Optional partner-declared schedule intent. Omit or set to onetime for a one-time contribution (default). Set to monthly, annually, or other when the partner considers this part of a recurring schedule they manage externally. extraItems are rejected when frequency is monthly, annually, or other. One of onetime monthly annually other
extraItems ExtraItemRequest[] Optional add-on items charged to the giver and not sent to the 529. At most one item. An empty array is treated as omitted. Extra-item processing is computed from the payment rail and returned on each item; it is not charged to the giver.

ContributionFundingRequest

Identifies who is funding the contribution and which saved payment method to charge.

ContributionFundingRequest
Field Type Description
type Required string Discriminator for the funding source. Only the customer funding source is supported. One of CUSTOMER
customerId Required string (uuid) Contributor's Backer customer UUID.
paymentMethodId Required string (uuid) Backer payment-method UUID to charge.

Contribution

Contribution
Field Type Description
transactionId string (uuid) Backer's UUID for the underlying transaction.
accountId string (uuid) Backer linked-account UUID the contribution was sent to.
amountInCents integer Contribution amount sent to the 529 plan.
status TransactionStatus
type string
createdAt string (date-time)
updatedAt string (date-time)
contribution ContributionDetails

ContributionDetails

ContributionDetails
Field Type Description
clientContributionId string Nullable Partner-supplied identifier for this contribution, if one was provided on creation; null otherwise.
frequency string Partner-declared schedule intent. onetime for one-time contributions; monthly, annually, or other when the partner marked the contribution as part of a recurring schedule. One of onetime monthly annually other
funding ContributionFunding
processingFeeInCents integer Card processing fee charged to the contributor (0 for ACH).
platformFeeInCents integer Platform fee charged to the contributor (0 for owner self-contributions).
extraItems ExtraItem[] Extra items persisted on this contribution, including the recomputed extra-item processing fee. Omitted when none were sent.
totalAmountInCents integer Total amount charged to the contributor (amountInCents + platformFeeInCents + processingFeeInCents + extra item amounts + tax). Extra-item processing is not included.

ContributionFunding

Identifies who funded the contribution and which saved payment method was charged. Mirrors ContributionFundingRequest on the response side; type is returned lowercase (customer). paymentMethodId may be null if the payment method has been removed since the contribution was created.

ContributionFunding
Field Type Description
type string
customerId string (uuid) Contributor's Backer customer UUID.
paymentMethodId string (uuid) Nullable

TransactionContributionFunding

Funding identity recorded against a past transaction. Both customerId and paymentMethodId may be null if the contributor or the payment method have been removed since the transaction was recorded.

TransactionContributionFunding
Field Type Description
type string
customerId string (uuid) Nullable Contributor's Backer customer UUID.
paymentMethodId string (uuid) Nullable

TransactionStatus

REST transaction status values.

  • processing: contribution accepted and in progress – collecting funds from the contributor and/or transferring to the 529 plan.
  • settled: funds dispatched to the 529 plan. Most plans do not confirm receipt, so settled is the terminal success state.
  • cancelled: contribution was cancelled before completion; no failureDetails.
  • failed: contribution failed during funding or provider payout; see failureDetails.
  • refunded: refund completed successfully.
  • refund_processing: refund is initiated and in flight.
  • refund_failed: refund attempt failed; see failureDetails.

PaginatedTransactions

PaginatedTransactions
Field Type Description
items Transaction[]
total integer Total number of transactions for the account.
page integer Current page number (1-based).
pageSize integer Number of transactions per page.

Transaction

A single transaction (currently always a contribution) recorded against a linked 529 account.

Transaction
Field Type Description
transactionId string (uuid) Backer's UUID for the underlying transaction.
accountId string (uuid) Backer linked-account UUID the transaction belongs to.
amountInCents integer Transaction amount sent to the 529 plan, in cents.
status TransactionStatus
type string
createdAt string (date-time)
updatedAt string (date-time)
cancellableUntil string (date-time) Nullable Nominal deadline for cancelling this transaction (createdAt + 1 hour). Null for non-cancellable transaction types. Cancel requests are accepted until 5 minutes after this time (backend grace).
contribution TransactionContributionDetails
failureDetails TransactionFailureDetails | null Populated when status is failed or refund_failed; null otherwise.

TransactionContributionDetails

TransactionContributionDetails
Field Type Description
clientContributionId string Nullable Partner-supplied identifier for this contribution, if one was provided on creation; null otherwise.
funding TransactionContributionFunding
processingFeeInCents integer Card processing fee charged to the contributor (0 for ACH).
platformFeeInCents integer Platform fee charged to the contributor (0 for owner self-contributions).
extraItems ExtraItem[] Extra items persisted on this contribution, including the recomputed extra-item processing fee. Omitted when none were sent.
totalAmountInCents integer Total amount charged to the contributor (amountInCents + platformFeeInCents + processingFeeInCents + extra item amounts + tax). Extra-item processing is not included.

TransactionFailureDetails

TransactionFailureDetails
Field Type Description
phase string Stage of processing in which the transaction failed. - funding: failure while collecting funds from the contributor. - provider_payout: failure while sending funds to the 529 provider. - refund: failure while refunding funds back to the contributor. One of funding provider_payout refund
category string Failure category used to scope allowed code values. One of funding_card_failure funding_ach_failure provider_payout_failure refund_card_failure refund_ach_failure
code string Stable machine-readable failure code, category-dependent: - funding_card_failure: card_declined, insufficient_funds, card_expired, card_other_failure - funding_ach_failure: insufficient_funds, account_closed, invalid_account_number, other_ach_return - provider_payout_failure: invalid_account_number, account_closed, plan_not_available, unknown_error - refund_card_failure: card_expired, card_other_failure - refund_ach_failure: account_closed, other_ach_return
message string Nullable Human-readable failure reason.
failedAt string (date-time) Nullable

UpdateWebhookSubscriptionRequest

Fields to update on the partner's webhook subscription. At least one must be provided.

UpdateWebhookSubscriptionRequest
Field Type Description
url string (uri) Delivery endpoint URL (must be http or https).
eventTypes string[] Non-empty list of event types to subscribe to. One of transaction.settled transaction.failed transaction.refund_initiated transaction.refunded transaction.refund_failed
secret string Signing secret used to verify webhook payloads.
description string Human-readable description for the subscription.

WebhookSubscription

WebhookSubscription
Field Type Description
url string (uri) Delivery endpoint URL.
eventTypes string[] List of subscribed event types.
secret string Signing secret for verifying webhook payloads.
description string Nullable Human-readable description for the subscription.
status string Current status of the subscription. One of enabled disabled

ContributionFees

ContributionFees
Field Type Description
platformFeeInCents integer Platform fee in cents (0 for owner self-contributions).
processingFeeInCents integer Card processing fee in cents (0 for ACH).
totalAmountInCents integer Total the contributor will be charged in cents (amountInCents + platformFeeInCents + processingFeeInCents).

QuoteContributionRequest

QuoteContributionRequest
Field Type Description
frequency string Optional, as on POST /v2/contributions; defaults to onetime. Send the frequency the contribution will be created with: the quote applies the same rule, so extraItems with monthly, annually, or other return 422 here instead of at creation. One of onetime monthly annually other
paymentMethodType Required string How the contributor would pay; drives processing fees (card only). One of ach card
amountInCents Required integer Contribution amount in cents (sent to the 529 plan).
platformFeeInCents Required integer Platform fee in cents to apply to this contribution.
extraItems ExtraItemRequest[] Optional add-on items charged to the giver and not sent to the 529. At most one item. An empty array is treated as omitted. Extra-item processing is computed from the payment rail and returned on each item; it is not charged to the giver.

ExtraItemRequest

ExtraItemRequest
Field Type Description
sku Required string Partner-defined extra-item SKU. Echoed on the quote and transaction.
amountInCents Required integer Extra-item amount in cents charged to the giver.
taxAmountInCents integer Tax in cents charged to the giver. Defaults to 0 when omitted.

ExtraItem

ExtraItem
Field Type Description
sku string Partner-defined extra-item SKU.
amountInCents integer Extra-item amount in cents charged to the giver.
taxAmountInCents integer Tax in cents charged to the giver.
processingFeeInCents integer Extra-item card processing fee: 3% of (amountInCents + taxAmountInCents), rounded half up. 0 for ACH. Not charged to the giver; netted from the partner payout.

ContributionQuote

ContributionQuote
Field Type Description
amountInCents integer Contribution amount in cents (sent to the 529 plan). Echoed from the request.
platformFeeInCents integer Platform fee in cents.
processingFeeInCents integer Card processing fee on the 529 contribution amount (0 for ACH).
totalAmountInCents integer Total the contributor will be charged (amountInCents + platformFeeInCents + processingFeeInCents + extra item amounts + tax). Extra-item processing is not included.
extraItems ExtraItem[] Enriched extra items when they were sent on the request.

ActionErrorEnvelope

Envelope for non-validation 4xx and 5xx responses on every non-OAuth endpoint (auth, not-found, rate limit, business-rule failure). Carries a single error with a stable machine-readable errorCode and a partner-displayable message. Action errorCode values include but are not limited to: unauthorized, forbidden, not_found, conflict, rate_limited, internal_error, account_not_established, account_inactive, account_owner_on_hold, account_owner_inactive, customer_not_found, plan_not_found, payment_method_not_found, payment_method_mismatch, payment_not_created, ach_transaction_failed, card_payment_failed, refund_failed, stripe_unavailable, customer_resolution_failed, payment_method_session_failed, account_update_failed, invalid_status, transactions_still_processing, invalid_account_number, broker_not_found, broker_not_available, broker_plan_mismatch, invalid_request. New codes may be introduced over time without a breaking spec change. OAuth2 errors at POST /v2/oauth/token use OAuthErrorEnvelope instead.

ActionErrorEnvelope
Field Type Description
error object

FieldErrorsEnvelope

Envelope for 422 validation failures. Each entry names the failing field, a stable errorCode, and a human-readable message. The field value mirrors the camelCase request key.

FieldErrorsEnvelope
Field Type Description
fieldErrors object[]

WebhookEnvelope

Outer envelope for all webhook deliveries. The event-specific payload lives at data.

WebhookEnvelope
Field Type Description
id string (uuid) Unique id for this webhook event (also sent as the Webhook-Id HTTP header for idempotency).
type string Event type, e.g. transaction.settled.
createdAt string (date-time) ISO 8601 UTC datetime when the event occurred.
resourceId string (uuid) UUID of the affected resource, e.g. the transactionId.
resourceType string Type of the affected resource, e.g. transaction.
data object Event-specific payload. See per-event schemas.

TransactionSettledEventData

data payload for transaction.settled events.

TransactionSettledEventData
Field Type Description
status TransactionStatus
accountId string (uuid) Backer linked-account UUID the transaction belongs to.

TransactionFailedEventData

data payload for transaction.failed events.

TransactionFailedEventData
Field Type Description
accountId string (uuid) Backer linked-account UUID the transaction belongs to.
status TransactionStatus
failureDetails WebhookFailureDetails

WebhookFailureDetails

Failure details delivered on transaction.failed. Slimmer than the REST TransactionFailureDetails – no metadata field.

WebhookFailureDetails
Field Type Description
phase string - funding: failure occurred while collecting funds from the contributor's payment method. - provider_payout: funds were collected; failure occurred while sending money to the 529 provider. - refund: failure occurred while refunding funds to the contributor. One of funding provider_payout refund
category string Failure category used to scope allowed code values. One of funding_card_failure funding_ach_failure provider_payout_failure refund_card_failure refund_ach_failure
code string Stable machine-readable failure code, category-dependent: - funding_card_failure: card_declined, insufficient_funds, card_expired, card_other_failure - funding_ach_failure: insufficient_funds, account_closed, invalid_account_number, other_ach_return - provider_payout_failure: invalid_account_number, account_closed, plan_not_available, unknown_error - refund_card_failure: card_expired, card_other_failure - refund_ach_failure: account_closed, other_ach_return
message string Nullable Human-readable failure reason.
failedAt string (date-time) Nullable

TransactionSettledEvent

TransactionFailedEvent

TransactionRefundInitiatedEventData

data payload for transaction.refund_initiated events. status is typically refund_processing, refunded for synchronous card refunds.

TransactionRefundInitiatedEventData
Field Type Description
status TransactionStatus Current transaction status at event time. Typically refund_processing; card refunds may already show refunded.
accountId string (uuid) Backer linked-account UUID the transaction belongs to.

TransactionRefundInitiatedEvent

TransactionRefundedEventData

data payload for transaction.refunded events.

TransactionRefundedEventData
Field Type Description
status string Always refunded for this event.
accountId string (uuid) Backer linked-account UUID the transaction belongs to.

TransactionRefundedEvent

TransactionRefundFailedEventData

data payload for transaction.refund_failed events.

TransactionRefundFailedEventData
Field Type Description
accountId string (uuid) Backer linked-account UUID the transaction belongs to.
status string Always refund_failed for this event.
failureDetails WebhookFailureDetails

TransactionRefundFailedEvent