Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.waycore.com/llms.txt

Use this file to discover all available pages before exploring further.

This page defines how an integrator can reproduce Waycore’s native bank connection onboarding flow inside their own product using the public Waycore API.
Never expose a Waycore API key in browser code, mobile apps, logs, analytics, or client-side error reporting. The host frontend should call your own backend. Your backend should call https://api.waycore.com/v1 with Authorization: Bearer <waycore_api_key>.

Visual reference

Use the screenshots below as visual targets for the host-side implementation. They capture the three main UI states: connection details, delegated user creation, and finish setup.
Waycore connection details step with bank selection, connection type, and portal link

Architecture

Host frontend

Renders the native onboarding UI, stores local draft state, and calls the host backend. It must never call Waycore directly with an API key.

Host backend

Stores the Waycore API key server-side, validates the signed-in host user, and proxies only the Waycore actions that user is allowed to perform.

Waycore public API

Owns entities, institutions, connection setup state, delegated-user instructions, activation, sync, accounts, transactions, balances, and webhooks.

Waycore docs

Provides bank-specific delegated-user setup instructions. Use exact guide URLs supplied by Waycore, or fall back to the general setup page.

End-customer journey

1

Connections list

The user sees existing live and in-progress connections and can start a new connection or resume local draft progress.
2

Connection details

The user searches for a supported institution or enters an unsupported bank portal URL. The host backend uses the Waycore entity already mapped to that signed-in customer.
3

Delegated user

The host product renders the setup.instructions returned by Waycore and sends the user to Waycore’s delegated-user setup instructions.
4

Finish setup

The user optionally enters bank-issued login details, confirms the delegated user is active, and accepts the required Waycore terms.
5

Activate

The host product marks setup complete, then polls or listens for a webhook until the connection becomes kind="ready" and status="active".

Required scopes

For the full embedded onboarding flow, the API key must have:
ScopeUsed for
entities:readLooking up or validating the Waycore entity mapped to the signed-in customer.
entities:writeCreating the Waycore entity ahead of the connection flow, or lazily in the background before the first connection is created.
connections:readSearching institutions, listing connections, and polling setup state.
connections:writeCreating connections, submitting credentials, completing setup, deleting connections, and optionally triggering sync.
accounts:readReading accounts and balances after activation.
transactions:readReading and syncing transactions after activation.

Host screens

These screens are suggestions for the host product UI. They are not Waycore API paths, and the exact route names are up to the integrator.
ScreenPurpose
Connections listList existing and in-progress connections.
New connection wizardStart a new local draft.
Draft resumeResume local progress before Waycore has a connection.
Setup resumeResume a setup-stage Waycore connection.
Connection detailShow a connection after activation or terminal states.

UI-to-API mapping

Client products may use different labels for the same onboarding moments. Treat the labels below as generic interaction patterns, not required copy.
UI momentHost backend behaviorWaycore API behavior
Customer opens a bank connection flowIdentify the signed-in customer and resolve the mapped Waycore entity.No call is required if the entity mapping already exists.
Customer searches for or selects a bankQuery supported institutions, or keep the customer-entered portal URL for an unsupported bank.GET /v1/institutions when searching supported institutions.
Customer starts setup, requests credentials, or continues from bank selectionCreate or return the connection for the mapped entity.POST /v1/connections with entityId plus institutionId or portalUrl.
UI displays delegated-user name, email, username, phone, or addressRender the setup instructions from the connection response.Read connection.setup.instructions; do not call a separate provisioning endpoint.
Customer follows bank-portal setup instructionsWait while the customer acts in the bank portal.No Waycore API call is required during this step.
Customer enters optional bank-issued fieldsSubmit only populated optional fields.PUT /v1/connections/{connectionId}/credentials when at least one field is populated.
Customer confirms the delegated user is active or clicks activate/finishMark setup complete.PUT /v1/connections/{connectionId}/setupCompletion.
UI shows confirming, activating, or waiting statePoll or consume webhook updates.GET /v1/connections/{connectionId} or connection.status_changed.
UI shows connected stateTreat the connection as usable only once it is ready and active.Require kind="ready" and status="active".
Customer abandons or resets before a Waycore connection existsClear local draft state only.No Waycore API call is required.
Customer requests removal after a Waycore connection existsRequire explicit confirmation before deleting the connection.DELETE /v1/connections/{connectionId} only for intentional removal.

