# 5 · Treasury

Phase 5 runs **alongside** the quote flow rather than after it, and it is the
one phase where Nexa is the caller on the API legs. Nexa accumulates USDC
from the deposits it credits GTQ against; this phase is how it sees that
balance and converts it out. BitGo's USDC→USD conversion and the payout to
Nexa's own bank are out of scope. The Tesser API calls are in scope.

These are **existing, live Tesser core-API operations**. They are vendored
into [Tesser endpoints exposed to Nexa](/api-tesser) so this reference is
complete in one place; <a href="https://docs.tesser.xyz" target="_blank">docs.tesser.xyz</a>
stays normative, and the vendored copies are diffed against the live
definition in CI so they cannot silently rot.

<Mermaid
  chart={`sequenceDiagram
    autonumber
    participant T as Tesser (orchestrator)
    participant N as Banco Nexa

    Note over T,N: Phase 5 · Nexa treasury (existing Tesser core API)
    N->>T: GET /v1/accounts/{id} [T]
    T-->>N: 200 AccountResponseDto (USDC balance)
    N->>T: POST /v1/treasury/withdrawals [T]
    T-->>N: 201 WithdrawalResponse
    T->>N: webhook: withdrawal status → Nexa's receiver [N]`}
/>

## Step 7 · Read the USDC balance <T />

**Operation:** [`GET /v1/accounts/{id}`: Get an account by ID](/api-tesser/accounts#get-an-account-by-id)
· hosted by **Tesser**, called by **Nexa**.

Nexa's USDC wallet account ID is shared during onboarding (single-wallet
MVP). The response is the core API's `AccountResponseDto`.

<div className="what-can-go-wrong">

**What can go wrong: get account**

These are Tesser **core-API** error codes, not the `error_code` vocabulary
used by the Nexa-facing quote endpoints.

| Error | HTTP | When |
| --- | --- | --- |
| `counterparties-3001` / `counterparties-3002` | 400 | Invalid request. |
| `api-0004` | 401 | Client certificate / API key missing or invalid. |
| `api-0001` | 404 | No account with this ID, or it is not visible to Nexa's organization. |
| `api-0006` | 500 | Unexpected failure on Tesser's side. |

</div>

## Step 8 · Withdraw USDC <T />

**Operation:** [`POST /v1/treasury/withdrawals`: Create withdrawal](/api-tesser/treasury#create-withdrawal)
· hosted by **Tesser**, called by **Nexa**.

Request is the core API's `CreateWithdrawalRequest`
(`organization_reference_id` plus a `desired` overlay); the response is a
`WithdrawalResponse`. Status progression arrives via Tesser's standard
outbound withdrawal webhooks, which is step 9.

<div className="what-can-go-wrong">

**What can go wrong: create withdrawal**

| Error | HTTP | When |
| --- | --- | --- |
| `counterparties-3001` / `counterparties-3002` | 400 | Invalid request. |
| `api-0004` | 401 | Client certificate / API key missing or invalid. |
| `api-0006` | 500 | Unexpected failure on Tesser's side. |

</div>

## Step 9 · Receive Tesser's withdrawal webhooks <N />

**Operation:** [`POST /v1/webhooks/tesser`: Receive Tesser webhook (Nexa implements this)](/api-nexa/webhooks#receive-tesser-webhook-nexa-implements-this)
· hosted by **Nexa**, called by **Tesser**.

This is the one endpoint in the Nexa-hosted document that Nexa builds for
Tesser's benefit rather than Tesser's. It receives Tesser's standard outbound
webhooks, which here means withdrawal status updates for step 8. The
envelope and event types
are Tesser's existing ones; this portal documents the subscription Nexa needs
and links to the core docs rather than re-specifying them.

Delivery authentication is covered on
[Authentication](/authentication): Tesser's webhook sender
signs with Ed25519 (`X-Tesser-Signature`) today and is being extended to
present a client certificate for Nexa deliveries.

<div className="what-can-go-wrong">

**What can go wrong: Tesser to Nexa webhook delivery**

| `error_code` | HTTP | When |
| --- | --- | --- |
| `VALIDATION_ERROR` | 400 | Malformed envelope or unknown event type. |
| `UNAUTHENTICATED` | 401 | Signature invalid, or (once outbound mTLS ships) client certificate missing/unrecognised. |
| `INTERNAL_ERROR` | 500 | Unexpected failure on Nexa's side. **Tesser retries this one.** |

Any 2xx with an empty body is success. Anything else is retried, so the
receiver must be idempotent on the event id.

</div>

**Back to:** [Lifecycle](/flow-nexa/lifecycle) ·
[Webhooks guide](/webhooks-guide)
