Developer guide

Partner integration

13 min read

The architecture separates three independent choices: entry channel, authorization mode and blockchain execution model. Choosing WhatsApp leaves the question of who signs and who broadcasts open; choosing external broadcast leaves the user's experience as it is.

Partner-app-first

sequenceDiagram
    autonumber
    participant U as User
    participant APP as Partner app
    participant PB as Partner backend
    participant SDK as B2B SDK
    participant API as B2B API
    participant OP as Operation
    participant SG as Partner signer
    participant CH as Blockchain
    participant R as Reconciler
    participant WH as Webhook

    U->>APP: Recipient, asset, amount
    APP->>PB: Request quote
    PB->>SDK: createQuote
    SDK->>API: POST /v1/quotes
    API-->>PB: Quote + fees + expiry
    PB-->>APP: Show summary
    U->>APP: Confirm
    APP->>PB: Authenticated confirmation
    PB->>SDK: createTransfer + idempotency key
    SDK->>API: POST /v1/transfers
    API-->>PB: operation_id
    API->>OP: Process
    OP->>SG: Request signature
    SG-->>OP: Signature
    OP->>CH: Broadcast
    R->>CH: Receipt / finality
    R->>OP: Reconcile
    OP->>WH: Event
    WH-->>PB: Signed webhook
    PB-->>APP: Update status

What each step does

  1. User → Partner app. The person picks recipient, asset and amount in the Partner's own interface. The Partner owns the experience and the session.
  2. App → Partner backend. The app asks its own backend for the quote, which keeps the API credential off the device.
  3. Backend → SDK: createQuote. The SDK is a typed client of the B2B API, and the caller works with the types of the contract.
  4. SDK → API: POST /v1/quotes. The tenant is derived from the authenticated credential.
  5. API → backend: quote, fees and expiry. The quote carries the fee breakdown — network fee, provider fee, service fee, total — the policy version it was priced under, and the moment it expires. Amounts travel in integer minimum units.
  6. Backend → app: show the summary. The person sees the total they are about to authorize before deciding.
  7. User → app: confirmation. The confirmation is given against that summary, which is what binds it to the quote that was shown.
  8. App → backend: authenticated confirmation. The Partner applies its own authentication, KYC and risk rules here, where its user session lives.
  9. Backend → SDK: createTransfer with an idempotency key. The key is what makes a retry safe: the same key returns the same operation instead of sending twice.
  10. SDK → API: POST /v1/transfers.
  11. API → backend: operation_id. The answer confirms acceptance, so the backend holds no open connection waiting for finality.
  12. API → Operation: process. The Operation is persisted with its reserve and its event, and from here the flow survives a restart.
  13. Operation → Partner signer: request the signature. A keyReference and a digest travel under the tenant's policy.
  14. Signer → Operation: signature. It returns with an audit reference and a key version, and the API verifies it against the digest and the expected address.
  15. Operation → blockchain: broadcast. The adapter of the enabled network builds and submits the transaction.
  16. Reconciler → chain: receipt and finality. The observer waits for the depth agreed for this operation.
  17. Reconciler → Operation: reconcile. The amounts settled and the fees paid are contrasted against what was recorded.
  18. Operation → webhook dispatcher: event. The event is written in the same transaction as the change that caused it, so every state change has its event.
  19. Dispatcher → backend: signed webhook. Delivery is at-least-once, so the backend deduplicates by event identifier.
  20. Backend → app: update the status. The Partner rebuilds its own projection, and GET Operation and the event cursor cover a delayed delivery.

Advantages: it integrates with the authentication, KYC, risk and UX already in place; the Partner controls the whole experience; webhooks feed the detail view.

Trade-offs: the Partner maintains a backend and a state projection; starting operations depends on the availability of its app and backend.

WhatsApp-first