Draft and resume model

The host product can keep local draft progress before a Waycore connection exists. Once POST /v1/connections succeeds, use the returned id as the resume key. From that point onward, the connection is a Waycore resource, not just local UI state.
type ConnectionSetupViewStep =
  | "details"
  | "instructions"
  | "completion"
  | "activation"

interface ConnectionSetupDraft {
  bankPortalUrl: string
  createdAt: number
  requestedInstitutionName: string
  selectedInstitutionId: string
  selectedInstitutionName: string
  updatedAt: number
  viewStep: ConnectionSetupViewStep
}
Draft rules:
  • Scope local draft storage by the host tenant or organization.
  • Expire abandoned local drafts after a reasonable period, such as 30 days.
  • Store only non-secret UI progress in local storage.
  • Do not store bank passwords or Waycore API keys in local storage.
  • Do not let the browser choose a Waycore entityId; resolve it on the host backend from the signed-in customer.
  • Before POST /v1/connections, a cancel or reset action should only clear local draft state.
  • After POST /v1/connections, a cancel action should usually leave the setup connection resumable.
  • Only call DELETE /v1/connections/{connectionId} when the customer intentionally wants to remove the Waycore connection.

Public API sequence

1. Resolve the entity server-side

Every public connection must belong to an entityId, but the end customer should not select, create, or even need to understand Waycore entities. The host integration must maintain a 1:1 mapping between its customer or company record and the corresponding Waycore entity. Before a customer can create a connection, the host backend must already know which Waycore entityId belongs to that signed-in customer. Create that entity ahead of time during customer onboarding, or create it lazily in the background when the customer first opens the bank connection flow.
POST /v1/entities
Authorization: Bearer way_live_...
Content-Type: application/json

{
  "externalEntityId": "customer_001",
  "name": "Acme Operating LLC",
  "metadata": {
    "customerTier": "enterprise"
  }
}
Entity mapping rules:
  • Store the mapping in the host system, for example hostCustomerId -> waycoreEntityId.
  • Use externalEntityId to make the Waycore entity traceable to the host customer record.
  • Do not render an entity selector in the embedded onboarding UI.
  • Do not accept an arbitrary entityId from the browser as the owner of the connection.
  • If the backend cannot resolve the mapped entity, stop the flow and fix the mapping before calling POST /v1/connections.
Sandbox note: test API keys can create sandbox connections only against the organization’s default entity. Live keys use the normal entity model.

2. Search supported institutions

Use the public institution catalog for supported banks.
GET /v1/institutions?query=chase&limit=20
Authorization: Bearer way_live_...
Institution records use this public shape:
interface Institution {
  institutionId: string
  name: string
  canonicalPortalUrl: string
  additionalPortalUrls: string[]
}
Search behavior:
  • Preserve the user’s free text until they explicitly select a suggestion.
  • Never auto-select a fuzzy match.
  • Show the institution name and portal domain.
  • If a supported institution is selected, keep its institutionId.
  • If no supported institution fits, collect a bank name for host UI context and a valid HTTPS portalUrl.

3. Create or return the connection

Supported institution:
POST /v1/connections
Authorization: Bearer way_live_...
Content-Type: application/json

{
  "entityId": "11111111-2222-3333-4444-555555555555",
  "institutionId": "beacon_bank"
}
Supported institution with a specific login portal:
POST /v1/connections
Authorization: Bearer way_live_...
Content-Type: application/json

{
  "entityId": "11111111-2222-3333-4444-555555555555",
  "institutionId": "beacon_bank",
  "portalUrl": "https://business.beacon.example.com/login"
}
Unsupported or newly requested institution:
POST /v1/connections
Authorization: Bearer way_live_...
Content-Type: application/json

{
  "entityId": "11111111-2222-3333-4444-555555555555",
  "portalUrl": "https://business.bank.example.com/login"
}
Creation rules:
  • Use the entityId mapped to the signed-in customer by the host backend.
  • Use institutionId when the selected bank exists in /v1/institutions.
  • Use portalUrl alone when the bank is not yet supported.
  • Optionally send portalUrl with institutionId when the supported institution has multiple login portals.
  • Do not send the host-only requestedInstitutionName to Waycore.
  • Do not send an entityId chosen by the browser or end customer.
  • A duplicate create may return an existing connection with 200 OK; a new one returns 201 Created.
