Cross-service walkthrough

End-to-end narrative: signup → deposit → payment → group → deal. Touches all three services + the federated gateway.

Guides/Walkthroughs

A single narrative across auth, payments-direct, agents, and the federated gateway: authenticate off-chain, activate one chain account only when it is needed, move value on the matching payments instance, and use federation for cross-subgraph data.

What you'll build

  1. Sign up + log in (auth)
  2. Select a chain + activate its account (auth → payments)
  3. Deposit + send a confidential payment (payments-direct)
  4. Create a working group + post a thread (agents)
  5. Read deal-flow data through federation (gateway → agents/shared core)

Prerequisites

  • Auth REST at auth.yieldfabric.com.
  • The GraphQL gateway at api.yieldfabric.com.
  • Test payments-direct GraphQL and message polling at pay.test.yieldfabric.com (Live uses pay.live.yieldfabric.com).
  • Agents REST/SSE at agents.yieldfabric.com.
  • curl and jq.

Step 1 — Auth: sign up + log in

User creation and login are off-chain. They create identity/key material and a chain-bound session, but no smart account:

curl -s -X POST https://auth.yieldfabric.com/auth/users \
  -H 'Content-Type: application/json' \
  -d '{"email":"demo@yieldfabric.com","password":"correct horse battery staple"}' \
  | jq .

LOGIN=$(curl -s -X POST https://auth.yieldfabric.com/auth/login \
  -H 'Content-Type: application/json' \
  -d '{"email":"demo@yieldfabric.com","password":"correct horse battery staple"}')

TOKEN=$(echo "$LOGIN" | jq -r '.token // .access_token')
REFRESH=$(echo "$LOGIN" | jq -r '.refresh_token')
USER_ID=$(echo "$LOGIN" | jq -r '.user.id')

Per-flow detail: Authentication & signing.

Step 2 — Explicit chain-account activation (auth → payments)

Select an enabled chain through refresh. Refresh tokens rotate, so retain the replacement:

CHAIN_ID=153
MODE_SESSION=$(curl -s -X POST https://auth.yieldfabric.com/auth/refresh \
  -H 'Content-Type: application/json' \
  -d "{\"refresh_token\":\"$REFRESH\",\"chain_id\":\"$CHAIN_ID\"}")

TOKEN=$(echo "$MODE_SESSION" | jq -r '.access_token // .token')
REFRESH=$(echo "$MODE_SESSION" | jq -r '.refresh_token')

Activation is an explicit, idempotent resource. The caller can activate their own user or a group they own/administer; it cannot activate another user:

ACTIVATION_URL="https://auth.yieldfabric.com/entities/user/$USER_ID/chain-accounts/$CHAIN_ID/activation"

ACTIVATION=$(curl -s -X POST "$ACTIVATION_URL" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{}')

echo "$ACTIVATION" | jq .

The lifecycle is provisioning, pending_signature, ready, or failed_retryable. Poll with GET while provisioning. A failed_retryable state may be POSTed again to begin/reconcile the next attempt; pending_signature requires the wallet signing ceremony. Continue only after ready:

curl -s "$ACTIVATION_URL" \
  -H "Authorization: Bearer $TOKEN" \
  | jq '{status, chain_id, wallet_id, account_address}'

Refresh once more on the same explicit chain after readiness so the JWT carries the new default_wallet_id and account_address:

READY_SESSION=$(curl -s -X POST https://auth.yieldfabric.com/auth/refresh \
  -H 'Content-Type: application/json' \
  -d "{\"refresh_token\":\"$REFRESH\",\"chain_id\":\"$CHAIN_ID\"}")
TOKEN=$(echo "$READY_SESSION" | jq -r '.access_token // .token')
REFRESH=$(echo "$READY_SESSION" | jq -r '.refresh_token')

Step 3 — Payments-direct: deposit + send + settle

Wallet/MQ/RPC-backed operations go to the payments instance selected by the JWT chain. For chain 153 in this example:

PAY_URL=https://pay.test.yieldfabric.com

DEPOSIT=$(curl -s -X POST "$PAY_URL/graphql" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "query": "mutation($input: DepositInput!) { deposit(input: $input) { success messageId } }",
    "variables": { "input": {
      "assetId": "aud-token-asset",
      "amount": "100",
      "idempotencyKey": "demo-deposit-1"
    }}
  }')

echo "$DEPOSIT" | jq .
DEPOSIT_MESSAGE_ID=$(echo "$DEPOSIT" | jq -r '.data.deposit.messageId')

Send a confidential payment. destinationId is the recipient's entity or wallet id:

SEND=$(curl -s -X POST "$PAY_URL/graphql" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "query": "mutation($input: InstantSendInput!) { instant(input: $input) { success messageId transactionId } }",
    "variables": { "input": {
      "destinationId": "ENT-…",
      "assetId": "aud-token-asset",
      "amount": "10",
      "idempotencyKey": "demo-send-1"
    }}
  }')

echo "$SEND" | jq .
SEND_MESSAGE_ID=$(echo "$SEND" | jq -r '.data.instant.messageId')

GraphQL mutation success means the MQ accepted the work, not necessarily that the chain transaction settled. Poll each message id on the same payments host until executed is non-null. If the next step reads graph-materialized rows, also wait for post_processed_at:

curl -s "$PAY_URL/api/users/$USER_ID/messages/$SEND_MESSAGE_ID" \
  -H "Authorization: Bearer $TOKEN" \
  | jq '{executed, post_processed_at, response_status}'

Payments mutations do not go through federation in a dual deployment. The gateway is pinned to one payments subgraph for composition; direct Test/Live routing follows the JWT-selected host.

Per-mutation detail: Payments.

Step 4 — Agents: working group + thread

GROUP_ID=$(curl -s -X POST https://agents.yieldfabric.com/working-groups \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"name":"Demo group","description":"Cross-service walkthrough"}' \
  | jq -r .id)

THREAD_ID=$(curl -s -X POST \
  "https://agents.yieldfabric.com/working-groups/$GROUP_ID/threads" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"title":"First thread"}' \
  | jq -r .id)

curl -s -X POST \
  "https://agents.yieldfabric.com/working-groups/$GROUP_ID/threads/$THREAD_ID/messages" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"text":"Hello from the walkthrough"}' \
  | jq .