sequenceDiagram
    autonumber
    participant U as User
    participant WA as Partner WhatsApp
    participant BOT as Partner conversational instance
    participant API as B2B API
    participant RR as Recipient Resolver
    participant OP as Operation
    participant SG as Partner signer
    participant CH as Blockchain
    participant PB as Partner backend

    U->>WA: Send asset/amount to a contact
    WA->>BOT: Inbound message
    BOT->>API: Resolve + quote
    API->>RR: Alias to ChainAccount
    RR-->>API: Destination + state
    API-->>BOT: Quote + fees
    BOT-->>U: Summary and confirmation
    U->>BOT: Confirm
    BOT->>API: Create idempotent operation
    API->>OP: Policy + limits + signature
    OP->>SG: Request signature
    SG-->>OP: Signature
    OP->>CH: Broadcast
    OP-->>BOT: State
    OP-->>PB: Signed webhook
    BOT-->>U: Result

What each step does

  1. User → WhatsApp. The person says what they want in plain words, on the Partner's own number.
  2. WhatsApp → conversational instance. The inbound message reaches the instance, which reads the intent and collects whatever is missing.
  3. Instance → API: resolve and quote. One request covers who the recipient is and what the transfer costs.
  4. API → Recipient Resolver: alias to ChainAccount. The alias is normalized and resolved inside the tenant.
  5. Resolver → API: destination and state. The answer carries the address and whether that account is already active on the network.
  6. API → instance: quote and fees. The same fee breakdown and expiry as any other channel.
  7. Instance → user: summary and confirmation. The person sees amount, recipient, fees and total before deciding.
  8. User → instance: confirmation. The explicit confirmation is what authorizes the operation in this channel. The phone number acts as an alias, and the authority to spend comes from the link between that alias and an enabled TenantUser.
  9. Instance → API: create the idempotent operation. The request carries the idempotency key and the evidence of the channel.
  10. API → Operation: policy, limits and signing policy. The API checks that the sender is linked and enabled, and applies the tenant's limits before anything is signed.
  11. Operation → Partner signer: request the signature.
  12. Signer → Operation: signature.
  13. Operation → blockchain: broadcast.
  14. Operation → instance: state. The conversation receives the state of the operation, and the person is told without having to ask again.
  15. Operation → Partner backend: signed webhook. The Partner's backend receives the same durable event, so its projection matches what happened in the conversation.
  16. Instance → user: result.

WhatsApp-first is still B2B when the user, tenant, WABA, policies, signer and financial relationship belong to the Partner. The phone number serves as a channel alias and as a way to resolve recipients, and the authority to move funds comes from the link to an enabled TenantUser.

Authorization modes from WhatsApp

ModeHow it worksAdvantageCost / limitation
Direct confirmation in WhatsAppA linked user confirms the quote; B2B applies limits and signer policyLeast friction and least synchronous dependencyRequires strong linking, limits and risk controls
Partner callbackB2B asks the Partner backend for every operationThe Partner decides in real timeAdds latency and a dependency on that backend
Signed grant/assertionThe Partner issues an authorization scoped by scope, amount, nonce and expiryAvoids a callback per operationRequires issuance, revocation and replay protection
Step-up in the Partner appWhatsApp starts it; the Partner app confirms the sensitive operationStronger security for higher riskChanges channel and adds friction

Initial baseline Direct confirmation in WhatsApp for previously linked users, under the tenant's limits and policy. The other modes can be enabled by risk or capability.

Partner callback

sequenceDiagram
    autonumber
    participant U as User
    participant BOT as WhatsApp channel
    participant API as B2B API
    participant PB as Partner backend
    participant OP as Operation
    U->>BOT: Confirms the quote
    BOT->>API: Confirmation + channel evidence
    API->>PB: Request a decision
    PB-->>API: approved / denied / step-up
    API->>OP: Create only when authorized
    API-->>BOT: Authorization outcome

The Partner can run its own rules in real time. The contract defines the timeout, the idempotency and what happens while that backend is unavailable: a missing answer counts as a denial.

Signed grant

