Connect

Programmatically monitor Connect activity with event-driven webhook notifications

Overview

Connect delivers real-time webhook notifications when deposit and withdrawal events occur. These webhooks are sent to Organization-configured endpoint URLs and provide status updates throughout the lifecycle of each transaction.

There are two webhook payload types:

  • connect_deposit.status_changed - fired when a deposit transitions to a new status
  • connect_withdrawal.status_changed - fired when a withdrawal transitions to a new status

Authentication and Delivery

  • Webhooks are delivered via HTTP POST to the URLs configured in your Organization settings (separate URLs for deposits and withdrawals).
  • Requests are authenticated using Organization-specific KMS-managed credentials.
  • Failed deliveries are retried with exponential backoff.
  • Each webhook has a unique event ID used for idempotency - you may safely deduplicate on this ID.

Webhook Security

Request Headers

HeaderDescription
client-idAlways Connect.
timestampUnix timestamp (seconds) when the request was signed.
signatureBase64-encoded RSA-SHA256 signature of the request.
x-zh-hook-payload-typeThe webhook payload type (e.g., connect_deposit.status_changed).

Validating the signature

  1. Retrieve Connect's public keys from the JWKS endpoint (GET /v1/jwks).
  2. Reconstruct the signing base string by concatenating: {timestamp}POST{webhook_url}{request_body}
    1. timestamp: the value from the timestamp header
    2. POST: the HTTP method (always POST)
    3. webhook_url: the full URL of your webhook endpoint
    4. request_body: the raw JSON request body
  3. Base64-decode the signature header value.
  4. Verify the decoded signature against the signing base using the RSA public key with PKCS1 v1.5 SHA-256.

Deposit Webhooks

Payload type: connect_deposit.status_changed

Deposit event names

Event NameDescription
connect.deposits.pendingThe end user clicked Submit on the Connect SDK, Connect has created a transaction within our system, and we are preparing to initiate the transaction within the connected-accounts' (ie, Coinbase) system
connect.deposits.submittedThe deposit has been created within the connected-accounts' (ie, Robinhood) system
connect.deposits.confirmedThe deposit has been confirmed on-chain
connect.deposits.unexpectedConnect received a deposit that was outside of the normal Auth flow. See full guide here.

Only relevant if you are configured to prevent non-auth deposits
connect.deposits.abandonedThe end user started the deposit flow, but no deposit was received within 30 minutes
connect.deposits.failedWhen Connect attempted to initiate the transaction with the connected-account, the connected-account failed the API call.

Note: If you receive a connect.deposits.submitted webhook, followed by an connect.deposits.abandoned one, it means that either the connected-account had an issue processing the transaction or the blockchain itself had an issue processing the transaction. In either case, the user's balance at the connected-account should be re-credited.

Deposit Payload Fields

Top-level fields:

FieldTypeDescription
eventstringThe event name (ie, connect.deposits.confirmed)
depositobjectDeposit details (see below)
sessionobjectSession details (see below)
accountobjectAccount details (see below)

deposit Object

FieldTypeAlways in payload?Always has a value?Description
idstringYesYesUnique identifier for the deposit
amountstringYesYesDeposit amount (ie, .13 BTC)
networkstringYesYesBlockchain network (ie, ethereum)
assetstringYesYesAsset (ie, USD, BTC, or ETH)
created_atstringYesYesTimestamp when the deposit was created (ISO 8601).
updated_atstringYesYesTimestamp when the deposit was last updated (ISO 8601).
statusstringNoWhen present, yesCurrent status value.
transactionobjectYesYes (but inner fields vary)On-chain transaction details (see below).
sourceobjectNoWhen present, yesSource of the deposit (see below). Present when the deposit originates from a known integration.
failure_reasonstringNoWhen present, yesReason for failure. Only present when the deposit has failed.
account_labelstringNoWhen present, yesLabel of the account associated with the withdrawal.

deposit.transaction object

FieldTypeAlways in payload?Always has a value?Description
hashstringYesNo - empty string until transaction is on-chainBlockchain transaction hash.
tostringNoWhen present, yesDestination address on-chain
block_numberstringNoWhen present, yesBlock number in which the transaction was included.
valuestringNoWhen present, yesRaw on-chain value of the transaction.

deposit.source object (when present)

FieldTypeDescription
typestringSource type: CUSTODIAL, NON_CUSTODIAL, or MANUAL
integrationstringIntegration identifier (ie, robinhood, geminietc)

session object

