> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.clossir.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.clossir.com/_mcp/server.

# Async Operations

GETTING STARTED · SDK · ASYNC OPERATIONS

The Clossir API follows a CQRS (Command Query Responsibility Segregation) pattern.
Understanding this split is essential for integrating correctly.

## Reads vs commands

| Operation type      | HTTP method             | Status code    | Behavior                                  |
| ------------------- | ----------------------- | -------------- | ----------------------------------------- |
| **Read** (query)    | `GET`                   | `200 OK`       | Returns current state immediately         |
| **Write** (command) | `POST`, `PUT`, `DELETE` | `202 Accepted` | Queues the operation for async processing |

Reads hit the database directly and return the current projection. Commands are queued and
processed asynchronously by dedicated workers — they don't execute inline with your request.

## The 202 response

When you issue a command, the API returns `202 Accepted` with a response body containing
the resource ID and a pending status:

```ts title="create-transfer.ts"
const result = await signum.transfers.postTransfers({
  fromWallet: "0xabc...sender",
  toWallet: "0xdef...receiver",
  assetId: "ast_abc123",
  amount: "1000",
});

console.log(result.accepted);    // true
console.log(result.transferId);  // "txn_xyz789"
console.log(result.status);      // "pending"
console.log(result.message);     // human-readable confirmation
```

At this point the transfer is **queued**, not complete. The system will evaluate compliance
policies, execute the on-chain transaction, and update the status asynchronously.

Some endpoints also return a `requestId` field for webhook correlation (see below).

## Checking status (polling)

Poll the corresponding `GET` endpoint with the resource ID to check progress:

```ts title="poll-status.ts"
async function waitForTransfer(transferId: string): Promise<void> {
  const maxAttempts = 30;
  const intervalMs = 2000;

  for (let i = 0; i < maxAttempts; i++) {
    const transfer = await signum.transfers.getTransfersByTransferId({
      transferId,
    });

    if (transfer.status === "completed") {
      console.log("Transfer settled:", transfer);
      return;
    }

    if (transfer.status === "failed") {
      throw new Error(`Transfer failed: ${transfer.failureReason}`);
    }

    // Still pending — wait and retry
    await new Promise((r) => setTimeout(r, intervalMs));
  }

  throw new Error("Transfer did not settle within timeout");
}
```

## Webhook correlation (preferred)

Instead of polling, subscribe to webhooks for real-time notifications. Endpoints that
return a `requestId` in their 202 response (such as asset deployment and bridge operations)
allow you to correlate the webhook payload with the original command:

```
POST /orgs/:id/assets/:id/deploy → 202 { requestId: "req_abc", assetId: "ast_xyz", status: "pending" }

... async processing ...

Webhook → { event: "asset.deployed", requestId: "req_abc", assetId: "ast_xyz", ... }
```

For endpoints that return a resource ID instead (like `transferId`), match on that ID in
the webhook payload.

Webhooks are more efficient than polling and give you immediate notification when processing
completes. See the [API Reference](/api/overview) for the webhook payloads and event types.

## Common 202 endpoints

| Endpoint                           | ID in response         | What happens async                   |
| ---------------------------------- | ---------------------- | ------------------------------------ |
| `POST /attestations`               | `attestationId`        | On-chain attestation settlement      |
| `POST /transfers`                  | `transferId`           | Compliance check + on-chain transfer |
| `POST /orgs/:id/assets`            | `assetId`              | Asset registration                   |
| `POST /orgs/:id/assets/:id/deploy` | `requestId`, `assetId` | On-chain contract deployment         |
| `POST /orgs/:id/assets/:id/bridge` | `requestId`            | Cross-chain bridge execution         |

## React integration

With `@signum-tech/sdk-react`, use `useSignumMutation` for commands and `useSignumQuery`
with `refetchInterval` for polling:

```tsx title="use-transfer.tsx"
import { useSignumMutation, useSignumQuery } from "@signum-tech/sdk-react";

function TransferButton({ payload }: { payload: TransferPayload }) {
  const [transferId, setTransferId] = useState<string | null>(null);

  const mutation = useSignumMutation({
    mutationFn: (client, variables: TransferPayload) =>
      client.transfers.postTransfers(variables),
    onSuccess: (data) => setTransferId(data.transferId),
  });

  const status = useSignumQuery({
    queryKey: ["transfer", transferId],
    queryFn: (client) =>
      client.transfers.getTransfersByTransferId({ transferId: transferId! }),
    enabled: !!transferId,
    refetchInterval: (query) =>
      query.state.data?.status === "pending" ? 2000 : false,
  });

  // render based on mutation + status states...
}
```

See [React Integration](/getting-started/sdk/react) for the full `sdk-react` guide.

## Next steps

* [Error Handling](/getting-started/sdk/error-handling) — catch and branch on API errors
* [API Reference](/api/overview) — webhook payloads and event types
* [Webhooks](/solutions/infra/webhooks) — set up webhook subscriptions