Agent runtime, working-group model, and threads: Agents, knowledge & workspaces.

Step 5 — Federated GraphQL: cross-subgraph/shared-core reads

Use the gateway where federation adds value: a query that joins or exposes auth, agents, and shared-core entities. Deal-flow is owned by agents and is reachable through the gateway:

curl -s -X POST https://api.yieldfabric.com/graphql \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "query": "query { dealFlow { dealsAwaitingMySignature { id status name } } }"
  }' \
  | jq .

An empty list is expected for a fresh user. Payments-instance mutations and mode-bound payments reads remain payments-direct even when an agents workflow initiates them internally.

Service boundaries you just crossed

Step
1
Direction
client → auth
Mechanism
Off-chain identity/session REST
Step
2
Direction
client → auth → payments
Mechanism
Explicit activation; auth routes by chain id
Step
3
Direction
client → payments-direct
Mechanism
Mode-bound GraphQL + message settlement REST
Step
4
Direction
client → agents
Mechanism
Workspace/thread REST
Step
5
Direction
client → gateway
Mechanism
Federated agents/shared-core query

All surfaces accept the same user JWT, but its default_chain_id determines which payments-direct host may execute mode-bound work.

sequenceDiagram
    autonumber
    participant C as Client
    participant Auth as auth.yieldfabric.com
    participant Pay as pay.test.yieldfabric.com
    participant Agents as agents.yieldfabric.com
    participant Router as api.yieldfabric.com

    C->>Auth: POST /auth/users + /auth/login
    Auth-->>C: Walletless JWT + refresh token
    C->>Auth: POST /auth/refresh (chain 153)
    C->>Auth: POST /entities/user/:id/chain-accounts/153/activation
    Auth->>Pay: DeployAccount on chain 153
    Auth-->>C: provisioning / ready
    C->>Auth: POST /auth/refresh (chain 153)
    Auth-->>C: JWT with chain account

    C->>Pay: POST /graphql (deposit/send)
    Pay-->>C: messageId
    C->>Pay: GET /api/users/:user/messages/:message
    Pay-->>C: execution + post-processing state

    C->>Agents: POST /working-groups/:id/threads
    Agents->>Auth: Validate JWT
    Agents-->>C: Thread state

    C->>Router: Federated dealFlow query
    Router->>Agents: Resolve agents-owned field
    Agents-->>C: Shared response

Failure modes across services

Where
Step 1
Symptom
409 on user create
Cause / fix
Email already exists — log in instead
Where
Step 2
Symptom
provisioning
Cause / fix
Poll the auth activation resource; do not submit wallet-required work
Where
Step 2
Symptom
pending_signature
Cause / fix
Complete the wallet signature ceremony, then resume polling
Where
Step 2/3
Symptom
CHAIN_ACCOUNT_REQUIRED
Cause / fix
Activate the returned entity/chain, refresh there, retry once
Where
Step 3
Symptom
CHAIN_MODE_MISMATCH
Cause / fix
Route the chain-bound JWT to its matching Test/Live payments host
Where
Step 3
Symptom
message has no executed time
Cause / fix
Keep polling; do not infer settlement from mutation success
Where
Step 4
Symptom
403 posting a message
Cause / fix
The caller is not a member of that working group

What's next