sequenceDiagram
    autonumber
    participant PB as Partner backend
    participant BOT as WhatsApp channel
    participant API as B2B API
    participant OP as Operation
    PB-->>BOT: Scoped grant
    BOT->>API: Confirmed quote + grant
    API->>API: Verify issuer/user/scope/limits/nonce/expiry
    API->>OP: Create when the grant is valid
    API-->>BOT: operation_id / rejection

The grant reduces the synchronous dependency, and it needs expiry, revocation and replay protection. Its authority reaches as far as its scope, amount, nonce and expiry state.

Step-up in the Partner app

sequenceDiagram
    autonumber
    participant U as User
    participant BOT as WhatsApp channel
    participant API as B2B API
    participant APP as Partner app
    participant PB as Partner backend
    participant OP as Operation
    U->>BOT: Requests a sensitive operation
    BOT->>API: Draft + quote
    API-->>BOT: step-up required + challenge
    BOT-->>U: Open the app / deep link
    U->>APP: Confirms the challenge
    APP->>PB: Authenticated confirmation
    PB->>API: Resolve the challenge
    API->>OP: Continue the operation
    API-->>BOT: operation_id

The challenge is bound to the original draft and quote, so a reinforced confirmation applies to that operation alone.

Blockchain execution models

B2B coordinates the execution

Initial recommended model

The channel delivers an authorized intent. ChatterPay creates the Operation, builds the payload, asks the Partner-controlled signer for a signature, broadcasts, observes and reconciles.

sequenceDiagram
    autonumber
    participant P as Partner / channel
    participant API as B2B API
    participant SG as Partner signer
    participant CH as Blockchain
    participant R as Reconciler
    P->>API: Authorized intent
    API->>SG: Digest + keyReference
    SG-->>API: Signature
    API->>CH: Broadcast
    R->>CH: Evidence
    R-->>P: Webhook / state

The Partner executes on-chain itself

ChatterPay can resolve the recipient and later import a reference to the external transaction. Keeping reconciliation equivalent requires linking that external operation deterministically to an Operation.

sequenceDiagram
    autonumber
    participant PB as Partner backend
    participant API as B2B API
    participant CH as Blockchain
    PB->>API: Resolve the destination
    API-->>PB: Address
    PB->>CH: Build + sign + broadcast
    CH-->>PB: tx_hash
    PB->>API: Import tx_hash + intent reference
    API->>CH: Observe / reconcile
    API-->>PB: State / webhook

ChatterPay builds and the Partner broadcasts

ChatterPay validates the intent and returns a payload and digest. The Partner signs and broadcasts, and then returns the on-chain reference. This model requires an expiry, a policy binding and explicit treatment of an ambiguous broadcast.

sequenceDiagram
    autonumber
    participant PB as Partner backend
    participant API as B2B API
    participant SG as Partner signer
    participant CH as Blockchain
    participant R as Reconciler
    PB->>API: Create Operation
    API-->>PB: Payload/digest + expiry + policy binding
    PB->>SG: Sign
    SG-->>PB: Signature
    PB->>CH: Broadcast
    CH-->>PB: tx_hash / ambiguous result
    PB->>API: Import the broadcast result
    API->>R: Observe and reconcile
    R-->>PB: Webhook / state

The imported reference has to match the authorized payload exactly. Closing an Operation as successful requires a transaction hash that agrees with the intent, the chain and the expiry.

Comparison

ResponsibilityB2B coordinatesPartner executesB2B builds / Partner broadcasts
User authenticationPartner/channelPartnerPartner
Payload constructionChatterPayPartnerChatterPay
Key controlPartner signerPartnerPartner
BroadcastChatterPay workerPartnerPartner
Durable OperationNativeRequires import/linkNative + result callback
Ledger and reconciliationCompleteComplete once evidence is importedComplete after importing the broadcast
Integration complexityLow/mediumHighHigh

Reference combinations

