Skip to content

docs: correct the ownership challenge behavior and list its account statuses - #898

Draft
shreyav wants to merge 3 commits into
mainfrom
shreyav/fix-ownership-verification-docs
Draft

docs: correct the ownership challenge behavior and list its account statuses#898
shreyav wants to merge 3 commits into
mainfrom
shreyav/fix-ownership-verification-docs

Conversation

@shreyav

@shreyav shreyav commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Reason

Running the Travel Rule catalog against the dev Striga platform turned up two
endpoint descriptions that do not match what the API does, and two status tables
that omit the ownership statuses entirely.

Two wrong claims, present in both the customer and platform challenge files:

Doc said Observed
"Calling this endpoint again abandons any in-flight challenge" Returns the outstanding challenge unchanged: same messageToSign, same expiresAt
"An UNVERIFIED account returns to PENDING_OWNERSHIP_VERIFICATION when a new challenge is issued" Stays UNVERIFIED until a retry succeeds

The implemented behavior is the better one in the first case: a user who reloads
a signing page gets the same message back rather than invalidating the one they
were about to sign. So the docs move, not the code.

The status tables are incomplete and, in one place, misleading. Neither
snippets/external-accounts.mdx nor ramps/accounts/external-accounts.mdx
listed PENDING_OWNERSHIP_VERIFICATION or UNVERIFIED. The ramps table has a
"Can Use for Conversions" column marking everything other than ACTIVE as ,
but transfers below the regulatory threshold go through while a wallet is
pending. As written it tells integrators to build a block that Grid does not
impose.

Overview

  • Rewrites the "calling this endpoint again" paragraph in both challenge files to
    describe the real behavior, and adds that requesting LIVENESS starts a
    liveness attempt even while a signature challenge is outstanding.
  • Adds PENDING_OWNERSHIP_VERIFICATION and UNVERIFIED to both status tables,
    with the ramps "can use" column reading "Below the regulatory threshold"
    instead of a yes/no that cannot express the real rule.
  • Adds a short note to each explaining how a wallet reaches the status and how to
    clear it, naming both verification methods rather than only the signature.

No change to ExternalAccountStatus.yaml. Its UNVERIFIED description became
accurate once webdev #34316 landed: a refused signature now does move the account
there.

Test Plan

make build then make lint — exits 0, zero errors, 55 warnings, which is the
same count as main. The two informational notices mentioning challenge and
ownership schemas (ScaChallenge.factor, OwnershipVerifyRequest.signatureScheme
missing examples) are pre-existing and on schemas this PR does not touch.

Behavior confirmed against the dev Striga platform
019fe537-a313-b4db-0000-0f2ac35f082c on 2026-09-04:

  • Two consecutive challenge calls returned identical messageToSign and
    expiresAt.
  • After a refused signature, a new challenge left the account UNVERIFIED; a
    correct signature then moved it to ACTIVE.
  • A quote to a PENDING_OWNERSHIP_VERIFICATION destination was created
    successfully, confirming the status is not a block.
  • A LIVENESS challenge was issued while a signature challenge was outstanding,
    and a later signature request still returned the original message.

Follow-up

The feature still has no prose guide. ownershipType,
PENDING_OWNERSHIP_VERIFICATION and vaspName appear nowhere in the docs
outside the changelog and the generated spec, despite four endpoints and two
verification methods. Worth a snippet covering the declare, challenge, verify
flow, the UTC date window on the signed message, and the fact that vaspName
belongs inside accountInfo (at the top level it is silently dropped and the
wallet is treated as self-custody). Separate PR.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NrRvhfq3vabYreWe8yvFD1

…tatuses

Two claims on the challenge endpoints did not match what the API does, in both
the customer and platform trees:

- "Calling this endpoint again abandons any in-flight challenge". It returns the
  outstanding challenge unchanged instead, with the same messageToSign and
  expiresAt, so reloading a signing page does not invalidate the message the user
  is about to sign.
- "An UNVERIFIED account returns to PENDING_OWNERSHIP_VERIFICATION when a new
  challenge is issued". It stays UNVERIFIED until a retry succeeds.

Both were verified against the dev Striga platform. The endpoint descriptions now
state the actual behavior, and note that requesting LIVENESS starts a liveness
attempt even while a signature challenge is outstanding.