FieldTypeDescription
idstringSession identifier
metadataobjectKey-value metadata attached to the session at creation time
created_atstringTimestamp when the session was created (ISO 8601)

account object

FieldTypeDescription
reference_idstringYour external reference ID for the account (ie, the participant_code)

Example Deposit Payloads

Example Deposit Payload - connect.deposits.pending

  {  
    "event": "connect.deposits.pending",  
    "deposit": {  
      "id": "d1a2b3c4-5678-90ab-cdef-1234567890ab",  
      "amount": "0.05",  
      "network": "ethereum",  
      "asset": "ETH",  
      "created_at": "2026-03-29T14:00:00Z",  
      "updated_at": "2026-03-29T14:00:00Z",  
      "status": "pending",  
      "transaction": {  
        "hash": ""  
      },  
      "source": {  
        "type": "CUSTODIAL",  
        "integration": "robinhood"  
      },  
      "account_label": "abc123"  
    },  
    "session": {  
      "id": "a1b2c3d4-0000-0000-0000-000000000001",  
      "metadata": {  
        "user_id": "usr_12345",  
        "order_id": "ord_67890"  
      },  
      "created_at": "2026-03-29T13:55:00Z"  
    },  
    "account": {  
      "reference_id": "CUST01"  
    }  
  }

Example Deposit Payload - connect.deposits.submitted

  {  
    "event": "connect.deposits.submitted",  
    "deposit": {  
      "id": "d1a2b3c4-5678-90ab-cdef-1234567890ab",  
      "amount": "0.05",  
      "network": "ethereum",  
      "asset": "ETH",  
      "created_at": "2026-03-29T14:00:00Z",  
      "updated_at": "2026-03-29T14:02:00Z",  
      "status": "submitted",  
      "transaction": {  
        "hash": "0xabc123def4567890abc123def4567890abc123def4567890abc123def4567890"  
      },  
      "source": {  
        "type": "CUSTODIAL",  
        "integration": "robinhood"  
      },  
      "account_label": "abc123"  
    },  
    "session": {  
      "id": "a1b2c3d4-0000-0000-0000-000000000001",  
      "metadata": {  
        "user_id": "usr_12345",  
        "order_id": "ord_67890"  
      },  
      "created_at": "2026-03-29T13:55:00Z"  
    },  
    "account": {  
      "reference_id": "CUST01"  
    }  
  }

Example Deposit Payload - connect.deposits.confirmed

  {  
    "event": "connect.deposits.confirmed",  
    "deposit": {  
      "id": "d1a2b3c4-5678-90ab-cdef-1234567890ab",  
      "amount": "0.05",  
      "network": "ethereum",  
      "asset": "ETH",  
      "created_at": "2026-03-29T14:00:00Z",  
      "updated_at": "2026-03-29T14:15:00Z",  
      "status": "confirmed",  
      "transaction": {  
        "hash": "0xabc123def4567890abc123def4567890abc123def4567890abc123def4567890",  
        "to": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD68",  
        "block_number": "19234567",  
        "value": "50000000000000000"  
      },  
      "source": {  
        "type": "CUSTODIAL",  
        "integration": "robinhood"  
      },  
      "account_label": "abc123"  
    },  
    "session": {  
      "id": "a1b2c3d4-0000-0000-0000-000000000001",  
      "metadata": {  
        "user_id": "usr_12345",  
        "order_id": "ord_67890"  
      },  
      "created_at": "2026-03-29T13:55:00Z"  
    },  
    "account": {  
      "reference_id": "CUST01"  
    }  
  }

Example Deposit Payload - connect.unexpected.failed

  {  
    "event": "connect.deposits.unexpected",  
    "deposit": {  
      "id": "d7a6b5c4-3210-98fe-badc-765432109edc",  
      "amount": "0.75",  
      "network": "ethereum",  
      "asset": "USDT",  
      "created_at": "2026-03-29T16:00:00Z",  
      "updated_at": "2026-03-29T16:00:00Z",  
      "status": "unexpected",  
      "transaction": {  
        "hash": "0x7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b",  
        "to": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD68",  
        "value": "750000000000000000"  
      }  
    },  
    "session": {  
      "id": "d4e5f6a7-0000-0000-0000-000000000004",  
      "metadata": {},  
      "created_at": "2026-03-29T15:50:00Z"  
    },  
    "account": {  
      "reference_id": "CUST01"  
    }  
  }

Example Deposit Payload - connect.deposits.failed