POST /v1/connections returns a ConnectionResource directly.
type ConnectionResource = SetupConnection | ReadyConnection
If the response is kind="setup", render setup instructions immediately.
interface SetupConnection {
  kind: "setup"
  id: string
  entityId: string
  portalUrl: string | null
  institutionId: string | null
  institutionName: string | null
  status:
    | "draft"
    | "pendingActivation"
    | "active"
    | "reauthRequired"
    | "errored"
    | "invalidConfig"
    | "paused"
    | "revoked"
  createdAt: string
  updatedAt: string
  errorCode: string | null
  errorMessage: string | null
  metadata: Record<string, unknown> | null
  setup: {
    status: "awaitingDelegatedUserCreation" | "pendingActivation"
    credentialsPresent: boolean
    actionRequiredBy: "endUser" | "integrator" | "waycore" | "none"
    nextAction:
      | "createDelegatedUser"
      | "provideCredentials"
      | "activateConnection"
      | "none"
    instructions: {
      firstName: string
      lastName: string
      address: string
      email: string | null
      username: string | null
      phoneNumber: string | null
      emailProvisioningStatus: "pending" | "provisioned"
      phoneNumberProvisioningStatus: "pending" | "provisioned"
    }
  }
}
The setup object is returned on the create response. There is no separate provisioning endpoint to call before showing the delegated-user step. Render the values that are present and use the provisioning statuses for any values that are null or not yet available. If the response is kind="ready", the connection is already active enough for data access.
interface ReadyConnection {
  kind: "ready"
  id: string
  entityId: string
  portalUrl: string | null
  institutionId: string
  institutionName: string | null
  status: "active" | "reauthRequired" | "errored" | "paused" | "revoked"
  syncStatus: "idle" | "syncing"
  createdAt: string
  updatedAt: string
  lastSyncedAt: string | null
  errorCode: string | null
  errorMessage: string | null
  metadata: Record<string, unknown> | null
}

4. Render delegated-user instructions

Use connection.setup.instructions as the source of truth. Show these fields when present:
  • First name
  • Last name
  • Address
  • Email
  • Username
  • Phone number
Recommended copy:
  • Grant the delegated user read-only permissions unless Waycore has explicitly told you otherwise.
  • Use SMS, phone call, or email one-time codes where the bank supports them.
  • Authenticator apps can work when required by the bank.
  • Physical hardware tokens are not supported for this onboarding flow.
Setup guide link behavior:
  • Use an exact Waycore bank setup guide URL only if Waycore has supplied it to your integration.
  • Otherwise link to https://docs.waycore.com/user-setup.
  • Do not invent bank-specific setup steps or derive guide slugs from institution names.

5. Submit optional credentials

Some banks issue or require details after the delegated user has been created. If the customer provides any of them, submit only the populated fields.
PUT /v1/connections/{connectionId}/credentials
Authorization: Bearer way_live_...
Content-Type: application/json

{
  "bankUsername": "waycore387",
  "bankCustomerId": "123456",
  "password": "temporary-or-current-password"
}
Rules:
  • All fields are optional.
  • Skip this call if all fields are blank.
  • The password is accepted but never echoed back.
  • Do not persist password values in browser storage.

6. Mark setup complete

Call setup completion after the customer confirms the delegated user is active in the bank portal.
PUT /v1/connections/{connectionId}/setupCompletion
Authorization: Bearer way_live_...
This hands activation back to Waycore. Waycore validates or claims the bank session, activates the connection, and starts the initial historical sync as part of bringing the connection online.

7. Poll until ready

Poll the connection, or listen for connection.status_changed webhooks.
GET /v1/connections/{connectionId}
Authorization: Bearer way_live_...
Polling rules:
  • Poll every 5 seconds while the user is waiting on the activation screen.
  • Stop polling when kind="ready" and status="active".
  • Show a recoverable error state for reauthRequired, errored, or invalidConfig.
  • Show a terminal or support state for paused or revoked.
  • Prefer webhooks for production background updates when the host product is ready.

8. Read data or optionally sync