The account status tables listed neither PENDING_OWNERSHIP_VERIFICATION nor
UNVERIFIED, and the ramps table implied that any status other than ACTIVE cannot
transact. Transfers below the regulatory threshold go through while a wallet is
pending, so that table told integrators to build a block Grid does not impose.
Both tables now carry the two statuses and say what they allow.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NrRvhfq3vabYreWe8yvFD1
@mintlify

mintlify Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
Grid 🟢 Ready View Preview Sep 4, 2026, 8:45 PM

@vercel

vercel Bot commented Sep 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Actions Updated
grid-flow-builder Ignored Ignored Preview Sep 4, 2026 9:21pm UTC
grid-wallet-demo Ignored Ignored Preview Sep 4, 2026 9:21pm UTC

Request Review

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

✱ Stainless preview builds for grid

This PR will update the grid SDKs with the following commit messages.

cli

chore(internal): regenerate SDK with no functional changes

go

docs(api): update Challenge method docs for external accounts

kotlin

docs(api): update external account challenge method documentation

openapi

docs(api): update external account ownership challenge endpoint descriptions

php

docs(api): update external accounts challenge method documentation

python

docs(api): update external_accounts verify_ownership challenge documentation

ruby

docs(api): clarify challenge behavior in external_accounts

typescript

docs(api): update challenge method docs in customers/platform external_accounts

Edit this comment to update them. They will appear in their respective SDK's changelogs.

grid-typescript studio · code · diff

Your SDK build had at least one "note" diagnostic, but this did not represent a regression.
generate ✅build ✅lint ❗test ✅

npm install https://pkg.stainless.com/s/grid-typescript/ca78a9ee1b6bc15b0e15a2e3fa30f28cbefda919/dist.tar.gz
grid-openapi studio · code · diff

Your SDK build had at least one "warning" diagnostic, but this did not represent a regression.
generate ⚠️

grid-ruby studio · code · diff

Your SDK build had at least one "note" diagnostic, but this did not represent a regression.
generate ✅build ✅lint ✅test ✅

grid-kotlin studio · code · diff

Your SDK build had at least one "warning" diagnostic, but this did not represent a regression.
generate ⚠️build ✅lint ✅test ❗

grid-go studio · code · diff

Your SDK build had at least one "note" diagnostic, but this did not represent a regression.
generate ✅build ✅lint ❗test ❗

go get github.com/stainless-sdks/grid-go@2c9d3de962caa69bedd3f67d0db3e80522624f63
grid-python studio · code · diff

Your SDK build had at least one "note" diagnostic, but this did not represent a regression.
generate ✅build ✅lint ❗test ❗

pip install https://pkg.stainless.com/s/grid-python/ae940957d6a0d1d39b6a85422fc8def735a84d3f/grid-0.0.1-py3-none-any.whl
grid-php studio · code · diff

Your SDK build had at least one "note" diagnostic, but this did not represent a regression.
generate ✅lint ✅test ✅

grid-cli studio · code · diff

Your SDK build had at least one "warning" diagnostic, but this did not represent a regression.
generate ⚠️build ❗lint ❗test ❗


This comment is auto-generated by GitHub Actions and is automatically kept up to date as you push.
If you push custom code to the preview branch, re-run this workflow to update the comment.
Last updated: 2026-09-04 21:25:10 UTC

Ownership verification is likely to apply outside the EU, so the status notes now
state the rule generally and name the EU as an example, matching how the spec
already phrases region-conditional requirements ("Required in regions that verify
the email address before identity verification (e.g. the EU)"). The earlier
wording made the EU Travel Rule the defining condition.

Also adds the two statuses to the account model page, which carries a third copy
of the external account status list.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NrRvhfq3vabYreWe8yvFD1
The feature shipped with four endpoints, two verification methods, and no prose.
`ownershipType`, `PENDING_OWNERSHIP_VERIFICATION` and `vaspName` appeared nowhere
in the docs outside the changelog and the generated spec.

Adds an Ownership Verification section to the account model page, next to the
external account statuses it produces, following how Strong Customer
Authentication is documented on the quote it attaches to rather than as a page of
its own.

Covers both methods, and the three things that are easy to get wrong: the signed
message is matched character for character and carries a UTC date good for
yesterday, today and tomorrow only; re-requesting a challenge returns the
outstanding one rather than a fresh message; and `vaspName` belongs inside
`accountInfo`, where at the top level it is ignored and a custodied wallet is
treated as self-custody.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NrRvhfq3vabYreWe8yvFD1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant