diff --git a/docs.json b/docs.json index efa888c..4fa08d5 100644 --- a/docs.json +++ b/docs.json @@ -123,6 +123,54 @@ } ] }, + { + "tab": "SDKs", + "groups": [ + { + "group": "Overview", + "pages": [ + "sdks/index" + ] + }, + { + "group": "Quickstart", + "pages": [ + "sdks/quickstart/go", + "sdks/quickstart/python", + "sdks/quickstart/typescript", + "sdks/quickstart/java" + ] + }, + { + "group": "Guides", + "pages": [ + "sdks/authentication", + "sdks/error-handling", + "sdks/pagination", + "sdks/webhooks", + "sdks/sandbox", + "sdks/ai-agents", + "sdks/migration" + ] + }, + { + "group": "Service References", + "pages": [ + "sdks/services/transfers", + "sdks/services/identity", + "sdks/services/orders", + "sdks/services/profiles", + "sdks/services/fiat-transfers", + "sdks/services/deposit-addresses", + "sdks/services/stablecoin-conversion", + "sdks/services/settlement", + "sdks/services/market-data", + "sdks/services/events", + "sdks/services/api-credentials" + ] + } + ] + }, { "tab": "Developer Guide", "groups": [ diff --git a/sdks/ai-agents.mdx b/sdks/ai-agents.mdx new file mode 100644 index 0000000..d8aa528 --- /dev/null +++ b/sdks/ai-agents.mdx @@ -0,0 +1,58 @@ +--- +title: 'AI & Agent Usage' +description: 'Use AI coding assistants with Paxos SDKs for faster, more accurate integrations.' +--- + +Each Paxos SDK ships with `CLAUDE.md` and `AGENTS.md` files that provide structured context for AI coding assistants. These files help LLMs generate correct SDK code by describing available methods, patterns, and common pitfalls. + +## How It Works + +When you point an AI assistant at a Paxos SDK repository, the `CLAUDE.md` file gives it: + +- A summary of all available services and methods +- Correct patterns for authentication, error handling, and pagination +- Common workflows (e.g., "create identity, approve it, fund the profile, make a transfer") +- Warnings about common mistakes (e.g., using floats for monetary amounts) + +## Using Claude with the SDK + +If you're using [Claude Code](https://claude.com/claude-code), the `CLAUDE.md` file is read automatically when you work in the SDK repository. + +Example prompts that produce good results: + +- "Create a crypto withdrawal with idempotency from profile X to address Y" +- "Set up a webhook handler that processes identity approval events" +- "Write an integration test that deposits USD and lists transfers" +- "Implement pagination to export all transfers to a CSV file" + +## LLM-Friendly Documentation + +All SDK methods include natural language docstrings with business context, not just type signatures. This helps LLMs understand *when* to use a method, not just *how*. + +For example, asking an LLM to "implement a crypto withdrawal with idempotency" produces code that correctly uses `CreateCryptoWithdrawal` with an idempotency key — because the docstring explains the business context and the idempotency pattern. + +## AGENTS.md Reference + +Each SDK includes an `AGENTS.md` file with task-specific instructions for common workflows: + +- Setting up a new integration from scratch +- Adding webhook handling to an existing application +- Migrating from direct API calls to the SDK +- Writing integration tests against the Sandbox + +## Best Practices + +- **Use environment variables for credentials** — Never paste `PAXOS_CLIENT_ID` or `PAXOS_CLIENT_SECRET` inline in prompts +- **Test generated code in Sandbox** — Always verify generated code works in [Sandbox](/sdks/sandbox) before deploying to production +- **Use string types for amounts** — LLMs sometimes suggest floating-point types for monetary amounts. Paxos SDKs use string-based decimal types to avoid precision errors +- **Review error handling** — Verify that generated code handles errors appropriately for your use case + +## Documentation Resources + +Paxos provides machine-readable documentation for AI tools: + +- [`/llms.txt`](https://docs.paxos.com/llms.txt) — Structured index of all documentation pages, following the [llmstxt.org](https://llmstxt.org) convention +- [`/llms-full.txt`](https://docs.paxos.com/llms-full.txt) — Complete documentation compiled into a single file for full-context AI prompts +- [OpenAPI specification](https://developer.paxos.com/docs/paxos-v2.openapi.json) — Complete REST API schema for precise implementation details + +> For more about using AI tools with Paxos APIs generally, see the [AI-Assisted Development](/guides/developer/ai-assisted-development) guide. diff --git a/sdks/authentication.mdx b/sdks/authentication.mdx new file mode 100644 index 0000000..bb180f9 --- /dev/null +++ b/sdks/authentication.mdx @@ -0,0 +1,185 @@ +--- +title: 'Authentication' +description: 'How the Paxos SDK handles OAuth2 client credentials automatically, including token caching and refresh.' +--- + +Paxos uses OAuth2 client credentials (machine-to-machine) for authentication. The SDK manages the full token lifecycle automatically — you provide your credentials once when creating the client, and every API call is authenticated transparently. + +## How It Works + +When you make an API call, the SDK: + +1. Checks for a cached access token +2. If no valid token exists, requests one from the Paxos auth server +3. Injects the `Authorization: Bearer ` header into your request +4. Caches the token until it expires (with a 60-second safety buffer) +5. Refreshes the token automatically before expiry + +```mermaid +sequenceDiagram + participant App as Your App + participant SDK as Paxos SDK + participant Auth as Paxos Auth Server + participant API as Paxos API + + App->>SDK: client.Transfers.GetTransfer("id") + SDK->>SDK: Check token cache + SDK->>Auth: POST /oauth2/token (if needed) + Auth-->>SDK: access_token (1h TTL) + SDK->>API: GET /transfer/transfers/id + Note over SDK,API: Authorization: Bearer + API-->>SDK: Transfer JSON + SDK-->>App: Transfer object +``` + +You never need to call the token endpoint directly or manage token expiry. + +## Client Setup + + + +```go Go +client, err := paxos.NewClient( + os.Getenv("PAXOS_CLIENT_ID"), + os.Getenv("PAXOS_CLIENT_SECRET"), + paxos.WithSandbox(), +) +if err != nil { + log.Fatal(err) +} + +// All calls are automatically authenticated +transfer, err := client.Transfers.GetTransfer(ctx, "txn_123") +``` + +```python Python +client = paxos.Client( + client_id=os.environ["PAXOS_CLIENT_ID"], + client_secret=os.environ["PAXOS_CLIENT_SECRET"], + sandbox=True, +) + +# All calls are automatically authenticated +transfer = client.transfers.get_transfer("txn_123") +``` + +```typescript TypeScript +const client = new PaxosClient({ + clientId: process.env.PAXOS_CLIENT_ID!, + clientSecret: process.env.PAXOS_CLIENT_SECRET!, + sandbox: true, +}); + +// All calls are automatically authenticated +const transfer = await client.transfers.getTransfer("txn_123"); +``` + +```java Java +PaxosClient client = PaxosClient.builder() + .clientId(System.getenv("PAXOS_CLIENT_ID")) + .clientSecret(System.getenv("PAXOS_CLIENT_SECRET")) + .sandbox(true) + .build(); + +// All calls are automatically authenticated +Transfer transfer = client.transfers().getTransfer("txn_123"); +``` + + + +## Token Lifecycle + +- Tokens are cached for their full TTL (typically 1 hour) minus a 60-second buffer +- Automatic refresh happens before expiry — no interrupted requests +- Thread-safe: concurrent requests share a single token, and only one refresh runs at a time +- On `401` responses, the SDK invalidates the cache, fetches a new token, and retries once + +## Credential Management + + +Never hardcode credentials in source code. Always use environment variables or a secret manager. + + +**Environment variables** (recommended for local development): + +```bash +export PAXOS_CLIENT_ID="your_client_id" +export PAXOS_CLIENT_SECRET="your_client_secret" +``` + +**Secret managers** (recommended for production): + +Use your infrastructure's secret manager (AWS Secrets Manager, GCP Secret Manager, HashiCorp Vault) to inject credentials at runtime. The SDK accepts credentials as strings, so any secret source works. + +## Multiple Environments + +Use separate clients for Sandbox and Production. Each environment has its own credentials and base URL. + + + +```go Go +sandboxClient, _ := paxos.NewClient( + os.Getenv("PAXOS_SANDBOX_CLIENT_ID"), + os.Getenv("PAXOS_SANDBOX_CLIENT_SECRET"), + paxos.WithSandbox(), +) + +prodClient, _ := paxos.NewClient( + os.Getenv("PAXOS_PROD_CLIENT_ID"), + os.Getenv("PAXOS_PROD_CLIENT_SECRET"), + // Production is the default +) +``` + +```python Python +sandbox_client = paxos.Client( + client_id=os.environ["PAXOS_SANDBOX_CLIENT_ID"], + client_secret=os.environ["PAXOS_SANDBOX_CLIENT_SECRET"], + sandbox=True, +) + +prod_client = paxos.Client( + client_id=os.environ["PAXOS_PROD_CLIENT_ID"], + client_secret=os.environ["PAXOS_PROD_CLIENT_SECRET"], +) +``` + +```typescript TypeScript +const sandboxClient = new PaxosClient({ + clientId: process.env.PAXOS_SANDBOX_CLIENT_ID!, + clientSecret: process.env.PAXOS_SANDBOX_CLIENT_SECRET!, + sandbox: true, +}); + +const prodClient = new PaxosClient({ + clientId: process.env.PAXOS_PROD_CLIENT_ID!, + clientSecret: process.env.PAXOS_PROD_CLIENT_SECRET!, +}); +``` + +```java Java +PaxosClient sandboxClient = PaxosClient.builder() + .clientId(System.getenv("PAXOS_SANDBOX_CLIENT_ID")) + .clientSecret(System.getenv("PAXOS_SANDBOX_CLIENT_SECRET")) + .sandbox(true) + .build(); + +PaxosClient prodClient = PaxosClient.builder() + .clientId(System.getenv("PAXOS_PROD_CLIENT_ID")) + .clientSecret(System.getenv("PAXOS_PROD_CLIENT_SECRET")) + .build(); +``` + + + +## Getting API Credentials + +➊ Sign in to the [Paxos Dashboard](https://dashboard.paxos.com/) (or [Sandbox Dashboard](https://dashboard.sandbox.paxos.com/)) + +➋ Navigate to **Developer** > **API Credentials** + +➌ Create a new credential pair and select the required [scopes](/guides/developer/credentials) + +➍ Save the **Client ID** and **Client Secret** — the secret is only shown once + +> Scopes for each endpoint are listed in the **Authorizations** section of the [API Reference](/api-reference). diff --git a/sdks/error-handling.mdx b/sdks/error-handling.mdx new file mode 100644 index 0000000..55da135 --- /dev/null +++ b/sdks/error-handling.mdx @@ -0,0 +1,153 @@ +--- +title: 'Error Handling' +description: 'Handle API errors with typed exceptions, RFC 7807 Problem Details, and request IDs for support.' +--- + +Paxos API errors follow [RFC 7807 Problem Details](https://tools.ietf.org/html/rfc7807). The SDK parses these into typed errors so you can handle specific failure cases without inspecting raw HTTP status codes. + +## Error Format + +All Paxos API errors return a JSON body with these fields: + +```json +{ + "type": "https://docs.paxos.com/problems/not-found", + "title": "Not Found", + "status": 404, + "detail": "transfer with id 'abc' not found", + "instance": "/transfer/transfers/abc", + "request_id": "req_01HX..." +} +``` + +| Field | Description | +|---|---| +| `type` | URI identifying the error type | +| `title` | Short human-readable summary | +| `status` | HTTP status code | +| `detail` | Longer explanation of what went wrong | +| `instance` | The request path that caused the error | +| `request_id` | Unique ID for this request — include this in support tickets | + +## Typed Errors + +The SDK maps HTTP status codes to typed errors: + +| HTTP Status | Error Type | Helper | +|---|---|---| +| 400 | `ValidationError` | `IsValidationError()` | +| 401 | `UnauthorizedError` | `IsUnauthorized()` | +| 403 | `ForbiddenError` | `IsForbidden()` | +| 404 | `NotFoundError` | `IsNotFound()` | +| 409 | `ConflictError` | `IsConflict()` | +| 422 | `UnprocessableError` | `IsUnprocessable()` | +| 429 | `RateLimitError` | `IsRateLimited()` | +| 5xx | `ServerError` | `IsServerError()` | + +## Handling Errors + + + +```go Go +transfer, err := client.Transfers.GetTransfer(ctx, "txn_123") +if err != nil { + if paxos.IsNotFound(err) { + fmt.Println("Transfer not found") + return + } + + var apiErr *paxos.APIError + if errors.As(err, &apiErr) { + fmt.Printf("API error: %s (request_id: %s)\n", apiErr.Detail, apiErr.RequestID) + } + + return err +} +``` + +```python Python +try: + transfer = client.transfers.get_transfer("txn_123") +except paxos.NotFoundError as e: + print("Transfer not found") +except paxos.APIError as e: + print(f"API error: {e.detail} (request_id: {e.request_id})") +``` + +```typescript TypeScript +try { + const transfer = await client.transfers.getTransfer("txn_123"); +} catch (e) { + if (e instanceof PaxosNotFoundError) { + console.log("Transfer not found"); + } else if (e instanceof PaxosAPIError) { + console.log(`API error: ${e.detail} (request_id: ${e.requestId})`); + } +} +``` + +```java Java +try { + Transfer transfer = client.transfers().getTransfer("txn_123"); +} catch (NotFoundException e) { + System.out.println("Transfer not found"); +} catch (PaxosApiException e) { + System.out.printf("API error: %s (request_id: %s)%n", e.getDetail(), e.getRequestId()); +} +``` + + + +## Common Errors and Fixes + +| Error | Status | Common Cause | Fix | +|---|---|---|---| +| `NotFoundError` | 404 | Wrong ID or resource doesn't exist | Verify the ID; use List endpoints to discover valid IDs | +| `UnauthorizedError` | 401 | Bad credentials | Verify `client_id` and `client_secret`; check you are using the correct environment | +| `ForbiddenError` | 403 | Missing OAuth2 scope | Add the required scope to your API credentials in the [Dashboard](https://dashboard.paxos.com/) | +| `ValidationError` | 400 | Invalid request body | Check required fields and field types in the [API Reference](/api-reference) | +| `RateLimitError` | 429 | Too many requests | Reduce concurrency; the SDK retries automatically with backoff | +| `ServerError` | 5xx | Paxos-side issue | The SDK retries automatically; if the issue persists, contact [Support](https://support.paxos.com) | + +## Extracting Request ID + +Always include the `request_id` when contacting support. Every error carries it: + + + +```go Go +var apiErr *paxos.APIError +if errors.As(err, &apiErr) { + log.Printf("Include this in your support ticket: %s", apiErr.RequestID) +} +``` + +```python Python +except paxos.APIError as e: + print(f"Include this in your support ticket: {e.request_id}") +``` + +```typescript TypeScript +if (e instanceof PaxosAPIError) { + console.log(`Include this in your support ticket: ${e.requestId}`); +} +``` + +```java Java +catch (PaxosApiException e) { + System.out.println("Include this in your support ticket: " + e.getRequestId()); +} +``` + + + +## Retry Behavior + +The SDK automatically retries requests that fail with `429` (rate limit) or `5xx` (server error): + +- Up to 3 retries with exponential backoff +- Initial delay of 500ms, doubling each attempt (with jitter) +- Maximum backoff of 30 seconds +- `Retry-After` headers are respected when present + +Retries are transparent — you only see the final result or error. Client errors (`400`, `403`, `404`) are never retried since they require a code change to fix. diff --git a/sdks/index.mdx b/sdks/index.mdx new file mode 100644 index 0000000..1904afd --- /dev/null +++ b/sdks/index.mdx @@ -0,0 +1,68 @@ +--- +title: 'SDKs' +description: 'Idiomatic client libraries for Go, Python, TypeScript, and Java that handle authentication, pagination, retries, and error handling automatically.' +--- + +Paxos SDKs provide a simple, idiomatic interface to all Paxos APIs in Go, Python, TypeScript, and Java. Each SDK handles OAuth2 authentication, automatic retries with backoff, cursor-based pagination, and typed error handling so you can focus on your integration logic. + +## Choose Your Language + + + + Go 1.21+ with functional options. The reference SDK implementation. + + + Python 3.9+ with async support and type hints. + + + Node 18+ and browser-compatible with full TypeScript types. + + + Java 17+ with builder patterns and CompletableFuture support. + + + +## Feature Comparison + +Every SDK provides the same core capabilities: + +| Feature | Go | Python | TypeScript | Java | +|---|---|---|---|---| +| Auto-authentication (OAuth2) | ✅ | ✅ | ✅ | ✅ | +| Auto-pagination (iterators) | ✅ | ✅ | ✅ | ✅ | +| Typed errors (RFC 7807) | ✅ | ✅ | ✅ | ✅ | +| Retry with exponential backoff | ✅ | ✅ | ✅ | ✅ | +| Sandbox mode | ✅ | ✅ | ✅ | ✅ | +| Decimal precision for amounts | ✅ | ✅ | ✅ | ✅ | +| AI tooling (CLAUDE.md) | ✅ | ✅ | ✅ | ✅ | + +## API Coverage + +The SDKs cover all publicly documented Paxos API services: + +**Identity & Accounts** — [Identity](/api-reference/endpoints/identity/overview), [Profiles](/api-reference/endpoints/profiles/overview), [Accounts](/api-reference/endpoints/accounts/overview) + +**Transfers & Funding** — [Transfers](/api-reference/endpoints/transfers/overview), [Fiat Transfers](/api-reference/endpoints/fiat-transfers/overview), [Deposit Addresses](/api-reference/endpoints/deposit-addresses/list-deposit-addresses), [Crypto Withdrawals](/api-reference/endpoints/crypto-withdrawals/create-crypto-withdrawal) + +**Trading** — [Orders](/api-reference/endpoints/orders/overview), [Market Data](/api-reference/endpoints/market-data/overview), [Pricing](/api-reference/endpoints/pricing/overview), [Quotes](/api-reference/endpoints/quotes/overview) + +**Stablecoin** — [Stablecoin Conversion](/api-reference/endpoints/stablecoin-conversion/overview), [Orchestrations](/api-reference/endpoints/orchestration/overview) + +**Settlement** — [Settlement](/api-reference/endpoints/settlement/overview) + +**Events** — [Events](/api-reference/endpoints/events/overview) + +## GitHub Repositories + +| Language | Repository | +|---|---| +| Go | [github.com/paxosglobal/paxos-go](https://github.com/paxosglobal/paxos-go) | +| Python | [github.com/paxosglobal/paxos-python](https://github.com/paxosglobal/paxos-python) | +| TypeScript | [github.com/paxosglobal/paxos-js](https://github.com/paxosglobal/paxos-js) | +| Java | [github.com/paxosglobal/paxos-java](https://github.com/paxosglobal/paxos-java) | + +## Next Steps + +- Follow a [Quickstart](/sdks/quickstart/go) to make your first API call +- Learn how the SDK handles [Authentication](/sdks/authentication) automatically +- Set up the [Sandbox](/sdks/sandbox) for testing diff --git a/sdks/migration.mdx b/sdks/migration.mdx new file mode 100644 index 0000000..f700a10 --- /dev/null +++ b/sdks/migration.mdx @@ -0,0 +1,133 @@ +--- +title: 'Migration Guide' +description: 'Migrate from direct API calls to the Paxos SDK for automatic authentication, retries, pagination, and typed errors.' +--- + +If you already integrate with Paxos APIs using raw HTTP calls, you can migrate to the SDK incrementally. The SDK handles authentication, retries, pagination, and error parsing automatically — eliminating boilerplate you currently maintain. + +## Why Migrate? + +| Concern | Direct API Calls | With the SDK | +|---|---|---| +| Authentication | Manual token management, refresh logic, thread safety | Automatic — handled by the SDK | +| Retries | Manual retry loops with backoff and jitter | Automatic — 429 and 5xx retried with exponential backoff | +| Pagination | Manual cursor tracking and page fetching | Automatic — iterators handle page boundaries | +| Error handling | Parse JSON, check status codes, extract request ID | Typed errors with `IsNotFound()`, `IsRateLimited()`, etc. | +| Idempotency | Generate and manage idempotency keys manually | Automatic — SDK generates keys for retried mutating requests | + +## Before and After + +### Authentication + +**Before** — Manual token acquisition and injection: + +```bash +# Get a token +TOKEN=$(curl -s -X POST https://oauth.sandbox.paxos.com/oauth2/token \ + --data-urlencode "grant_type=client_credentials" \ + --data-urlencode "client_id=$PAXOS_CLIENT_ID" \ + --data-urlencode "client_secret=$PAXOS_CLIENT_SECRET" \ + | jq -r '.access_token') + +# Use the token +curl https://api.sandbox.paxos.com/v2/transfer/transfers/txn_123 \ + -H "Authorization: Bearer $TOKEN" +``` + +**After** — The SDK handles it: + + + +```go Go +client, _ := paxos.NewClient(os.Getenv("PAXOS_CLIENT_ID"), os.Getenv("PAXOS_CLIENT_SECRET"), paxos.WithSandbox()) +transfer, err := client.Transfers.GetTransfer(ctx, "txn_123") +``` + +```python Python +client = paxos.Client(client_id=os.environ["PAXOS_CLIENT_ID"], client_secret=os.environ["PAXOS_CLIENT_SECRET"], sandbox=True) +transfer = client.transfers.get_transfer("txn_123") +``` + +```typescript TypeScript +const client = new PaxosClient({ clientId: process.env.PAXOS_CLIENT_ID!, clientSecret: process.env.PAXOS_CLIENT_SECRET!, sandbox: true }); +const transfer = await client.transfers.getTransfer("txn_123"); +``` + +```java Java +PaxosClient client = PaxosClient.builder().clientId(System.getenv("PAXOS_CLIENT_ID")).clientSecret(System.getenv("PAXOS_CLIENT_SECRET")).sandbox(true).build(); +Transfer transfer = client.transfers().getTransfer("txn_123"); +``` + + + +### Pagination + +**Before** — Manual cursor loop: + +```go +var cursor string +for { + resp, _ := http.Get(fmt.Sprintf("https://api.sandbox.paxos.com/v2/transfer/transfers?limit=50&page_cursor=%s", cursor)) + var result ListResponse + json.NewDecoder(resp.Body).Decode(&result) + + for _, t := range result.Items { + process(t) + } + + if result.NextPageCursor == "" { + break + } + cursor = result.NextPageCursor +} +``` + +**After** — Auto-pagination iterator: + +```go +for iter := client.Transfers.ListTransfers(ctx, &paxos.ListTransfersRequest{Limit: 50}); iter.Next(); { + process(iter.Current()) +} +``` + +### Error Handling + +**Before** — Raw status code checks: + +```go +resp, _ := http.Get(url) +if resp.StatusCode == 429 { + time.Sleep(time.Second * 5) + // retry... +} else if resp.StatusCode == 404 { + // not found... +} +``` + +**After** — Typed error checking: + +```go +transfer, err := client.Transfers.GetTransfer(ctx, "txn_123") +if paxos.IsNotFound(err) { + // handle not found +} +// 429 and 5xx are retried automatically +``` + +## Migration Checklist + +Use this checklist to migrate incrementally: + +- [ ] Install the SDK ([Go](/sdks/quickstart/go), [Python](/sdks/quickstart/python), [TypeScript](/sdks/quickstart/typescript), [Java](/sdks/quickstart/java)) +- [ ] Replace token management code with SDK client construction +- [ ] Replace HTTP call sites with SDK service methods one at a time +- [ ] Replace manual error handling with typed SDK errors +- [ ] Replace pagination loops with SDK iterators +- [ ] Test each migrated call against [Sandbox](/sdks/sandbox) +- [ ] Deploy to production + +## Incremental Migration + +You don't have to migrate everything at once. The SDK client can coexist with your existing HTTP code. Start with the endpoints you call most frequently, then migrate the rest over time. + +> The SDK uses the same underlying REST API — there are no behavioral differences between SDK calls and direct API calls. diff --git a/sdks/pagination.mdx b/sdks/pagination.mdx new file mode 100644 index 0000000..8d456c5 --- /dev/null +++ b/sdks/pagination.mdx @@ -0,0 +1,203 @@ +--- +title: 'Pagination' +description: 'Iterate through large result sets using auto-pagination iterators or manual cursor control.' +--- + +Paxos APIs use cursor-based pagination. The SDK provides auto-pagination iterators that handle page fetching automatically, so you can iterate through results without managing cursors. + +## How Paxos Pagination Works + +- List endpoints return a page of results plus a `next_page_cursor` +- Pass the cursor to the next request to fetch the following page +- When `next_page_cursor` is absent, you've reached the last page +- The `limit` parameter controls the number of items per page + +## Auto-Pagination (Recommended) + +The SDK's iterators fetch pages transparently. Iterate through results as if they were a single collection: + + + +```go Go +iter := client.Transfers.ListTransfers(ctx, &paxos.ListTransfersRequest{ + ProfileID: "profile_123", + Limit: 50, +}) + +for iter.Next() { + transfer := iter.Current() + fmt.Printf("Transfer: %s — %s %s\n", transfer.ID, transfer.Amount, transfer.Asset) +} +if err := iter.Err(); err != nil { + log.Fatal(err) +} +``` + +```python Python +for transfer in client.transfers.list_transfers(profile_id="profile_123", limit=50): + print(f"Transfer: {transfer.id} — {transfer.amount} {transfer.asset}") +``` + +```typescript TypeScript +for await (const transfer of client.transfers.listTransfers({ + profileId: "profile_123", + limit: 50, +})) { + console.log(`Transfer: ${transfer.id} — ${transfer.amount} ${transfer.asset}`); +} +``` + +```java Java +for (Transfer transfer : client.transfers().listTransfers( + ListTransfersRequest.builder() + .profileId("profile_123") + .limit(50) + .build())) { + System.out.printf("Transfer: %s — %s %s%n", + transfer.getId(), transfer.getAmount(), transfer.getAsset()); +} +``` + + + +The iterator fetches pages of 50 items at a time behind the scenes. When one page is exhausted, it automatically fetches the next one. + +## Manual Pagination + +If you need direct control over page cursors (for example, to store a cursor and resume later), use the page-level methods: + + + +```go Go +var cursor string + +for { + resp, err := client.Transfers.ListTransfersPage(ctx, &paxos.ListTransfersRequest{ + ProfileID: "profile_123", + Limit: 50, + PageCursor: cursor, + }) + if err != nil { + log.Fatal(err) + } + + for _, transfer := range resp.Items { + fmt.Printf("Transfer: %s\n", transfer.ID) + } + + if resp.NextPageCursor == "" { + break + } + cursor = resp.NextPageCursor +} +``` + +```python Python +cursor = None + +while True: + page = client.transfers.list_transfers_page( + profile_id="profile_123", + limit=50, + page_cursor=cursor, + ) + + for transfer in page.items: + print(f"Transfer: {transfer.id}") + + if not page.next_page_cursor: + break + cursor = page.next_page_cursor +``` + +```typescript TypeScript +let cursor: string | undefined; + +do { + const page = await client.transfers.listTransfersPage({ + profileId: "profile_123", + limit: 50, + pageCursor: cursor, + }); + + for (const transfer of page.items) { + console.log(`Transfer: ${transfer.id}`); + } + + cursor = page.nextPageCursor; +} while (cursor); +``` + +```java Java +String cursor = null; + +do { + ListTransfersResponse page = client.transfers().listTransfersPage( + ListTransfersRequest.builder() + .profileId("profile_123") + .limit(50) + .pageCursor(cursor) + .build()); + + for (Transfer transfer : page.getItems()) { + System.out.printf("Transfer: %s%n", transfer.getId()); + } + + cursor = page.getNextPageCursor(); +} while (cursor != null); +``` + + + +## Performance Tips + +- **Set an appropriate page size** — Larger pages mean fewer network round-trips but more memory per page. Start with 50–100. +- **Break early** — If you're searching for a specific item, stop iterating once you find it. +- **Process pages in parallel** — If ordering doesn't matter, fetch the next page while processing the current one. + +## Error Handling During Pagination + +If a network error or API error occurs mid-iteration, the iterator surfaces it: + + + +```go Go +for iter.Next() { + // process items +} +if err := iter.Err(); err != nil { + // handle error — you can resume from the last successfully processed item + log.Printf("pagination failed: %v", err) +} +``` + +```python Python +try: + for transfer in client.transfers.list_transfers(profile_id="profile_123"): + process(transfer) +except paxos.APIError as e: + print(f"Pagination failed: {e.detail}") +``` + +```typescript TypeScript +try { + for await (const transfer of client.transfers.listTransfers({ profileId: "profile_123" })) { + process(transfer); + } +} catch (e) { + console.error("Pagination failed:", e); +} +``` + +```java Java +try { + for (Transfer transfer : client.transfers().listTransfers( + ListTransfersRequest.builder().profileId("profile_123").build())) { + process(transfer); + } +} catch (PaxosApiException e) { + System.err.println("Pagination failed: " + e.getDetail()); +} +``` + + diff --git a/sdks/quickstart/go.mdx b/sdks/quickstart/go.mdx new file mode 100644 index 0000000..448ea47 --- /dev/null +++ b/sdks/quickstart/go.mdx @@ -0,0 +1,82 @@ +--- +title: 'Go Quickstart' +description: 'Install the Paxos Go SDK and make your first API call in under 5 minutes.' +--- + + + +### Install the SDK + +Requires Go 1.21 or later. + +```bash +go get github.com/paxosglobal/paxos-go +``` + +### Set Up Credentials + +Create API credentials in the [Paxos Dashboard](https://dashboard.sandbox.paxos.com/) and export them as environment variables. + +```bash +export PAXOS_CLIENT_ID="your_client_id" +export PAXOS_CLIENT_SECRET="your_client_secret" +``` + +> If you don't have a Sandbox account, [sign up here](https://dashboard.sandbox.paxos.com/). + +### Make Your First API Call + +Create a file called `main.go` with the following code. This example creates a client, lists your profiles, and prints the result. + +```go +package main + +import ( + "context" + "fmt" + "log" + "os" + + "github.com/paxosglobal/paxos-go" +) + +func main() { + client, err := paxos.NewClient( + os.Getenv("PAXOS_CLIENT_ID"), + os.Getenv("PAXOS_CLIENT_SECRET"), + paxos.WithSandbox(), + ) + if err != nil { + log.Fatal(err) + } + + ctx := context.Background() + + // List profiles + iter := client.Profiles.ListProfiles(ctx, &paxos.ListProfilesRequest{ + Limit: 10, + }) + for iter.Next() { + profile := iter.Current() + fmt.Printf("Profile: %s (%s)\n", profile.ID, profile.Nickname) + } + if err := iter.Err(); err != nil { + log.Fatal(err) + } +} +``` + +Run the program: + +```bash +go run main.go +``` + + + +## Next Steps + +- Learn how the SDK manages [Authentication](/sdks/authentication) automatically +- Explore [Error Handling](/sdks/error-handling) patterns +- Set up the [Sandbox](/sdks/sandbox) environment for testing +- Browse the [Transfers](/sdks/services/transfers) service reference diff --git a/sdks/quickstart/java.mdx b/sdks/quickstart/java.mdx new file mode 100644 index 0000000..5e88d56 --- /dev/null +++ b/sdks/quickstart/java.mdx @@ -0,0 +1,70 @@ +--- +title: 'Java Quickstart' +description: 'Install the Paxos Java SDK and make your first API call in under 5 minutes.' +--- + + + +### Install the SDK + +Requires Java 17 or later. + +**Maven**: +```xml + + com.paxos + paxos-sdk + 1.0.0 + +``` + +**Gradle**: +```groovy +implementation 'com.paxos:paxos-sdk:1.0.0' +``` + +### Set Up Credentials + +Create API credentials in the [Paxos Dashboard](https://dashboard.sandbox.paxos.com/) and export them as environment variables. + +```bash +export PAXOS_CLIENT_ID="your_client_id" +export PAXOS_CLIENT_SECRET="your_client_secret" +``` + +> If you don't have a Sandbox account, [sign up here](https://dashboard.sandbox.paxos.com/). + +### Make Your First API Call + +Create a file with the following code. This example creates a client, lists your profiles, and prints the result. + +```java +import com.paxos.PaxosClient; +import com.paxos.models.Profile; +import com.paxos.models.ListProfilesRequest; + +public class Main { + public static void main(String[] args) { + PaxosClient client = PaxosClient.builder() + .clientId(System.getenv("PAXOS_CLIENT_ID")) + .clientSecret(System.getenv("PAXOS_CLIENT_SECRET")) + .sandbox(true) + .build(); + + // List profiles + for (Profile profile : client.profiles().listProfiles( + ListProfilesRequest.builder().limit(10).build())) { + System.out.printf("Profile: %s (%s)%n", profile.getId(), profile.getNickname()); + } + } +} +``` + + + +## Next Steps + +- Learn how the SDK manages [Authentication](/sdks/authentication) automatically +- Explore [Error Handling](/sdks/error-handling) patterns +- Set up the [Sandbox](/sdks/sandbox) environment for testing +- Browse the [Transfers](/sdks/services/transfers) service reference diff --git a/sdks/quickstart/python.mdx b/sdks/quickstart/python.mdx new file mode 100644 index 0000000..d739045 --- /dev/null +++ b/sdks/quickstart/python.mdx @@ -0,0 +1,59 @@ +--- +title: 'Python Quickstart' +description: 'Install the Paxos Python SDK and make your first API call in under 5 minutes.' +--- + + + +### Install the SDK + +Requires Python 3.9 or later. + +```bash +pip install paxos-sdk +``` + +### Set Up Credentials + +Create API credentials in the [Paxos Dashboard](https://dashboard.sandbox.paxos.com/) and export them as environment variables. + +```bash +export PAXOS_CLIENT_ID="your_client_id" +export PAXOS_CLIENT_SECRET="your_client_secret" +``` + +> If you don't have a Sandbox account, [sign up here](https://dashboard.sandbox.paxos.com/). + +### Make Your First API Call + +Create a file called `main.py` with the following code. This example creates a client, lists your profiles, and prints the result. + +```python +import os +import paxos + +client = paxos.Client( + client_id=os.environ["PAXOS_CLIENT_ID"], + client_secret=os.environ["PAXOS_CLIENT_SECRET"], + sandbox=True, +) + +# List profiles +for profile in client.profiles.list_profiles(limit=10): + print(f"Profile: {profile.id} ({profile.nickname})") +``` + +Run the program: + +```bash +python main.py +``` + + + +## Next Steps + +- Learn how the SDK manages [Authentication](/sdks/authentication) automatically +- Explore [Error Handling](/sdks/error-handling) patterns +- Set up the [Sandbox](/sdks/sandbox) environment for testing +- Browse the [Transfers](/sdks/services/transfers) service reference diff --git a/sdks/quickstart/typescript.mdx b/sdks/quickstart/typescript.mdx new file mode 100644 index 0000000..c965bd4 --- /dev/null +++ b/sdks/quickstart/typescript.mdx @@ -0,0 +1,63 @@ +--- +title: 'TypeScript Quickstart' +description: 'Install the Paxos TypeScript SDK and make your first API call in under 5 minutes.' +--- + + + +### Install the SDK + +Requires Node.js 18 or later. + +```bash +npm install @paxos/sdk +``` + +### Set Up Credentials + +Create API credentials in the [Paxos Dashboard](https://dashboard.sandbox.paxos.com/) and export them as environment variables. + +```bash +export PAXOS_CLIENT_ID="your_client_id" +export PAXOS_CLIENT_SECRET="your_client_secret" +``` + +> If you don't have a Sandbox account, [sign up here](https://dashboard.sandbox.paxos.com/). + +### Make Your First API Call + +Create a file called `index.ts` with the following code. This example creates a client, lists your profiles, and prints the result. + +```typescript +import { PaxosClient } from "@paxos/sdk"; + +const client = new PaxosClient({ + clientId: process.env.PAXOS_CLIENT_ID!, + clientSecret: process.env.PAXOS_CLIENT_SECRET!, + sandbox: true, +}); + +async function main() { + // List profiles + for await (const profile of client.profiles.listProfiles({ limit: 10 })) { + console.log(`Profile: ${profile.id} (${profile.nickname})`); + } +} + +main().catch(console.error); +``` + +Run the program: + +```bash +npx tsx index.ts +``` + + + +## Next Steps + +- Learn how the SDK manages [Authentication](/sdks/authentication) automatically +- Explore [Error Handling](/sdks/error-handling) patterns +- Set up the [Sandbox](/sdks/sandbox) environment for testing +- Browse the [Transfers](/sdks/services/transfers) service reference diff --git a/sdks/sandbox.mdx b/sdks/sandbox.mdx new file mode 100644 index 0000000..629ed4f --- /dev/null +++ b/sdks/sandbox.mdx @@ -0,0 +1,160 @@ +--- +title: 'Sandbox' +description: 'Test your integration in the Paxos Sandbox environment with simulated deposits, identity approvals, and test data.' +--- + +The Paxos Sandbox is a separate environment for testing your integration without real money or real identity verification. It mirrors the production API at `api.sandbox.paxos.com` with separate credentials and isolated test data. + +## Enabling Sandbox Mode + +Pass the sandbox option when creating your client: + + + +```go Go +client, err := paxos.NewClient( + os.Getenv("PAXOS_CLIENT_ID"), + os.Getenv("PAXOS_CLIENT_SECRET"), + paxos.WithSandbox(), +) +``` + +```python Python +client = paxos.Client( + client_id=os.environ["PAXOS_CLIENT_ID"], + client_secret=os.environ["PAXOS_CLIENT_SECRET"], + sandbox=True, +) +``` + +```typescript TypeScript +const client = new PaxosClient({ + clientId: process.env.PAXOS_CLIENT_ID!, + clientSecret: process.env.PAXOS_CLIENT_SECRET!, + sandbox: true, +}); +``` + +```java Java +PaxosClient client = PaxosClient.builder() + .clientId(System.getenv("PAXOS_CLIENT_ID")) + .clientSecret(System.getenv("PAXOS_CLIENT_SECRET")) + .sandbox(true) + .build(); +``` + + + +> Sandbox credentials are different from production credentials. Create them in the [Sandbox Dashboard](https://dashboard.sandbox.paxos.com/). + +## Simulating Deposits + +Use `CreateSandboxDeposit` to add test funds to a profile: + + + +```go Go +deposit, err := client.Sandbox.CreateSandboxDeposit(ctx, &paxos.CreateSandboxDepositRequest{ + ProfileID: "profile_123", + Asset: "USD", + Amount: "10000.00", +}) +if err != nil { + log.Fatal(err) +} +fmt.Printf("Deposited %s %s\n", deposit.Amount, deposit.Asset) +``` + +```python Python +deposit = client.sandbox.create_sandbox_deposit( + profile_id="profile_123", + asset="USD", + amount="10000.00", +) +print(f"Deposited {deposit.amount} {deposit.asset}") +``` + +```typescript TypeScript +const deposit = await client.sandbox.createSandboxDeposit({ + profileId: "profile_123", + asset: "USD", + amount: "10000.00", +}); +console.log(`Deposited ${deposit.amount} ${deposit.asset}`); +``` + +```java Java +SandboxDeposit deposit = client.sandbox().createSandboxDeposit( + CreateSandboxDepositRequest.builder() + .profileId("profile_123") + .asset("USD") + .amount("10000.00") + .build()); +System.out.printf("Deposited %s %s%n", deposit.getAmount(), deposit.getAsset()); +``` + + + +## Setting Identity Status + +Bypass the identity verification process in Sandbox by setting the status directly: + + + +```go Go +err := client.Sandbox.SetIdentityStatus(ctx, &paxos.SetIdentityStatusRequest{ + IdentityID: "identity_123", + IDVerificationStatus: "APPROVED", + SanctionsVerificationStatus: "APPROVED", +}) +``` + +```python Python +client.sandbox.set_identity_status( + identity_id="identity_123", + id_verification_status="APPROVED", + sanctions_verification_status="APPROVED", +) +``` + +```typescript TypeScript +await client.sandbox.setIdentityStatus({ + identityId: "identity_123", + idVerificationStatus: "APPROVED", + sanctionsVerificationStatus: "APPROVED", +}); +``` + +```java Java +client.sandbox().setIdentityStatus( + SetIdentityStatusRequest.builder() + .identityId("identity_123") + .idVerificationStatus("APPROVED") + .sanctionsVerificationStatus("APPROVED") + .build()); +``` + + + +## Test Workflow Example + +A typical Sandbox test scenario: + +➊ Create a profile + +➋ Create an identity and approve it with `SetIdentityStatus` + +➌ Fund the profile with `CreateSandboxDeposit` + +➍ Execute transfers, orders, or other operations + +➎ Verify results using the List and Get endpoints + +## Sandbox Limitations + +- **No real blockchain transactions** — Crypto withdrawals don't execute on a live network (testnets are available for some chains) +- **Simulated settlements** — Settlement operations complete immediately +- **More permissive rate limits** — Sandbox has higher rate limits than production +- **Separate data** — Sandbox data is completely isolated from production + +> For testnet details, withdrawal limits, and fiat transfer testing, see the [Sandbox reference](/guides/developer/sandbox). diff --git a/sdks/services/api-credentials.mdx b/sdks/services/api-credentials.mdx new file mode 100644 index 0000000..f463c93 --- /dev/null +++ b/sdks/services/api-credentials.mdx @@ -0,0 +1,75 @@ +--- +title: 'API Credentials' +description: 'SDK reference for the API Credentials service — list and delete API credentials programmatically.' +--- + +The API Credentials service lets you manage your OAuth2 API credentials programmatically. + +**Client accessor**: `client.APICredentials` + +## Available Methods + +| Method | HTTP Equivalent | Description | +|---|---|---| +| `ListAPICredentials` | `GET /credentials/api-credentials` | List all API credentials | +| `DeleteAPICredentials` | `DELETE /credentials/api-credentials/{id}` | Delete an API credential | + +## ListAPICredentials + + + +```go Go +creds, err := client.APICredentials.ListAPICredentials(ctx) +if err != nil { + log.Fatal(err) +} +for _, c := range creds { + fmt.Printf("Credential: %s (created: %s)\n", c.ID, c.CreatedAt) +} +``` + +```python Python +creds = client.api_credentials.list_api_credentials() +for c in creds: + print(f"Credential: {c.id} (created: {c.created_at})") +``` + +```typescript TypeScript +const creds = await client.apiCredentials.listApiCredentials(); +for (const c of creds) { + console.log(`Credential: ${c.id} (created: ${c.createdAt})`); +} +``` + +```java Java +List creds = client.apiCredentials().listApiCredentials(); +for (ApiCredential c : creds) { + System.out.printf("Credential: %s (created: %s)%n", c.getId(), c.getCreatedAt()); +} +``` + + + +## DeleteAPICredentials + + + +```go Go +err := client.APICredentials.DeleteAPICredentials(ctx, "credential_123") +``` + +```python Python +client.api_credentials.delete_api_credentials("credential_123") +``` + +```typescript TypeScript +await client.apiCredentials.deleteApiCredentials("credential_123"); +``` + +```java Java +client.apiCredentials().deleteApiCredentials("credential_123"); +``` + + + +> For the full REST API documentation, see the [API Credentials API Reference](/api-reference/endpoints/api-credentials/overview). diff --git a/sdks/services/deposit-addresses.mdx b/sdks/services/deposit-addresses.mdx new file mode 100644 index 0000000..5c37714 --- /dev/null +++ b/sdks/services/deposit-addresses.mdx @@ -0,0 +1,59 @@ +--- +title: 'Deposit Addresses' +description: 'SDK reference for the Deposit Addresses service — create and list crypto deposit addresses.' +--- + +The Deposit Addresses service lets you generate and list blockchain addresses for receiving crypto deposits. + +**Client accessor**: `client.DepositAddresses` + +## Available Methods + +| Method | HTTP Equivalent | Description | +|---|---|---| +| `ListDepositAddresses` | `GET /transfer/deposit-addresses` | List deposit addresses | +| `CreateDepositAddress` | `POST /transfer/deposit-addresses` | Create a new deposit address | + +## CreateDepositAddress + + + +```go Go +addr, err := client.DepositAddresses.CreateDepositAddress(ctx, &paxos.CreateDepositAddressRequest{ + ProfileID: "profile_123", + CryptoNetwork: "ETHEREUM", +}) +if err != nil { + log.Fatal(err) +} +fmt.Printf("Deposit address: %s (%s)\n", addr.Address, addr.CryptoNetwork) +``` + +```python Python +addr = client.deposit_addresses.create_deposit_address( + profile_id="profile_123", + crypto_network="ETHEREUM", +) +print(f"Deposit address: {addr.address} ({addr.crypto_network})") +``` + +```typescript TypeScript +const addr = await client.depositAddresses.createDepositAddress({ + profileId: "profile_123", + cryptoNetwork: "ETHEREUM", +}); +console.log(`Deposit address: ${addr.address} (${addr.cryptoNetwork})`); +``` + +```java Java +DepositAddress addr = client.depositAddresses().createDepositAddress( + CreateDepositAddressRequest.builder() + .profileId("profile_123") + .cryptoNetwork("ETHEREUM") + .build()); +System.out.printf("Deposit address: %s (%s)%n", addr.getAddress(), addr.getCryptoNetwork()); +``` + + + +> For the full REST API documentation, see the [Deposit Addresses API Reference](/api-reference/endpoints/deposit-addresses/list-deposit-addresses). diff --git a/sdks/services/events.mdx b/sdks/services/events.mdx new file mode 100644 index 0000000..64c5eaa --- /dev/null +++ b/sdks/services/events.mdx @@ -0,0 +1,86 @@ +--- +title: 'Events' +description: 'SDK reference for the Events service — list and get events for notifications and webhook processing.' +--- + +The Events service provides access to platform events such as identity status changes, transfer completions, and orchestration updates. Use it for polling or to fetch full event details from webhook notifications. + +**Client accessor**: `client.Events` + +## Available Methods + +| Method | HTTP Equivalent | Description | +|---|---|---| +| `ListEvents` | `GET /notification/events` | List events with optional filters | +| `GetEvent` | `GET /notification/events/{id}` | Get an event by ID | + +## ListEvents + + + +```go Go +iter := client.Events.ListEvents(ctx, &paxos.ListEventsRequest{ + Limit: 100, +}) +for iter.Next() { + event := iter.Current() + fmt.Printf("%s: %s (%s)\n", event.ID, event.Type, event.CreatedAt) +} +if err := iter.Err(); err != nil { + log.Fatal(err) +} +``` + +```python Python +for event in client.events.list_events(limit=100): + print(f"{event.id}: {event.type} ({event.created_at})") +``` + +```typescript TypeScript +for await (const event of client.events.listEvents({ limit: 100 })) { + console.log(`${event.id}: ${event.type} (${event.createdAt})`); +} +``` + +```java Java +for (Event event : client.events().listEvents( + ListEventsRequest.builder().limit(100).build())) { + System.out.printf("%s: %s (%s)%n", + event.getId(), event.getType(), event.getCreatedAt()); +} +``` + + + +## GetEvent + +Fetch a single event by ID. This is used internally by `client.Webhooks.ParseEvent()` but is also available for direct use. + + + +```go Go +event, err := client.Events.GetEvent(ctx, "event_123") +if err != nil { + log.Fatal(err) +} +fmt.Printf("Event %s: %s\n", event.ID, event.Type) +``` + +```python Python +event = client.events.get_event("event_123") +print(f"Event {event.id}: {event.type}") +``` + +```typescript TypeScript +const event = await client.events.getEvent("event_123"); +console.log(`Event ${event.id}: ${event.type}`); +``` + +```java Java +Event event = client.events().getEvent("event_123"); +System.out.printf("Event %s: %s%n", event.getId(), event.getType()); +``` + + + +> For the full REST API documentation, see the [Events API Reference](/api-reference/endpoints/events/overview). diff --git a/sdks/services/fiat-transfers.mdx b/sdks/services/fiat-transfers.mdx new file mode 100644 index 0000000..8af9f7b --- /dev/null +++ b/sdks/services/fiat-transfers.mdx @@ -0,0 +1,74 @@ +--- +title: 'Fiat Transfers' +description: 'SDK reference for the Fiat Transfers service — manage fiat accounts, deposit instructions, and withdrawals.' +--- + +The Fiat Transfers service manages fiat bank accounts, deposit instructions, and fiat withdrawals. + +**Client accessor**: `client.FiatTransfers` + +## Available Methods + +| Method | HTTP Equivalent | Description | +|---|---|---| +| `ListFiatAccounts` | `GET /transfer/fiat-accounts` | List fiat bank accounts | +| `CreateFiatAccount` | `POST /transfer/fiat-accounts` | Register a fiat bank account | +| `GetFiatAccount` | `GET /transfer/fiat-accounts/{id}` | Get a fiat account by ID | +| `UpdateFiatAccount` | `PATCH /transfer/fiat-accounts/{id}` | Update a fiat account | +| `DeleteFiatAccount` | `DELETE /transfer/fiat-accounts/{id}` | Delete a fiat account | +| `ListFiatDepositInstructions` | `GET /transfer/fiat-deposit-instructions` | List fiat deposit instructions | +| `CreateFiatDepositInstructions` | `POST /transfer/fiat-deposit-instructions` | Create deposit instructions | +| `GetFiatDepositInstructions` | `GET /transfer/fiat-deposit-instructions/{id}` | Get deposit instructions by ID | +| `CreateFiatWithdrawal` | `POST /transfer/fiat-withdrawals` | Initiate a fiat withdrawal | + +## CreateFiatWithdrawal + + + +```go Go +withdrawal, err := client.FiatTransfers.CreateFiatWithdrawal(ctx, &paxos.CreateFiatWithdrawalRequest{ + ProfileID: "profile_123", + FiatAccountID: "fiat_acct_456", + Amount: "1000.00", + Asset: "USD", +}) +if err != nil { + log.Fatal(err) +} +fmt.Printf("Withdrawal %s: %s\n", withdrawal.ID, withdrawal.Status) +``` + +```python Python +withdrawal = client.fiat_transfers.create_fiat_withdrawal( + profile_id="profile_123", + fiat_account_id="fiat_acct_456", + amount="1000.00", + asset="USD", +) +print(f"Withdrawal {withdrawal.id}: {withdrawal.status}") +``` + +```typescript TypeScript +const withdrawal = await client.fiatTransfers.createFiatWithdrawal({ + profileId: "profile_123", + fiatAccountId: "fiat_acct_456", + amount: "1000.00", + asset: "USD", +}); +console.log(`Withdrawal ${withdrawal.id}: ${withdrawal.status}`); +``` + +```java Java +FiatWithdrawal withdrawal = client.fiatTransfers().createFiatWithdrawal( + CreateFiatWithdrawalRequest.builder() + .profileId("profile_123") + .fiatAccountId("fiat_acct_456") + .amount("1000.00") + .asset("USD") + .build()); +System.out.printf("Withdrawal %s: %s%n", withdrawal.getId(), withdrawal.getStatus()); +``` + + + +> For the full REST API documentation, see the [Fiat Transfers API Reference](/api-reference/endpoints/fiat-transfers/overview). diff --git a/sdks/services/identity.mdx b/sdks/services/identity.mdx new file mode 100644 index 0000000..8ef4eeb --- /dev/null +++ b/sdks/services/identity.mdx @@ -0,0 +1,132 @@ +--- +title: 'Identity' +description: 'SDK reference for the Identity service — create, verify, and manage customer identities.' +--- + +The Identity service manages KYC (Know Your Customer) verification for individuals and institutions. Identities must be verified before they can transact. + +**Client accessor**: `client.Identity` + +## Available Methods + +| Method | HTTP Equivalent | Description | +|---|---|---| +| `ListIdentities` | `GET /identity/identities` | List identities with optional filters | +| `CreateIdentity` | `POST /identity/identities` | Create a new identity for verification | +| `GetIdentity` | `GET /identity/identities/{id}` | Get an identity by ID | +| `UpdateIdentity` | `PATCH /identity/identities/{id}` | Update identity details | + +## CreateIdentity + + + +```go Go +identity, err := client.Identity.CreateIdentity(ctx, &paxos.CreateIdentityRequest{ + PersonDetails: &paxos.PersonDetails{ + FirstName: "Jane", + LastName: "Doe", + DateOfBirth: "1990-01-15", + }, +}) +if err != nil { + log.Fatal(err) +} +fmt.Printf("Created identity: %s (status: %s)\n", identity.ID, identity.SummaryStatus) +``` + +```python Python +identity = client.identity.create_identity( + person_details={ + "first_name": "Jane", + "last_name": "Doe", + "date_of_birth": "1990-01-15", + }, +) +print(f"Created identity: {identity.id} (status: {identity.summary_status})") +``` + +```typescript TypeScript +const identity = await client.identity.createIdentity({ + personDetails: { + firstName: "Jane", + lastName: "Doe", + dateOfBirth: "1990-01-15", + }, +}); +console.log(`Created identity: ${identity.id} (status: ${identity.summaryStatus})`); +``` + +```java Java +Identity identity = client.identity().createIdentity( + CreateIdentityRequest.builder() + .personDetails(PersonDetails.builder() + .firstName("Jane") + .lastName("Doe") + .dateOfBirth("1990-01-15") + .build()) + .build()); +System.out.printf("Created identity: %s (status: %s)%n", + identity.getId(), identity.getSummaryStatus()); +``` + + + +## GetIdentity + + + +```go Go +identity, err := client.Identity.GetIdentity(ctx, "identity_123") +``` + +```python Python +identity = client.identity.get_identity("identity_123") +``` + +```typescript TypeScript +const identity = await client.identity.getIdentity("identity_123"); +``` + +```java Java +Identity identity = client.identity().getIdentity("identity_123"); +``` + + + +## ListIdentities + + + +```go Go +iter := client.Identity.ListIdentities(ctx, &paxos.ListIdentitiesRequest{Limit: 50}) +for iter.Next() { + id := iter.Current() + fmt.Printf("%s: %s %s (%s)\n", id.ID, id.PersonDetails.FirstName, id.PersonDetails.LastName, id.SummaryStatus) +} +``` + +```python Python +for id in client.identity.list_identities(limit=50): + print(f"{id.id}: {id.person_details.first_name} {id.person_details.last_name} ({id.summary_status})") +``` + +```typescript TypeScript +for await (const id of client.identity.listIdentities({ limit: 50 })) { + console.log(`${id.id}: ${id.personDetails.firstName} ${id.personDetails.lastName} (${id.summaryStatus})`); +} +``` + +```java Java +for (Identity id : client.identity().listIdentities( + ListIdentitiesRequest.builder().limit(50).build())) { + System.out.printf("%s: %s %s (%s)%n", + id.getId(), id.getPersonDetails().getFirstName(), + id.getPersonDetails().getLastName(), id.getSummaryStatus()); +} +``` + + + +> In Sandbox, use `client.Sandbox.SetIdentityStatus()` to approve identities without real verification. See the [Sandbox Guide](/sdks/sandbox). + +> For the full REST API documentation, see the [Identity API Reference](/api-reference/endpoints/identity/overview). diff --git a/sdks/services/market-data.mdx b/sdks/services/market-data.mdx new file mode 100644 index 0000000..b707d3e --- /dev/null +++ b/sdks/services/market-data.mdx @@ -0,0 +1,85 @@ +--- +title: 'Market Data' +description: 'SDK reference for the Market Data service — list markets, order books, tickers, and recent executions.' +--- + +The Market Data service provides real-time market information including available markets, order book depth, tickers, and recent trade executions. Most Market Data endpoints do not require authentication. + +**Client accessor**: `client.MarketData` + +## Available Methods + +| Method | HTTP Equivalent | Description | +|---|---|---| +| `ListMarkets` | `GET /trading/markets` | List available trading markets | +| `GetOrderBook` | `GET /trading/markets/{market}/order-book` | Get the order book for a market | +| `GetTicker` | `GET /trading/markets/{market}/ticker` | Get the ticker for a market | +| `ListRecentExecutions` | `GET /trading/markets/{market}/recent-executions` | List recent trades for a market | + +## ListMarkets + + + +```go Go +markets, err := client.MarketData.ListMarkets(ctx) +if err != nil { + log.Fatal(err) +} +for _, m := range markets { + fmt.Printf("%s: %s / %s\n", m.Market, m.BaseAsset, m.QuoteAsset) +} +``` + +```python Python +markets = client.market_data.list_markets() +for m in markets: + print(f"{m.market}: {m.base_asset} / {m.quote_asset}") +``` + +```typescript TypeScript +const markets = await client.marketData.listMarkets(); +for (const m of markets) { + console.log(`${m.market}: ${m.baseAsset} / ${m.quoteAsset}`); +} +``` + +```java Java +List markets = client.marketData().listMarkets(); +for (Market m : markets) { + System.out.printf("%s: %s / %s%n", m.getMarket(), m.getBaseAsset(), m.getQuoteAsset()); +} +``` + + + +## GetOrderBook + + + +```go Go +book, err := client.MarketData.GetOrderBook(ctx, "BTC-USD") +if err != nil { + log.Fatal(err) +} +fmt.Printf("Best bid: %s, Best ask: %s\n", book.Bids[0].Price, book.Asks[0].Price) +``` + +```python Python +book = client.market_data.get_order_book("BTC-USD") +print(f"Best bid: {book.bids[0].price}, Best ask: {book.asks[0].price}") +``` + +```typescript TypeScript +const book = await client.marketData.getOrderBook("BTC-USD"); +console.log(`Best bid: ${book.bids[0].price}, Best ask: ${book.asks[0].price}`); +``` + +```java Java +OrderBook book = client.marketData().getOrderBook("BTC-USD"); +System.out.printf("Best bid: %s, Best ask: %s%n", + book.getBids().get(0).getPrice(), book.getAsks().get(0).getPrice()); +``` + + + +> For the full REST API documentation, see the [Market Data API Reference](/api-reference/endpoints/market-data/overview). diff --git a/sdks/services/orders.mdx b/sdks/services/orders.mdx new file mode 100644 index 0000000..b7520cf --- /dev/null +++ b/sdks/services/orders.mdx @@ -0,0 +1,96 @@ +--- +title: 'Orders' +description: 'SDK reference for the Orders service — create, list, and cancel trading orders.' +--- + +The Orders service lets you place, monitor, and cancel trading orders on the Paxos exchange. + +**Client accessor**: `client.Orders` + +## Available Methods + +| Method | HTTP Equivalent | Description | +|---|---|---| +| `ListOrders` | `GET /trading/orders` | List orders with optional filters | +| `CreateOrder` | `POST /trading/orders` | Place a new order | +| `GetOrder` | `GET /trading/orders/{id}` | Get an order by ID | +| `CancelOrder` | `DELETE /trading/orders/{id}` | Cancel a pending order | +| `ListExecutions` | `GET /trading/executions` | List order executions | + +## CreateOrder + + + +```go Go +order, err := client.Orders.CreateOrder(ctx, &paxos.CreateOrderRequest{ + ProfileID: "profile_123", + Market: "BTC-USD", + Side: "BUY", + Type: "MARKET", + BaseAmount: "0.01", +}) +if err != nil { + log.Fatal(err) +} +fmt.Printf("Order %s: %s\n", order.ID, order.Status) +``` + +```python Python +order = client.orders.create_order( + profile_id="profile_123", + market="BTC-USD", + side="BUY", + type="MARKET", + base_amount="0.01", +) +print(f"Order {order.id}: {order.status}") +``` + +```typescript TypeScript +const order = await client.orders.createOrder({ + profileId: "profile_123", + market: "BTC-USD", + side: "BUY", + type: "MARKET", + baseAmount: "0.01", +}); +console.log(`Order ${order.id}: ${order.status}`); +``` + +```java Java +Order order = client.orders().createOrder( + CreateOrderRequest.builder() + .profileId("profile_123") + .market("BTC-USD") + .side("BUY") + .type("MARKET") + .baseAmount("0.01") + .build()); +System.out.printf("Order %s: %s%n", order.getId(), order.getStatus()); +``` + + + +## CancelOrder + + + +```go Go +err := client.Orders.CancelOrder(ctx, "order_123") +``` + +```python Python +client.orders.cancel_order("order_123") +``` + +```typescript TypeScript +await client.orders.cancelOrder("order_123"); +``` + +```java Java +client.orders().cancelOrder("order_123"); +``` + + + +> For the full REST API documentation, see the [Orders API Reference](/api-reference/endpoints/orders/overview). diff --git a/sdks/services/profiles.mdx b/sdks/services/profiles.mdx new file mode 100644 index 0000000..1ed573d --- /dev/null +++ b/sdks/services/profiles.mdx @@ -0,0 +1,92 @@ +--- +title: 'Profiles' +description: 'SDK reference for the Profiles service — create, list, and manage profiles and balances.' +--- + +Profiles represent segregated accounts within your Paxos organization. Each profile can hold assets, execute transfers, and place orders independently. + +**Client accessor**: `client.Profiles` + +## Available Methods + +| Method | HTTP Equivalent | Description | +|---|---|---| +| `ListProfiles` | `GET /identity/profiles` | List profiles | +| `CreateProfile` | `POST /identity/profiles` | Create a new profile | +| `GetProfile` | `GET /identity/profiles/{id}` | Get a profile by ID | +| `UpdateProfile` | `PATCH /identity/profiles/{id}` | Update profile details | +| `DeactivateProfile` | `POST /identity/profiles/{id}/deactivate` | Deactivate a profile | +| `ListProfileBalances` | `GET /identity/profiles/{id}/balances` | List balances for a profile | +| `GetProfileBalance` | `GET /identity/profiles/{id}/balances/{asset}` | Get balance for a specific asset | + +## CreateProfile + + + +```go Go +profile, err := client.Profiles.CreateProfile(ctx, &paxos.CreateProfileRequest{ + Nickname: "Trading Account", +}) +if err != nil { + log.Fatal(err) +} +fmt.Printf("Profile: %s (%s)\n", profile.ID, profile.Nickname) +``` + +```python Python +profile = client.profiles.create_profile(nickname="Trading Account") +print(f"Profile: {profile.id} ({profile.nickname})") +``` + +```typescript TypeScript +const profile = await client.profiles.createProfile({ nickname: "Trading Account" }); +console.log(`Profile: ${profile.id} (${profile.nickname})`); +``` + +```java Java +Profile profile = client.profiles().createProfile( + CreateProfileRequest.builder() + .nickname("Trading Account") + .build()); +System.out.printf("Profile: %s (%s)%n", profile.getId(), profile.getNickname()); +``` + + + +## ListProfileBalances + + + +```go Go +balances, err := client.Profiles.ListProfileBalances(ctx, "profile_123") +if err != nil { + log.Fatal(err) +} +for _, b := range balances { + fmt.Printf("%s: %s available\n", b.Asset, b.Available) +} +``` + +```python Python +balances = client.profiles.list_profile_balances("profile_123") +for b in balances: + print(f"{b.asset}: {b.available} available") +``` + +```typescript TypeScript +const balances = await client.profiles.listProfileBalances("profile_123"); +for (const b of balances) { + console.log(`${b.asset}: ${b.available} available`); +} +``` + +```java Java +List balances = client.profiles().listProfileBalances("profile_123"); +for (ProfileBalance b : balances) { + System.out.printf("%s: %s available%n", b.getAsset(), b.getAvailable()); +} +``` + + + +> For the full REST API documentation, see the [Profiles API Reference](/api-reference/endpoints/profiles/overview). diff --git a/sdks/services/settlement.mdx b/sdks/services/settlement.mdx new file mode 100644 index 0000000..b17ca1b --- /dev/null +++ b/sdks/services/settlement.mdx @@ -0,0 +1,66 @@ +--- +title: 'Settlement' +description: 'SDK reference for the Settlement service — create, affirm, cancel, and list settlement transactions.' +--- + +The Settlement service manages bilateral settlement transactions between counterparties. + +**Client accessor**: `client.Settlement` + +## Available Methods + +| Method | HTTP Equivalent | Description | +|---|---|---| +| `ListTransactions` | `GET /settlement/transactions` | List settlement transactions | +| `CreateTransaction` | `POST /settlement/transactions` | Create a settlement transaction | +| `GetTransaction` | `GET /settlement/transactions/{id}` | Get a transaction by ID | +| `CancelTransaction` | `DELETE /settlement/transactions/{id}` | Cancel a pending transaction | +| `AffirmTransaction` | `POST /settlement/transactions/{id}/affirm` | Affirm a transaction | + +## CreateTransaction + + + +```go Go +txn, err := client.Settlement.CreateTransaction(ctx, &paxos.CreateSettlementTransactionRequest{ + ProfileID: "profile_123", + Amount: "5000.00", + Asset: "USD", +}) +if err != nil { + log.Fatal(err) +} +fmt.Printf("Settlement %s: %s\n", txn.ID, txn.Status) +``` + +```python Python +txn = client.settlement.create_transaction( + profile_id="profile_123", + amount="5000.00", + asset="USD", +) +print(f"Settlement {txn.id}: {txn.status}") +``` + +```typescript TypeScript +const txn = await client.settlement.createTransaction({ + profileId: "profile_123", + amount: "5000.00", + asset: "USD", +}); +console.log(`Settlement ${txn.id}: ${txn.status}`); +``` + +```java Java +SettlementTransaction txn = client.settlement().createTransaction( + CreateSettlementTransactionRequest.builder() + .profileId("profile_123") + .amount("5000.00") + .asset("USD") + .build()); +System.out.printf("Settlement %s: %s%n", txn.getId(), txn.getStatus()); +``` + + + +> For the full REST API documentation, see the [Settlement API Reference](/api-reference/endpoints/settlement/overview). diff --git a/sdks/services/stablecoin-conversion.mdx b/sdks/services/stablecoin-conversion.mdx new file mode 100644 index 0000000..629eb9b --- /dev/null +++ b/sdks/services/stablecoin-conversion.mdx @@ -0,0 +1,69 @@ +--- +title: 'Stablecoin Conversion' +description: 'SDK reference for the Stablecoin Conversion service — create, list, and cancel stablecoin conversions.' +--- + +The Stablecoin Conversion service manages conversions between fiat and Paxos-issued stablecoins (USDP, PYUSD, USDG). + +**Client accessor**: `client.StablecoinConversion` + +## Available Methods + +| Method | HTTP Equivalent | Description | +|---|---|---| +| `ListStablecoinConversions` | `GET /conversion/stablecoin-conversions` | List conversions | +| `CreateStablecoinConversion` | `POST /conversion/stablecoin-conversions` | Create a conversion | +| `GetStablecoinConversion` | `GET /conversion/stablecoin-conversions/{id}` | Get a conversion by ID | +| `CancelStablecoinConversion` | `DELETE /conversion/stablecoin-conversions/{id}` | Cancel a pending conversion | + +## CreateStablecoinConversion + + + +```go Go +conversion, err := client.StablecoinConversion.CreateStablecoinConversion(ctx, &paxos.CreateStablecoinConversionRequest{ + ProfileID: "profile_123", + Amount: "1000.00", + SourceAsset: "USD", + TargetAsset: "USDP", +}) +if err != nil { + log.Fatal(err) +} +fmt.Printf("Conversion %s: %s\n", conversion.ID, conversion.Status) +``` + +```python Python +conversion = client.stablecoin_conversion.create_stablecoin_conversion( + profile_id="profile_123", + amount="1000.00", + source_asset="USD", + target_asset="USDP", +) +print(f"Conversion {conversion.id}: {conversion.status}") +``` + +```typescript TypeScript +const conversion = await client.stablecoinConversion.createStablecoinConversion({ + profileId: "profile_123", + amount: "1000.00", + sourceAsset: "USD", + targetAsset: "USDP", +}); +console.log(`Conversion ${conversion.id}: ${conversion.status}`); +``` + +```java Java +StablecoinConversion conversion = client.stablecoinConversion().createStablecoinConversion( + CreateStablecoinConversionRequest.builder() + .profileId("profile_123") + .amount("1000.00") + .sourceAsset("USD") + .targetAsset("USDP") + .build()); +System.out.printf("Conversion %s: %s%n", conversion.getId(), conversion.getStatus()); +``` + + + +> For the full REST API documentation, see the [Stablecoin Conversion API Reference](/api-reference/endpoints/stablecoin-conversion/overview). diff --git a/sdks/services/transfers.mdx b/sdks/services/transfers.mdx new file mode 100644 index 0000000..c56b385 --- /dev/null +++ b/sdks/services/transfers.mdx @@ -0,0 +1,122 @@ +--- +title: 'Transfers' +description: 'SDK reference for the Transfers service — list, get, and monitor crypto and fiat transfers.' +--- + +The Transfers service provides read access to all transfers (crypto deposits, crypto withdrawals, wire transfers, and internal transfers) associated with your profiles. + +**Client accessor**: `client.Transfers` + +## Available Methods + +| Method | HTTP Equivalent | Description | +|---|---|---| +| `ListTransfers` | `GET /transfer/transfers` | List transfers with optional filters | +| `GetTransfer` | `GET /transfer/transfers/{id}` | Get a single transfer by ID | + +## ListTransfers + +Returns an iterator over all transfers matching the given filters. + + + +```go Go +iter := client.Transfers.ListTransfers(ctx, &paxos.ListTransfersRequest{ + ProfileID: "profile_123", + Limit: 50, +}) + +for iter.Next() { + t := iter.Current() + fmt.Printf("%s: %s %s (%s)\n", t.ID, t.Amount, t.Asset, t.Status) +} +if err := iter.Err(); err != nil { + log.Fatal(err) +} +``` + +```python Python +for t in client.transfers.list_transfers(profile_id="profile_123", limit=50): + print(f"{t.id}: {t.amount} {t.asset} ({t.status})") +``` + +```typescript TypeScript +for await (const t of client.transfers.listTransfers({ + profileId: "profile_123", + limit: 50, +})) { + console.log(`${t.id}: ${t.amount} ${t.asset} (${t.status})`); +} +``` + +```java Java +for (Transfer t : client.transfers().listTransfers( + ListTransfersRequest.builder() + .profileId("profile_123") + .limit(50) + .build())) { + System.out.printf("%s: %s %s (%s)%n", + t.getId(), t.getAmount(), t.getAsset(), t.getStatus()); +} +``` + + + +### Request Parameters + +| Parameter | Type | Description | +|---|---|---| +| `profile_id` | string | Filter by profile ID | +| `limit` | int | Number of items per page (default 50) | +| `type` | string | Filter by transfer type (`DEPOSIT`, `WITHDRAWAL`, etc.) | +| `status` | string | Filter by status (`PENDING`, `COMPLETED`, `FAILED`) | + +## GetTransfer + +Fetch a single transfer by its ID. + + + +```go Go +transfer, err := client.Transfers.GetTransfer(ctx, "txn_123") +if err != nil { + if paxos.IsNotFound(err) { + fmt.Println("Transfer not found") + } + return err +} +fmt.Printf("Transfer %s: %s %s\n", transfer.ID, transfer.Amount, transfer.Asset) +``` + +```python Python +try: + transfer = client.transfers.get_transfer("txn_123") + print(f"Transfer {transfer.id}: {transfer.amount} {transfer.asset}") +except paxos.NotFoundError: + print("Transfer not found") +``` + +```typescript TypeScript +try { + const transfer = await client.transfers.getTransfer("txn_123"); + console.log(`Transfer ${transfer.id}: ${transfer.amount} ${transfer.asset}`); +} catch (e) { + if (e instanceof PaxosNotFoundError) { + console.log("Transfer not found"); + } +} +``` + +```java Java +try { + Transfer transfer = client.transfers().getTransfer("txn_123"); + System.out.printf("Transfer %s: %s %s%n", + transfer.getId(), transfer.getAmount(), transfer.getAsset()); +} catch (NotFoundException e) { + System.out.println("Transfer not found"); +} +``` + + + +> For the full REST API documentation, see the [Transfers API Reference](/api-reference/endpoints/transfers/overview). diff --git a/sdks/webhooks.mdx b/sdks/webhooks.mdx new file mode 100644 index 0000000..bdf59c8 --- /dev/null +++ b/sdks/webhooks.mdx @@ -0,0 +1,183 @@ +--- +title: 'Events & Webhooks' +description: 'Consume Paxos events through webhooks or the Events API for real-time notifications.' +--- + +Paxos delivers notifications about resource changes (identity approvals, transfer completions, orchestration status updates) through events. You can consume events in two ways: + +- **Webhooks** — Paxos pushes a notification to your endpoint when something happens +- **Events API** — You poll the [Events API](/api-reference/endpoints/events/overview) to fetch events on your own schedule + +## Webhook Payload Pattern + +Paxos webhooks use a reduced-payload approach. The webhook notification contains a summary (event ID, type, source, and timestamp) but **not** the full resource. Your application must call `GetEvent` to fetch the complete event details. + +This pattern ensures that sensitive data is only delivered through authenticated API calls. + + + +```go Go +// In your webhook HTTP handler +func handleWebhook(w http.ResponseWriter, r *http.Request) { + body, _ := io.ReadAll(r.Body) + + // ParseEvent extracts the event ID from the webhook body, + // then fetches the full event via the Events API + event, err := client.Webhooks.ParseEvent(r.Context(), body) + if err != nil { + http.Error(w, "failed to parse event", http.StatusBadRequest) + return + } + + switch event.Type { + case "identity.approved": + fmt.Printf("Identity %s approved\n", event.ResourceID) + case "transfer.crypto.deposit.completed": + fmt.Printf("Crypto deposit %s completed\n", event.ResourceID) + } + + w.WriteHeader(http.StatusOK) +} +``` + +```python Python +# In your webhook handler (e.g., Flask or FastAPI) +@app.post("/webhooks/paxos") +def handle_webhook(request): + body = request.body + + # parse_event extracts the event ID from the webhook body, + # then fetches the full event via the Events API + event = client.webhooks.parse_event(body) + + if event.type == "identity.approved": + print(f"Identity {event.resource_id} approved") + elif event.type == "transfer.crypto.deposit.completed": + print(f"Crypto deposit {event.resource_id} completed") + + return {"status": "ok"} +``` + +```typescript TypeScript +// In your webhook handler (e.g., Express) +app.post("/webhooks/paxos", async (req, res) => { + const body = req.body; + + // parseEvent extracts the event ID from the webhook body, + // then fetches the full event via the Events API + const event = await client.webhooks.parseEvent(body); + + switch (event.type) { + case "identity.approved": + console.log(`Identity ${event.resourceId} approved`); + break; + case "transfer.crypto.deposit.completed": + console.log(`Crypto deposit ${event.resourceId} completed`); + break; + } + + res.sendStatus(200); +}); +``` + +```java Java +// In your webhook handler (e.g., Spring Boot) +@PostMapping("/webhooks/paxos") +public ResponseEntity handleWebhook(@RequestBody byte[] body) { + Event event = client.webhooks().parseEvent(body); + + switch (event.getType()) { + case "identity.approved": + System.out.printf("Identity %s approved%n", event.getResourceId()); + break; + case "transfer.crypto.deposit.completed": + System.out.printf("Crypto deposit %s completed%n", event.getResourceId()); + break; + } + + return ResponseEntity.ok().build(); +} +``` + + + +## Webhook Endpoint Security + +Paxos authenticates with your webhook endpoint using one of two methods. Configure these in the [Dashboard](https://dashboard.paxos.com/): + +- **API Key** — Set a custom header name and value. Paxos includes this header in every webhook request. Validate it in your handler. +- **OAuth** — Provide your OAuth token endpoint. Paxos obtains a token from your endpoint before calling your webhook. + + +Paxos does not currently sign webhook payloads. Payload signing is planned for a future release. In the meantime, `ParseEvent` fetches the canonical event from the API to ensure authenticity. + + +## Polling with the Events API + +As an alternative to webhooks, poll the [Events API](/api-reference/endpoints/events/overview) to fetch events: + + + +```go Go +iter := client.Events.ListEvents(ctx, &paxos.ListEventsRequest{ + Limit: 100, +}) + +for iter.Next() { + event := iter.Current() + fmt.Printf("Event: %s — %s\n", event.ID, event.Type) +} +if err := iter.Err(); err != nil { + log.Fatal(err) +} +``` + +```python Python +for event in client.events.list_events(limit=100): + print(f"Event: {event.id} — {event.type}") +``` + +```typescript TypeScript +for await (const event of client.events.listEvents({ limit: 100 })) { + console.log(`Event: ${event.id} — ${event.type}`); +} +``` + +```java Java +for (Event event : client.events().listEvents( + ListEventsRequest.builder().limit(100).build())) { + System.out.printf("Event: %s — %s%n", event.getId(), event.getType()); +} +``` + + + +## Common Event Types + +| Event Type | Description | +|---|---| +| `identity.approved` | Identity has been approved for transactions | +| `identity.denied` | Identity verification was denied | +| `transfer.crypto.deposit.completed` | Crypto deposit confirmed on-chain | +| `transfer.crypto.withdrawal.completed` | Crypto withdrawal confirmed on-chain | +| `transfer.wire.deposit.completed` | Wire deposit has arrived | +| `transfer.wire.withdrawal.completed` | Wire withdrawal has been sent | +| `orchestration.completed` | Stablecoin orchestration finished successfully | +| `orchestration.failed` | Stablecoin orchestration failed | + +For the full list of event types and webhook payloads, see the [Webhooks API Reference](/api-reference/webhooks/identity-approved). + +## Handling Events Idempotently + +Webhooks may be delivered more than once. Deduplicate by tracking the `event.id`: + +```go +// Example: skip already-processed events +if alreadyProcessed(event.ID) { + return // skip duplicate +} +process(event) +markAsProcessed(event.ID) +``` + +> For more details on webhook configuration and retry behavior, see the [Webhooks Guide](/guides/webhooks/index).