# SDK Integration

Self Agent ID provides three SDKs with identical feature parity:

| Language   | Package              | Install                          |
| ---------- | -------------------- | -------------------------------- |
| TypeScript | `@selfxyz/agent-sdk` | `npm install @selfxyz/agent-sdk` |
| Python     | `selfxyz-agent-sdk`  | `pip install selfxyz-agent-sdk`  |
| Rust       | `self-agent-sdk`     | `cargo add self-agent-sdk`       |

## Agent-Side: Signing Requests

Use `SelfAgent` to sign outbound API requests. The SDK attaches three headers to every request:

* `x-self-agent-address` — the agent's Ethereum address
* `x-self-agent-signature` — ECDSA signature of `keccak256(timestamp + METHOD + path + bodyHash)`
* `x-self-agent-timestamp` — Unix timestamp (seconds)

{% tabs %}
{% tab title="TypeScript" %}

```typescript
import { SelfAgent } from "@selfxyz/agent-sdk";

const agent = new SelfAgent({
  privateKey: process.env.AGENT_PRIVATE_KEY!,
  registryAddress: "0xaC3DF9ABf80d0F5c020C06B04Cced27763355944",
  rpcUrl: "https://forno.celo.org",
});

// Signed fetch — headers are attached automatically
const res = await agent.fetch("https://api.example.com/protected", {
  method: "POST",
  body: JSON.stringify({ action: "hello" }),
});
```

{% endtab %}

{% tab title="Python" %}

```python
from self_agent_sdk import SelfAgent

agent = SelfAgent(
    private_key=os.environ["AGENT_PRIVATE_KEY"],
    registry_address="0xaC3DF9ABf80d0F5c020C06B04Cced27763355944",
    rpc_url="https://forno.celo.org",
)

# Signed request
res = agent.fetch("https://api.example.com/protected", method="POST",
                   json={"action": "hello"})
```

{% endtab %}

{% tab title="Rust" %}

```rust
use self_agent_sdk::SelfAgent;

let agent = SelfAgent::new(
    &std::env::var("AGENT_PRIVATE_KEY")?,
    "0xaC3DF9ABf80d0F5c020C06B04Cced27763355944",
    "https://forno.celo.org",
)?;

let res = agent.fetch("https://api.example.com/protected")
    .method("POST")
    .json(&serde_json::json!({"action": "hello"}))
    .send()
    .await?;
```

{% endtab %}
{% endtabs %}

## Service-Side: Verifying Requests

Use `SelfAgentVerifier` to verify incoming agent requests. The verifier recovers the signer address from the ECDSA signature, derives the agent key, and checks `isVerifiedAgent()` on-chain.

### Builder Pattern

{% tabs %}
{% tab title="TypeScript" %}

```typescript
import { SelfAgentVerifier } from "@selfxyz/agent-sdk";

const verifier = SelfAgentVerifier.create()
  .requireAge(18)
  .requireOFAC()
  .maxAgentsPerHuman(1)
  .build();

// Express middleware
app.use("/api", verifier.auth());
```

{% endtab %}

{% tab title="Python" %}

```python
from self_agent_sdk import SelfAgentVerifier

verifier = (SelfAgentVerifier.create()
    .require_age(18)
    .require_ofac()
    .max_agents_per_human(1)
    .build())

# Flask middleware
@app.before_request
def verify_agent():
    result = verifier.verify_request(request)
    if not result.valid:
        return {"error": result.error}, 401
```

{% endtab %}

{% tab title="Rust" %}

```rust
use self_agent_sdk::SelfAgentVerifier;

let verifier = SelfAgentVerifier::builder()
    .require_age(18)
    .require_ofac()
    .max_agents_per_human(1)
    .build()?;

// Axum middleware (requires `axum` feature)
let app = Router::new()
    .route("/api/protected", post(handler))
    .layer(verifier.into_layer());
```

{% endtab %}
{% endtabs %}

### Direct Verification

```typescript
const result = await verifier.verify({
  signature: req.headers["x-self-agent-signature"],
  timestamp: req.headers["x-self-agent-timestamp"],
  method: req.method,
  url: req.url,
  body: req.body,
});

if (result.valid) {
  console.log(`Verified agent: ${result.agentAddress}, ID #${result.agentId}`);
  console.log(`Credentials:`, result.credentials);
}
```

## Security Defaults

`SelfAgentVerifier` defaults are strict:

| Setting               | Default     | Description                                      |
| --------------------- | ----------- | ------------------------------------------------ |
| `requireSelfProvider` | `true`      | Only accept proofs from Self Protocol's provider |
| `maxAgentsPerHuman`   | `1`         | One agent per human (sybil resistance)           |
| Replay protection     | Enabled     | Signature nonce + timestamp freshness            |
| Timestamp window      | 300 seconds | Reject requests older than 5 minutes             |

{% hint style="warning" %}
Setting `requireSelfProvider: false` accepts verification from any approved proof provider, not only Self Protocol.
{% endhint %}

## Agent Status & Info

```typescript
// Check registration status
const registered = await agent.isRegistered();

// Get full agent info
const info = await agent.getInfo();
// { agentId, address, agentKey, isVerified, proofProvider, proofExpiresAt }
```

## Proof Expiry

Agent proofs have a validity window. The SDK exposes expiry information and handles stale proofs:

```typescript
const info = await agent.getInfo();
const expiresAt = info.proofExpiresAt; // Unix timestamp (seconds)

// SDK verifiers automatically reject expired proofs
// 30-day warning threshold for upcoming expiry
```

{% hint style="warning" %}
When a proof expires, the agent's `isProofFresh()` returns `false` on-chain. There is no on-chain refresh mechanism — the agent must deregister and re-register with a fresh proof (scanning their passport again). The soulbound NFT is NOT burned — it remains as a historical record.
{% endhint %}

## A2A Agent Cards

Build and store standardized agent identity cards:

```typescript
import { buildAgentCard } from "@selfxyz/agent-sdk";

const card = await buildAgentCard(agent, {
  name: "My Agent",
  description: "A human-verified AI assistant",
});

// Store on-chain via updateAgentMetadata()
```

Cards follow the A2A format and are queryable via:

* `GET /api/cards/{chainId}/{agentId}`
* `GET /.well-known/a2a/{agentId}?chain={chainId}`
* `POST /api/a2a` — A2A JSON-RPC endpoint for agent-to-agent communication


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.self.xyz/self-agent-id/sdk-integration.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