{  
    "event": "connect.deposits.failed",  
    "deposit": {  
      "id": "d9f8e7d6-5432-10fe-dcba-0987654321ab",  
      "amount": "1.00",  
      "network": "bitcoin",  
      "asset": "BTC",  
      "created_at": "2026-03-29T10:00:00Z",  
      "updated_at": "2026-03-29T10:30:00Z",  
      "status": "failed",  
      "transaction": {  
        "hash": "3a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b"  
      },  
      "failure_reason": "Transaction reverted on-chain",  
      "account_label": "primary"  
    },  
    "session": {  
      "id": "b2c3d4e5-0000-0000-0000-000000000002",  
      "metadata": {},  
      "created_at": "2026-03-29T09:55:00Z"  
    },  
    "account": {  
      "reference_id": "customer-67890"  
    }  
  }

Example Deposit Payload - connect.abandoned.failed

  {  
    "event": "connect.deposits.abandoned",  
    "deposit": {  
      "id": "d8e7f6a5-4321-09fe-cbad-876543210fed",  
      "amount": "2.00",  
      "network": "ethereum",  
      "asset": "ETH",  
      "created_at": "2026-03-29T08:00:00Z",  
      "updated_at": "2026-03-29T09:00:00Z",  
      "status": "abandoned",  
      "transaction": {  
        "hash": ""  
      },  
      "source": {  
        "type": "CUSTODIAL",  
        "integration": "robinhood"  
      },  
      "account_label": "abc123"  
    },  
    "session": {  
      "id": "c3d4e5f6-0000-0000000-000000000003",  
      "metadata": {  
        "user_id": "usr_55555"  
      },  
      "created_at": "2026-03-29T07:55:00Z"  
    },  
    "account": {  
      "reference_id": "CUST01"  
    }  
  }

Withdrawal Webhooks

Payload type: connect_withdrawal.status_changed

Withdrawal event names

Event NameDescription
connect.withdrawals.pendingWithdrawal has been created and is queued for processing.
connect.withdrawals.pendingWithdrawal has been submitted to the blockchain network for processing.
connect.withdrawals.confirmedWithdrawal has been confirmed on-chain and completed successfully.
connect.withdrawals.failedWithdrawal failed during processing.

Withdrawal Payload Fields

Top-level fields:

FieldTypeDescription
eventstringThe event name (ie, connect.withdrawals.confirmed).
withdrawalobjectWithdrawal details (see below).
sessionobjectSession details (same structure as deposits).
accountobjectAccount details (same structure as deposits).

withdrawal object

FieldTypeAlways in payload?Description
idstringYesUnique identifier for the withdrawal.
amountstringYesWithdrawal amount.
networkstringYesBlockchain network (ie, ethereum, bitcoin).
assetstringYesAsset identifier (ie, ETH, BTC).
created_atstringYesTimestamp when the withdrawal was created (ISO 8601).
updated_atstringYesTimestamp when the withdrawal was last updated (ISO 8601).
statusstringWhen present, yesCurrent status value. Omitted when empty.
transactionobjectYes (but inner fields vary)On-chain transaction details (see below).
destinationobjectWhen present, yesDestination of the withdrawal. Only present when the withdrawal is sent to a known integration.
account_labelstringWhen present, yesLabel of the account associated with the withdrawal.

withdrawal.transaction object

FieldTypeAlways in payload?Always has a value?Description
hashstringYesNo - empty string until transaction is on-chainBlockchain transaction hash.
tostringNoWhen present, yesDestination wallet address. Omitted when not known.
block_numberstringNoWhen present, yesBlock number in which the transaction was included. Only present once confirmed on-chain.
valuestringNoWhen present, yesRaw on-chain value of the transaction. Only present once confirmed on-chain.

withdrawal.destination object (when present):

FieldTypeDescription
typestringDestination type: CUSTODIAL, NON_CUSTODIAL, or MANUAL.
integrationstringIntegration identifier: robinhood,gemini, metamask, manual, etc

Example Withdrawal Payloads

connect.withdrawals.pending

  {  
    "event": "connect.withdrawals.pending",  
    "withdrawal": {  
      "id": "w1a2b3c4-5678-90ab-cdef-fedcba098765",  
      "amount": "0.10",  
      "network": "ethereum",  
      "asset": "ETH",  
      "created_at": "2026-03-29T16:00:00Z",  
      "updated_at": "2026-03-29T16:00:00Z",  
      "status": "pending",  
      "transaction": {  
        "hash": "",  
        "to": "0x1234567890abcdef1234567890abcdef12345678"  
      },  
      "destination": {  
        "type": "CUSTODIAL",  
        "integration": "robinhood"  
      },  
      "account_label": "abc123"  
    },  
    "session": {  
      "id": "f6a7b8c9-0000-0000-0000-000000000006",  
      "metadata": {  
        "user_id": "usr_12345"  
      },  
      "created_at": "2026-03-29T15:50:00Z"  
    },  
    "account": {  
      "reference_id": "CUST01"  
    }  
  }

