Skip to content
Testnet only: a reference implementation, not a production service.Tokens and bank transfers here are simulated and have no value.

Counterparties and trustlines

A counterparty is a party money can move to or from. There are two kinds: a bank_account, which receives fiat, and a stellar_wallet, which receives tokens. Both belong to the organisation and are created with POST /v1/counterparties.

A wallet also needs a trustline to the asset before tokens can reach it. Single-wallet responses carry a checks object that reports whether the account and its trustline exist, and whether the issuer can sponsor a missing one. When the trustline is missing, the issuer sponsors it: the platform prepares a sponsor-signed offer, the wallet co-signs, and the platform submits the result.

Every request on this page runs in CI against an in-process core on FakeChain, so a response that stops matching its # expect line fails the build.

Create a bank counterparty

A bank account is ready to use as soon as it is created.

POST /v1/counterparties
authorization: Bearer {{KEY}}
idempotency-key: {{uuid}}
content-type: application/json

{
  "type": "bank_account",
  "label": "Ops account",
  "beneficiary_name": "Acme Testnet Ltd",
  "bank_name": "Testnet mock bank",
  "account_number": "GB00TEST12345678",
  "routing_code": "TEST0001",
  "currency": "USD"
}
# expect 201
# save BANK = $.id

Create a wallet counterparty

A wallet counterparty is created pending_verification. The response carries an ownership challenge, and only the wallet's key can sign it.

POST /v1/counterparties
authorization: Bearer {{KEY}}
idempotency-key: {{uuid}}
content-type: application/json

{
  "type": "stellar_wallet",
  "address": "{{WALLET_ADDRESS}}",
  "label": "counterparties guide"
}
# expect 201
# save CPTY = $.id
# save CHALLENGE = $.ownership_proof.challenge_xdr
# sign SIGNED_CHALLENGE = CHALLENGE

Read the trustline checks

Read the wallet with GET /v1/counterparties/{id}. The checks object reports the account and trustline state. Here the account is present and the trustline is missing. The wallet is still pending_verification, so no sponsored-trustline offer is available yet; it becomes available once the wallet is active.

GET /v1/counterparties/{{CPTY}}
authorization: Bearer {{KEY}}
# expect 200

Prove control

Submit the signed challenge with POST /v1/counterparties/{id}/ownership-proof. The wallet becomes active. Sponsorship is offered only for active wallets, because it spends the issuer's reserve.

POST /v1/counterparties/{{CPTY}}/ownership-proof
authorization: Bearer {{KEY}}
idempotency-key: {{uuid}}
content-type: application/json

{
  "signed_challenge_xdr": "{{SIGNED_CHALLENGE}}"
}
# expect 200

Sponsor the trustline

Ask for the offer, co-sign the returned envelope with the wallet key, then submit the hash and the signed envelope together. The offer expires about a minute after it is issued.

POST /v1/counterparties/{{CPTY}}/sponsored-trustline
authorization: Bearer {{KEY}}
idempotency-key: {{uuid}}
content-type: application/json

{}
# expect 200
# save TRUSTLINE_HASH = $.hash
# save TRUSTLINE_ENVELOPE = $.envelope_xdr
# sign SIGNED_TRUSTLINE = TRUSTLINE_ENVELOPE
POST /v1/counterparties/{{CPTY}}/sponsored-trustline/submit
authorization: Bearer {{KEY}}
idempotency-key: {{uuid}}
content-type: application/json

{
  "hash": "{{TRUSTLINE_HASH}}",
  "signed_envelope_xdr": "{{SIGNED_TRUSTLINE}}"
}
# expect 200

Read the checks again

Read the wallet once more. The trustline is now present, and no further offer is made.

GET /v1/counterparties/{{CPTY}}
authorization: Bearer {{KEY}}
# expect 200

Edit on GitHub