Funding Source Management (Deposits)

Pull money into the user's Qwik account (DDA) from an external bank, via ACH. The external bank is linked through the provider's Plaid-based flow (distinct from the Teller aggregation in External Bank Connect).

!
The user must have completed card onboarding first. Without a card/consumer, deposits fail with 400 — External bank linking is only supported for Upwardli.
i
Flow: POST …/plaid-link/start (link a bank in a WebView) → GET …/external-accounts (pick the linked bank) → POST …/deposits → poll GET …/deposits/:id or await the Payment.ACH.Completed webhook.

POST/partner/cards/plaid-link/start

🔑 Org key + secret👤 User session

No body. Returns a hosted link URL to open in a WebView.

200 · Response
{ "hostedLinkUrl": "https://component-embedded-sandbox.upwardli.com/...?access_token=...", "accessToken": "...", "expiresAt": null }

GET/partner/cards/external-accounts

🔑 Org key + secret👤 User session

Lists the user's accounts (their primary Qwik DDA plus any linked external banks). Filter to account_type !== "dda" for the bank picker.

200 · Response
{
  "accounts": [
    { "id": "uuid", "account_type": "dda", "is_primary": true, "nickname": "Qwik DDA", "mask": "1234" },
    { "id": "uuid", "account_type": "external_plaid", "is_primary": false, "mask": "0000", "institution_name": "Chase" }
  ]
}

POST/partner/cards/deposits

🔑 Org key + secret👤 User session
FieldTypeRequiredNotes
amountnumberDollars, > 0.
from_account_idstringExternal bank id from …/external-accounts.
to_account_idstringExplicit DDA target; defaults to the user's primary DDA.
descriptionstringMax 500 chars.
201 · Response
{
  "ach_deposit": {
    "id": "uuid", "amount": 50.00, "currency": "USD", "status": "pending",
    "from_account_id": "uuid", "to_account_id": "uuid",
    "external_payment_id": "...", "description": "Card topup",
    "error": null, "created_at": "...", "updated_at": "..."
  }
}

See the ACH status lifecycle. 404 if from_account_id isn't one of the user's linked accounts; 502 if the provider rejects the create (the row is marked failed with error populated).

GET/partner/cards/deposits

🔑 Org key + secret👤 User session

Query: status (any lifecycle value), limit (default 20, max 100), offset (default 0).

200 · Response
{ "deposits": [ /* ach_deposit objects */ ], "pagination": { "limit": 20, "offset": 0, "total": 47 } }

GET/partner/cards/deposits/:depositId

🔑 Org key + secret👤 User session

Returns the same shape as the create response:

200 · Response
{
  "ach_deposit": { ... }
}

404 if it doesn't exist or belongs to another user. depositId must be a UUID.