connect.withdrawals.pending

  {  
    "event": "connect.withdrawals.pending",  
    "withdrawal": {  
      "id": "w1a2b3c4-5678-90ab-cdef-fedcba098765",  
      "amount": "0.10",  
      "network": "ethereum",  
      "asset": "ETH",  
      "created_at": "2026-03-29T16:00:00Z",  
      "updated_at": "2026-03-29T16:00:00Z",  
      "status": "pending",  
      "transaction": {  
        "hash": "",  
        "to": "0x1234567890abcdef1234567890abcdef12345678"  
      },  
      "destination": {  
        "type": "CUSTODIAL",  
        "integration": "robinhood"  
      },  
      "account_label": "abc123"  
    },  
    "session": {  
      "id": "f6a7b8c9-0000-0000-0000-000000000006",  
      "metadata": {  
        "user_id": "usr_12345"  
      },  
      "created_at": "2026-03-29T15:50:00Z"  
    },  
    "account": {  
      "reference_id": "CUST01"  
    }  
  }

connect.withdrawals.submitted

  {  
    "event": "connect.withdrawals.submitted",  
    "withdrawal": {  
      "id": "w1a2b3c4-5678-90ab-cdef-fedcba098765",  
      "amount": "0.10",  
      "network": "ethereum",  
      "asset": "ETH",  
      "created_at": "2026-03-29T16:00:00Z",  
      "updated_at": "2026-03-29T16:01:00Z",  
      "status": "submitted",  
      "transaction": {  
        "hash": "",  
        "to": "0x1234567890abcdef1234567890abcdef12345678"  
      },  
      "destination": {  
        "type": "CUSTODIAL",  
        "integration": "robinhood"  
      },  
      "account_label": "abc123"  
    },  
    "session": {  
      "id": "f6a7b8c9-0000-0000-0000-000000000006",  
      "metadata": {  
        "user_id": "usr_12345"  
      },  
      "created_at": "2026-03-29T15:50:00Z"  
    },  
    "account": {  
      "reference_id": "CUST01"  
    }  
  }

connect.withdrawals.confirmed

  {  
    "event": "connect.withdrawals.confirmed",  
    "withdrawal": {  
      "id": "w1a2b3c4-5678-90ab-cdef-fedcba098765",  
      "amount": "0.10",  
      "network": "ethereum",  
      "asset": "ETH",  
      "created_at": "2026-03-29T16:00:00Z",  
      "updated_at": "2026-03-29T16:20:00Z",  
      "status": "confirmed",  
      "transaction": {  
        "hash": "0xdef789abc123456def789abc123456def789abc123456def789abc123456def78",  
        "to": "0x1234567890abcdef1234567890abcdef12345678"  
      },  
      "destination": {  
        "type": "CUSTODIAL",  
        "integration": "robinhood"  
      },  
      "account_label": "abc123"  
    },  
    "session": {  
      "id": "f6a7b8c9-0000-0000-0000-000000000006",  
      "metadata": {  
        "user_id": "usr_12345"  
      },  
      "created_at": "2026-03-29T15:50:00Z"  
    },  
    "account": {  
      "reference_id": "CUST01"  
    }  
  }

connect.withdrawals.failed

  {  
    "event": "connect.withdrawals.failed",  
    "withdrawal": {  
      "id": "w9z8y7x6-5432-10fe-dcba-0987654321ab",  
      "amount": "500.00",  
      "network": "bitcoin",  
      "asset": "BTC",  
      "created_at": "2026-03-29T12:00:00Z",  
      "updated_at": "2026-03-29T12:15:00Z",  
      "status": "failed",  
      "transaction": {  
        "hash": "",  
        "to": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh"  
      },  
      "destination": {  
        "type": "NON_CUSTODIAL",  
        "integration": "metamask"  
      },  
      "account_label": "def456"  
    },  
    "session": {  
      "id": "a7b8c9d0-0000-0000-0000-000000000007",  
      "metadata": {},  
      "created_at": "2026-03-29T11:55:00Z"  
    },  
    "account": {  
      "reference_id": "CUST01"  
    }  
  }