InvestiFiPartner APIBeta
Prod Environment

Guides

End-to-end integration patterns built from the transaction and user endpoints.

Transaction Completed Event

Delivers a completed transaction to your callback URL. Sent to every callback URL subscribed to the `transaction` event type when an order of one of your financial institution's users fills: the trade completed and the user's holdings and cash balance changed. Other lifecycle movements (creation, pending states, cancellations, failures) are not delivered. A managed-portfolio (`robo` product) deposit, withdrawal, or rebalance delivers one webhook for the whole transaction once it completes, not one per buy/sell leg it placed. `data.transaction_id` names that managed-portfolio transaction; the legs remain separate records in the transaction feed. `data.status` uses the same vocabulary the transaction endpoints report and always carries `completed` today. Filter on `data.status` rather than assuming every delivery is a completion, so new statuses can be delivered in the future without breaking your consumer. The transaction is named by the `data.transaction_id` the transaction endpoints resolve. The payload deliberately carries no balances, positions, quantities, or amounts. On receipt, refetch what you need: `links.self` points at the authoritative transaction record, and the Get User Detail endpoint returns the user's refreshed account values (for example to update a balance shown in your app after the fill). Each request carries two headers: - `X-InvestiFi-Webhook-Id`: the delivery's idempotency key, equal to `event_id` and reused across retries. Deduplicate on it. - `X-InvestiFi-Webhook-Signature`: `t=<unix_seconds>,v1=<hex digest>`. The digest is a hash-based message authentication code (HMAC-SHA256) over the timestamp, a period, and the raw request body, keyed by the signing secret returned from your first subscribe. `v1` is a scheme tag: match on it rather than assuming one value. The header is sent once your financial institution has a signing secret. Verify against the raw request body, before parsing it, so the bytes match what was signed. Compare digests in constant time: ```python import hashlib import hmac parts = dict(p.split("=", 1) for p in signature_header.split(",")) signed = f"{parts['t']}.{raw_body.decode()}".encode() expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest() if not hmac.compare_digest(expected, parts["v1"]): raise ValueError("Signature does not match") ``` Delivery is at-least-once. Return any 2xx status to acknowledge; a non-2xx response or a timeout is retried.

Dashboard tile on the DBP

Build an investment tile in your own UI — four member states, balances, disclosures, and gain/loss.