Once the connection is ready, read accounts, balances, and transactions through their resource endpoints.
GET /v1/accounts?connectionId={connectionId}
Authorization: Bearer way_live_...
GET /v1/transactions?connectionId={connectionId}
Authorization: Bearer way_live_...
Manual sync is optional. The initial historical sync starts automatically during activation. Use manual sync only when the user explicitly requests fresh data or your backend workflow needs to queue a refresh.
PUT /v1/connections/{connectionId}/sync
Authorization: Bearer way_live_...
Manual sync behavior:
  • Returns 202 Accepted when queued.
  • Returns 409 Conflict if the connection is still in setup or a sync is already in progress.
  • Returns 429 Too Many Requests if the connection is in its 45-minute sync cooldown.
  • Honor Retry-After when present.

9. Delete only when intentional

DELETE /v1/connections/{connectionId}
Authorization: Bearer way_live_...
DELETE /v1/connections/{connectionId} is a hard delete of the public connection and its linked public data, including accounts and transactions. Do not use it as a casual “discard local draft” operation unless the user clearly intends to remove the Waycore connection.
UI labels such as Cancel, Reset, Start over, or Discard should not automatically call this endpoint. Use local draft cleanup before a connection exists, and require explicit removal confirmation after a Waycore connection has been created.

Wizard step contract

1

Connection details

Primary goalCollect the bank input required to create a connection. The host backend supplies the mapped entityId; the customer only provides or selects the institution/portal details.Fields
  • Bank search or unsupported bank name
  • Bank portal URL
Block submission if
  • No local draft exists
  • The host backend cannot resolve the mapped Waycore entity for the signed-in customer
  • No institution is selected and no unsupported bank portal URL is provided
  • The bank portal URL is not HTTPS
  • A matching supported institution exists but the user has not explicitly selected it
Successful submission sequence
  1. Resolve or create the customer’s mapped Waycore entity on the host backend.
  2. Create or return a connection with POST /v1/connections.
  3. Store the returned connection.id in local draft state.
  4. Route to the delegated-user step.
2

Delegated user

Primary goalTell the customer how to create the Waycore delegated user at the bank.Required sections
  • Access instruction callout
  • Authentication setup guidance
  • Delegated-user credentials block from connection.setup.instructions
  • Setup guide link
  • Next action
Credential block sourceRead from connection.setup.instructions.Setup guide sourceLink to an exact Waycore guide URL if provided out of band. Otherwise link to https://docs.waycore.com/user-setup.
3

Finish setup

Primary goalCapture optional bank-issued details and confirm the delegated user is active.Optional fields
  • Bank username
  • Customer ID
  • Password
AgreementRequire an affirmative checkbox confirming that the delegated user is active and that the customer accepts the Waycore Terms of Use on behalf of their company. Link to https://docs.waycore.com/legal/terms-of-use.Successful completion sequence
  1. If any optional credential field has a value, call PUT /v1/connections/{id}/credentials.
  2. Call PUT /v1/connections/{id}/setupCompletion.
  3. Route to the activation step.
4

Activation

Primary goalCommunicate that Waycore is finalizing activation and the customer can wait safely.CopyWaycore is finalizing activation and will start the first sync automatically.PollingPoll GET /v1/connections/{connectionId} every 5 seconds while the user is on this step, or update from webhooks if your backend already receives them.RedirectWhen the connection becomes kind="ready" and status="active", clear the local draft and route to the host connection detail page.

Step visibility state machine

This state machine uses only public API fields.
function getVisibleStep({
  connection,
  connectionId,
  currentStep,
}: {
  connection: ConnectionResource | null
  connectionId: string | null
  currentStep: ConnectionSetupViewStep
}): ConnectionSetupViewStep {
  if (connectionId == null) {
    return "details"
  }

  if (connection == null) {
    return currentStep === "details" ? "instructions" : currentStep
  }

  if (connection.kind === "ready") {
    return "activation"
  }

  if (connection.status === "invalidConfig") {
    return "details"
  }

  if (
    connection.setup.nextAction === "activateConnection" ||
    connection.setup.actionRequiredBy === "waycore"
  ) {
    return "activation"
  }

  if (
    currentStep === "completion" ||
    connection.setup.nextAction === "provideCredentials" ||
    connection.setup.credentialsPresent
  ) {
    return "completion"
  }

  return "instructions"
}

Public status display rules