ChannelUser authorizationExecutionReference use
Partner appAuthenticated confirmation in the appB2B coordinatesMain baseline
WhatsAppDirect confirmation by a linked userB2B coordinatesConversational baseline
WhatsAppStep-up in the appB2B coordinatesHigher risk or amount
WhatsAppPartner callbackB2B coordinatesThe Partner's own synchronous rule
Partner appConfirmation in the appThe Partner executesInteroperability
Partner appConfirmation in the appB2B builds / the Partner broadcastsAdvanced interoperability

How fast you may call

Authentication says who is calling; it says nothing about how often. Every authenticated route of this API is bounded, and three bounds are charged at once: per client, per tenant and for the deployment as a whole. The tenant bound is above one client's, so a Partner running a backend, a bot and a dashboard has room for all three — and cannot buy a fourth budget by registering a fourth client.

A request over a bound is answered 429 with Retry-After, before the work it asked for is started: it costs the deployment nothing, and it consumes none of the bounds it did not exceed. The problem document carries code: "RATE_LIMIT_EXCEEDED" and details.scopeclient, tenant or deployment — and never another caller's identifier.

What a bound is depends on what a route costs, not on how it is spelled: reads are the loosest, writes are in between, and the routes that move money or spend the deployment's funds are the tightest. /health is never bounded, because a throttled health check reports a deployment as down for the reason that it is busy.

Retry-After is an instruction, not a hint. The official SDK waits it out rather than applying a backoff of its own, and gives up instead of sleeping past your request timeout. A client that retries sooner is refused again, for the same reason and at the same cost.

App and dashboards

The Partner app can be the only end-user UI. The recommended pattern is webhook for updates plus GET Operation and events for recovery. The SDK is a typed client of the B2B API: it holds credentials for that API and calls its endpoints, and signing stays with the Partner Signer Gateway.

To project the detail of an operation, the Partner can keep at least operation_id, state, type, network, asset, requested and received amounts, fee breakdown, on-chain references, timestamps, and error or review codes where they apply. The API and the events are the authoritative source when a webhook delivery is delayed.

Optional surfaces, separated by audience:

  • a white-label portal for the Partner's users;
  • a Chatizalo operations dashboard for conversations and channel;
  • a B2B console for administration and control plane: networks, fees, limits and configuration.

Each surface keeps its own privileges and reaches its data through the API.

A possible evolution is a Partner Operations Console that brings the Chatizalo operation modules and the B2B configuration into one visual surface, while APIs, persistence, RBAC and audit stay separate.

AudienceTypical surfaceScope
partner_userPartner app / white-label portalTheir own wallets, balances and operations
partner_supportOperations dashboardConversations and operational reading
partner_adminB2B consoleAllowed configuration, limits, webhooks and capabilities
chatterpay_supportCross-component supportScoped and audited diagnosis
chatterpay_adminTechnical administrationPrivileged and audited operation

Capabilities in this area

This area covers the capabilities below. The Roadmap states the current availability of each one.

  • B2B API and asynchronous operations — The Partner sends an operation and immediately receives an identifier and a state. Settlement takes as long as the network takes, so the final state arrives through events or by querying the operation.

  • Official SDK — A typed client that handles authentication, idempotency keys, retries and the operation model. The Partner calls a method and receives the typed answer.

  • Portal and Sandbox backed by the SDK — The Sandbox on this site executes with the published SDK against a running B2B API. The requests it makes are the same ones a Partner's code makes.

  • Reference Partner and webhook receiver — An example application that authenticates against the API, sends operations and receives webhooks. It verifies the signature of every delivery and rejects the ones that do not verify.

  • OpenAPI, API and SDK fully synchronized — The OpenAPI specification, the implementation and the SDK are generated and checked from the same source. A field that is documented but not implemented, or the other way round, stops the build.

  • Bounds on how fast a credential may call — Every authenticated route is bounded per client, per tenant and for the deployment as a whole, and a caller over one of them is answered 429 with Retry-After before the work starts. Authentication says who is calling; it says nothing about how often.

  • Secure MCP API surface — Exposing the operations of the API as Model Context Protocol tools, with the same authentication, the same limits and the same human confirmation required from any other caller.