Skip to content

Rewrite all REST v3 examples: correct signing, pinned Docker, standardized docs#44

Open
bsoares wants to merge 1 commit into
mainfrom
improve/rest-v3-examples
Open

Rewrite all REST v3 examples: correct signing, pinned Docker, standardized docs#44
bsoares wants to merge 1 commit into
mainfrom
improve/rest-v3-examples

Conversation

@bsoares

@bsoares bsoares commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Every REST v3 example (12 languages + 2 official-SDK examples) was rewritten so an integrating developer gets correct, idiomatic, copy-pasteable code. The focus was the request-signing logic, which previously broke as soon as a request carried encoded query params or a JSON body.

The signing fix (root cause)

The prehash is timestamp + method + path + queryString + rawBody. Two mistakes were present in every example and are now fixed everywhere — both validated empirically against the live API:

  1. Query string was signed in its encoded form, and re-serialized independently by the HTTP client. The server rebuilds the prehash from the decoded values. The examples now build the decoded query (for the prehash) and the percent-encoded query (RFC 3986, space %20 never +, for the URL) from the same ordered param structure, so the signed and sent strings can never diverge.
  2. The JSON body was serialized twice (once to sign, once by the HTTP client to send). The examples now serialize the body once and sign & send that exact string (Python uses data=, not json=; axios/requests no longer re-serialize).

Correctness & robustness (all examples)

  • Dynamic price = 50% of the best bid from the public order book. The old hardcoded 10.0 BRL is now rejected by the API price band (HTTP 422), so the examples simply didn't work.
  • Demonstrate the public, unauthenticated order book endpoint.
  • Fail fast with a clear message when credentials are missing.
  • Never print the API key/secret (the old code logged the key).
  • Non-2xx responses print status + body and exit non-zero (the old code swallowed errors and exited 0).
  • Order id from the create step is used for the cancel step.

Dependencies & Docker

  • Dependencies minimized: JS/TS are now zero-dependency (native fetch + node:crypto), Ruby/PHP stdlib-only (Gemfile/composer removed), Go stdlib and modernized. Remaining deps pinned to exact versions.
  • Every example ships a Dockerfile pinned to a full base-image version (no latest/floating tags), multi-stage for compiled languages.

Docs

READMEs standardized in English (flow, credentials, Docker run, and a "how signing works" section covering the two gotchas). Root and rest-v3 READMEs updated; WebSocket v3 now listed.

Verification

All 14 examples were built under Docker and run end-to-end against the live API (/me → order book → create order → list active → cancel) with exit 0. The order is a real LIMIT BUY placed ~50% below market and cancelled by the example itself. Per-language signing test vectors (including the RFC 3986 encoding edge cases) pass for every language.

Note: 9 of the 14 images were rebuilt fresh and live-tested in this pass; the other 5 (the ones that download deps at build time — Python, TypeScript, both SDKs, Dart) were live-tested from images built earlier in the run, because a network TLS-intercepting proxy currently blocks fresh pip/npm/pub downloads inside Docker. Their Dockerfiles are unchanged and proven to build; Python and TypeScript signing were additionally re-verified offline against the current source. A clean-network rebuild of those five is worth a final confirmation before merge.

🤖 Generated with Claude Code

Rewrites every REST v3 sample so an integrating developer gets correct,
idiomatic, copy-pasteable code with a request-signing implementation that
holds for all request shapes (no body, query params, JSON body).

Signing (root cause of the previous breakage):
- The prehash uses the query string DECODED (raw values); the URL sends it
  percent-encoded (RFC 3986, space=%20). Both are built from one ordered
  param structure so the signed and sent strings can never diverge. This was
  validated empirically against the live API — signing the encoded form 401s.
- The JSON body is serialized exactly once; the same string is signed and
  sent on the wire (Python uses data=, not json=; axios/requests no longer
  re-serialize). Signing one formatting and sending another 401s.
- Timestamp in milliseconds; success is any 2xx (order creation returns 201).

Correctness/robustness fixes applied across all examples:
- Dynamic price = 50% of the best bid from the public order book. The old
  hardcoded 10.0 BRL is now rejected by the API price band (HTTP 422).
- Demonstrate the public (unauthenticated) order book endpoint.
- Fail fast with a clear message when credentials are missing.
- Never print the API key/secret.
- Non-2xx responses print status + body and exit non-zero.

Dependencies minimized (stdlib where possible): JS/TS now zero-dependency
(native fetch + node:crypto), Ruby/PHP stdlib-only (Gemfile/composer removed),
Go stdlib and modernized. Remaining deps pinned to exact versions.

Docker: every example ships a Dockerfile pinned to a full base-image version
(no latest/floating tags), multi-stage for compiled languages.

READMEs standardized in English (flow, credentials, Docker run, and how the
signing works, including the two gotchas). Root and rest-v3 READMEs updated;
WebSocket v3 listed.

Verified: all 14 examples build under Docker and complete the full flow
(me -> order book -> create order -> list active -> cancel) against the live
API with exit 0; signing test vectors pass for every language.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@bsoares bsoares requested a review from a team as a code owner July 7, 2026 03:17
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