Public fieldUI labelTypical action
kind="setup", status="draft"Setup in progressShow delegated-user or finish setup step.
kind="setup", status="pendingActivation"ActivatingShow activation step and poll.
kind="ready", status="active"ConnectedClear draft and show connection detail.
status="reauthRequired"Reauthentication requiredRoute to support or reauth handling.
status="errored"ErrorShow recoverable error and contact/support path.
status="invalidConfig"Needs correctionAsk user to review portal URL or contact support.
status="paused"PausedShow maintenance or support state.
status="revoked"RevokedShow disconnected state and stop polling.
Use syncStatus only on kind="ready" connections:
syncStatusUI label
idleNot currently syncing
syncingSyncing now

Bank portal URL rules

Do not strip query strings or deep paths generically. Send the exact HTTPS portal URL the user entered unless Waycore has explicitly provided a normalized or canonical portal URL through /v1/institutions. Safe rules:
  • For supported institutions, use canonicalPortalUrl as the default display value.
  • Offer additionalPortalUrls when present.
  • For unsupported banks, require the customer to provide a valid HTTPS portal URL.
  • Do not infer login URLs from bank names.
  • Do not convert arbitrary bank homepages into login portals.

Error handling

StatusMeaningHost behavior
400Invalid request, entity, institution, portal URL, cursor, or credential payload.Show a user-safe validation message, and keep the raw API error for developer logs or support.
401Missing or invalid API key.Fix server-side configuration. Do not ask the browser user for the API key.
403API key lacks required scope.Request or configure the missing scope.
404Resource not found or not visible in this API/environment.Treat as unavailable to this API key.
409State conflict, duplicate/cross-environment conflict, setup-stage sync, or sync already running.Show a non-destructive retry or support path.
429Rate limited or connection sync cooldown.Honor Retry-After before retrying.

LLM implementation constraints

If an LLM is generating the host-side product from this document, it must:
  1. Never put a Waycore API key in frontend code.
  2. Use the host backend as the only caller of Waycore public APIs.
  3. Use /v1 API paths only.
  4. Use API key auth only: Authorization: Bearer <key>.
  5. Never show an entity selector to the end customer.
  6. Resolve the Waycore entity on the host backend from the signed-in customer.
  7. Create the Waycore entity ahead of time or lazily in the background before creating the first connection.
  8. Use data and pagination.nextCursor for list responses.
  9. Use connection.setup.instructions for delegated-user details.
  10. Use institutionId for supported institutions and portalUrl for unsupported institutions.
  11. Never invent bank-specific instructions or setup guide URLs.
  12. Treat manual sync as optional because activation starts the initial sync automatically.
  13. Respect sync cooldowns and Retry-After.
  14. Treat DELETE /v1/connections/{id} as destructive.
  15. Map UI labels by lifecycle stage, not by wording.
  16. Treat a credentials/request/start button as connection creation when no Waycore connection exists yet.
  17. Treat an activate/finish/done button as setup completion once the delegated user exists.
  18. Treat cancel/reset/discard as local cleanup before connection creation and explicit deletion only after confirmation.
  19. Avoid promising public transfer execution or transaction preparation unless a separate released API supports it.

Example host-side orchestration

Frontend code calls the host backend:
async function startConnectionFromBrowser(input: StartConnectionInput) {
  const response = await fetch("/api/waycore/start-connection", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify(input),
  })

  if (!response.ok) {
    throw new Error("Unable to start connection")
  }

  return response.json()
}
Server-side code calls Waycore:
interface StartConnectionInput {
  bankPortalUrl?: string
  selectedInstitutionId?: string
}

interface HostUser {
  id: string
  customerId: string
}

interface WaycoreEntityMapping {
  entityId: string
}

async function startConnectionOnServer({
  input,
  user,
}: {
  input: StartConnectionInput
  user: HostUser
}) {
  const entityMapping = await getOrCreateWaycoreEntityForCustomer(user.customerId)

  if (entityMapping == null) {
    throw new Error("Waycore entity mapping is required before creating a connection")
  }

  const body =
    input.selectedInstitutionId == null
      ? {
          entityId: entityMapping.entityId,
          portalUrl: input.bankPortalUrl,
        }
      : {
          entityId: entityMapping.entityId,
          institutionId: input.selectedInstitutionId,
          ...(input.bankPortalUrl
            ? {
                portalUrl: input.bankPortalUrl,
              }
            : {}),
        }

  return waycorePublicApi.createConnection(body)
}

Success criteria

A customer using the host product should feel like they are completing Waycore bank onboarding natively, while the implementation remains safely server-side, uses only /v1 public APIs, and relies on Waycore for delegated-user details, setup state, activation, and sync lifecycle.