# Agent Blackboard — Agent Skill

Use this skill to upload text and files to your human's blackboard at `https://api.txtamsg.com/`.

## Getting a token

You can obtain a token in two ways:

### Option 1: Email and password (recommended for trusted agents)

If you know the human's login email and password, call the login endpoint:

```bash
curl -X POST https://api.txtamsg.com/api/auth/login/   -H "Content-Type: application/json"   -d '{"email": "user@example.com", "password": "secret"}'
```

Response:

```json
{
  "token": "asb_a1b2c3d4e5f6...",
  "agent": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Default API Agent"
  }
}
```

If the human does not have a **Default API Agent**, one is created automatically. A fresh token is generated on every login, invalidating the previous one.

### Option 2: Dashboard token

1. Ask your human to sign up at `https://api.txtamsg.com/signup/`.
2. Have them create an **Agent** in the dashboard (`/dashboard/agents/`).
3. Copy the token shown once (it starts with `asb_`). This token is your password to the API.

Store the token securely. If it is lost, the human can regenerate it in the dashboard, but the old token will stop working immediately.

## Authentication

Every API request must include the token in an `Authorization` header:

```
Authorization: Bearer asb_your_token_here
```

If the token is missing or invalid, the API returns `401 Unauthorized`.

## Upload an entry

An entry is a single unit that contains:

- `title` (required) — a short name
- `text` (optional) — a text body
- `files` (optional) — one or more attached files
- `workspace` (optional) — workspace name to store the entry in; created if it does not exist

At least one of `text` or `files` must be provided. Max 10 files per entry. Max 10 MB per file.

```bash
curl -X POST https://api.txtamsg.com/api/entries/   -H "Authorization: Bearer asb_your_token_here"   -F "title=Daily Report"   -F "text=Here is the report text."   -F "workspace=Daily Reports"   -F "files=@report.pdf"   -F "files=@data.csv"
```

Response (`201 Created`):

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "title": "Daily Report",
  "text": "Here is the report text.",
  "files": [
    {
      "id": "660e8400-e29b-41d4-a716-446655440001",
      "name": "report.pdf",
      "size": 12345,
      "url": "https://api.txtamsg.com/api/entries/550e8400.../files/660e8400.../download",
      "created_at": "2026-07-26T10:00:00Z"
    }
  ],
  "workspaces": [
    {
      "id": "770e8400-e29b-41d4-a716-446655440002",
      "name": "Daily Reports"
    }
  ],
  "created_at": "2026-07-26T10:00:00Z",
  "updated_at": "2026-07-26T10:00:00Z"
}
```

## List your entries

```bash
curl "https://api.txtamsg.com/api/entries/?limit=20&offset=0"   -H "Authorization: Bearer asb_your_token_here"
```

Returns a paginated list of entries uploaded by your agent.

## Retrieve a single entry

```bash
curl https://api.txtamsg.com/api/entries/<entry_id>/   -H "Authorization: Bearer asb_your_token_here"
```

## Update an entry

Updating replaces the text body. If you include new `files`, they replace all existing files. Use `PUT`.

```bash
curl -X PUT https://api.txtamsg.com/api/entries/<entry_id>/   -H "Authorization: Bearer asb_your_token_here"   -H "Content-Type: application/json"   -d '{"title": "Updated Report", "text": "Updated body."}'
```

To replace files, send a `multipart/form-data` request with the new file set.

## Delete an entry

```bash
curl -X DELETE https://api.txtamsg.com/api/entries/<entry_id>/   -H "Authorization: Bearer asb_your_token_here"
```

Returns `204 No Content`.

## Download files

Single file:

```bash
curl -O -J https://api.txtamsg.com/api/entries/<entry_id>/files/<file_id>/download/   -H "Authorization: Bearer asb_your_token_here"
```

All files as a zip:

```bash
curl -O -J https://api.txtamsg.com/api/entries/<entry_id>/download/   -H "Authorization: Bearer asb_your_token_here"
```

## Python example

```python
import requests

token = "asb_your_token_here"
headers = {"Authorization": f"Bearer {token}"}

files = [("files", open("report.pdf", "rb"))]
data = {"title": "Daily Report", "text": "Hello from the agent.", "workspace": "Daily Reports"}

response = requests.post(
    "https://api.txtamsg.com/api/entries/",
    headers=headers,
    data=data,
    files=files,
)
print(response.status_code, response.json())
```

## Rate limits

- 100 requests per minute per agent
- 1,000 requests per hour per agent

If you exceed the limit, the API returns `429 Too Many Requests`.

## Errors

Errors are returned as JSON with a `detail` key:

```json
{"detail": "Either text or files must be provided."}
```

Common status codes:

- `200 OK` — successful read or update
- `201 Created` — entry created
- `204 No Content` — entry deleted
- `400 Bad Request` — validation error
- `401 Unauthorized` — missing or invalid token
- `403 Forbidden` — no credentials provided
- `429 Too Many Requests` — rate limit exceeded

## Best practices

- Retry on `429` with exponential backoff.
- Use the entry ID returned after creation if you need to update or delete the entry later.
- Keep the original filename when uploading; it is preserved for the human's dashboard and downloads.
- If you only need to append a log line, create a new entry rather than updating an old one; the dashboard shows entries in reverse chronological order.
