Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
lint:
timeout-minutes: 10
name: lint
runs-on: ${{ github.repository == 'stainless-sdks/blooio-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata')
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
Expand All @@ -41,7 +41,7 @@ jobs:
permissions:
contents: read
id-token: write
runs-on: ${{ github.repository == 'stainless-sdks/blooio-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

Expand Down Expand Up @@ -78,7 +78,7 @@ jobs:
test:
timeout-minutes: 10
name: test
runs-on: ${{ github.repository == 'stainless-sdks/blooio-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
Expand Down
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "1.2.0"
".": "1.3.0"
}
4 changes: 2 additions & 2 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 54
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/blooio/blooio-bce90b321b6782841d7834e0e0689b1812ef1f10f8f2823cd9908185d9f306e6.yml
openapi_spec_hash: a90c7586ed5e83a938d72a286efa9f8e
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/blooio/blooio-4cfd8aadba2015ef9746f076452ef853f194ce40602854c29ce76842eff021a9.yml
openapi_spec_hash: 8137fd23f3a30da82f83a8ac74a433f8
config_hash: 839e191496287972d18d39dcab8b19b7
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
# Changelog

## 1.3.0 (2026-07-25)

Full Changelog: [v1.2.0...v1.3.0](https://github.com/Blooio/blooio-python-sdk/compare/v1.2.0...v1.3.0)

### Features

* **api:** api update ([30e8dd1](https://github.com/Blooio/blooio-python-sdk/commit/30e8dd13b8e2ca5988573a2cc482c122ea1650ae))
* **api:** api update ([f6caf8e](https://github.com/Blooio/blooio-python-sdk/commit/f6caf8e2ab1630818c57ab8142a5107cc534c57c))
* **api:** api update ([b3ba795](https://github.com/Blooio/blooio-python-sdk/commit/b3ba7951d022e732ae0e3a458520ed3f42a49a5f))
* **api:** api update ([d9b82ea](https://github.com/Blooio/blooio-python-sdk/commit/d9b82ea21659239202fb8a4d63366d54ea60fcbe))
* **api:** api update ([2e075ad](https://github.com/Blooio/blooio-python-sdk/commit/2e075ad61159d021fc31bd6fda9f0152ea703a34))
* **api:** api update ([178129e](https://github.com/Blooio/blooio-python-sdk/commit/178129ec16b48bb7be95b672071147fb1a4bf679))
* **api:** api update ([03aecef](https://github.com/Blooio/blooio-python-sdk/commit/03aecefb518d40f36c37d71cfa7637cefb0575c4))
* **api:** api update ([e4708cb](https://github.com/Blooio/blooio-python-sdk/commit/e4708cb01510e75961ac6a058308140cf69424ee))
* **api:** api update ([bb8074b](https://github.com/Blooio/blooio-python-sdk/commit/bb8074b817bc550cba91e705ebbd710dee71caba))
* **stlc:** configurable CI runner and private-production-repo support in workflow templates ([33ac236](https://github.com/Blooio/blooio-python-sdk/commit/33ac236b6e204193681f2db4822517a0de75b182))


### Bug Fixes

* **auth:** prioritize first auth header ([d692d48](https://github.com/Blooio/blooio-python-sdk/commit/d692d48a74bebaa8b86c6e645941c85ebab88c2e))
* **internal:** resolve build failures ([12fb122](https://github.com/Blooio/blooio-python-sdk/commit/12fb122bc963ca30ba0d2767352d2f3fde733bfb))

## 1.2.0 (2026-05-14)

Full Changelog: [v1.1.1...v1.2.0](https://github.com/Blooio/blooio-python-sdk/compare/v1.1.1...v1.2.0)
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "blooio"
version = "1.2.0"
version = "1.3.0"
description = "The official Python library for the blooio API"
dynamic = ["readme"]
license = "Apache-2.0"
Expand Down
2 changes: 1 addition & 1 deletion scripts/lint
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ else
fi

echo "==> Running pyright"
uv run pyright
uv run pyright -p .

echo "==> Running mypy"
uv run mypy .
Expand Down
16 changes: 10 additions & 6 deletions src/blooio/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,11 @@ def qs(self) -> Querystring:

@override
def _auth_headers(self, security: SecurityOptions) -> dict[str, str]:
return {
**(self._bearer_auth if security.get("bearer_auth", False) else {}),
}
headers: dict[str, str] = {}
if security.get("bearer_auth", False):
for key, value in self._bearer_auth.items():
headers.setdefault(key, value)
return headers

@property
def _bearer_auth(self) -> dict[str, str]:
Expand Down Expand Up @@ -424,9 +426,11 @@ def qs(self) -> Querystring:

@override
def _auth_headers(self, security: SecurityOptions) -> dict[str, str]:
return {
**(self._bearer_auth if security.get("bearer_auth", False) else {}),
}
headers: dict[str, str] = {}
if security.get("bearer_auth", False):
for key, value in self._bearer_auth.items():
headers.setdefault(key, value)
return headers

@property
def _bearer_auth(self) -> dict[str, str]:
Expand Down
2 changes: 1 addition & 1 deletion src/blooio/_version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

__title__ = "blooio"
__version__ = "1.2.0" # x-release-please-version
__version__ = "1.3.0" # x-release-please-version
50 changes: 40 additions & 10 deletions src/blooio/resources/chats/background.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@


class BackgroundResource(SyncAPIResource):
"""Set, get, and remove conversation backgrounds"""
"""View conversations and messages"""

@cached_property
def with_raw_response(self) -> BackgroundResourceWithRawResponse:
Expand Down Expand Up @@ -132,12 +132,27 @@ def set(
Works for both 1-on-1 and
group chats.

The uploaded image is converted into a PosterKit-compatible archive and applied
to the iMessage conversation on the linked device. Supported formats: JPEG, PNG,
GIF, WebP, HEIC/HEIF. Maximum file size: 10 MB.
The request body must be `multipart/form-data` with a single `background` field
containing the **raw image file bytes** (not a URL or base64 string). Supported
formats: JPEG, PNG, GIF, WebP, HEIC/HEIF. Maximum file size: 10 MB.

**Example with curl** — note the `@` prefix that tells curl to read the file
from disk:

```bash
curl -X PUT "https://api.blooio.com/v2/api/chats/%2B15551234567/background" \\
-H "Authorization: Bearer YOUR_API_KEY" \\
-F "background=@/path/to/image.jpg;type=image/jpeg"
```

When the chat id is a phone number, percent-encode the leading `+` as `%2B` in
the URL path.

Args:
background: The image file to set as the chat background
background: Binary image file upload (JPEG, PNG, GIF, WebP, HEIC/HEIF, max 10 MB). Send as a
file field in `multipart/form-data` — e.g. `-F "background=@/path/to/image.jpg"`
with curl, or a `File`/`Blob` appended to `FormData` in JavaScript. Do NOT send
a URL or base64 string.

extra_headers: Send extra headers

Expand Down Expand Up @@ -167,7 +182,7 @@ def set(


class AsyncBackgroundResource(AsyncAPIResource):
"""Set, get, and remove conversation backgrounds"""
"""View conversations and messages"""

@cached_property
def with_raw_response(self) -> AsyncBackgroundResourceWithRawResponse:
Expand Down Expand Up @@ -274,12 +289,27 @@ async def set(
Works for both 1-on-1 and
group chats.

The uploaded image is converted into a PosterKit-compatible archive and applied
to the iMessage conversation on the linked device. Supported formats: JPEG, PNG,
GIF, WebP, HEIC/HEIF. Maximum file size: 10 MB.
The request body must be `multipart/form-data` with a single `background` field
containing the **raw image file bytes** (not a URL or base64 string). Supported
formats: JPEG, PNG, GIF, WebP, HEIC/HEIF. Maximum file size: 10 MB.

**Example with curl** — note the `@` prefix that tells curl to read the file
from disk:

```bash
curl -X PUT "https://api.blooio.com/v2/api/chats/%2B15551234567/background" \\
-H "Authorization: Bearer YOUR_API_KEY" \\
-F "background=@/path/to/image.jpg;type=image/jpeg"
```

When the chat id is a phone number, percent-encode the leading `+` as `%2B` in
the URL path.

Args:
background: The image file to set as the chat background
background: Binary image file upload (JPEG, PNG, GIF, WebP, HEIC/HEIF, max 10 MB). Send as a
file field in `multipart/form-data` — e.g. `-F "background=@/path/to/image.jpg"`
with curl, or a `File`/`Blob` appended to `FormData` in JavaScript. Do NOT send
a URL or base64 string.

extra_headers: Send extra headers

Expand Down
36 changes: 26 additions & 10 deletions src/blooio/resources/chats/chats.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def typing(self) -> TypingResource:

@cached_property
def background(self) -> BackgroundResource:
"""Set, get, and remove conversation backgrounds"""
"""View conversations and messages"""
return BackgroundResource(self._client)

@cached_property
Expand Down Expand Up @@ -152,9 +152,13 @@ def list(
message.

Args:
limit: Maximum number of items to return (1-200)
limit: Maximum number of items to return in a single response. Must be between 1 and
200; defaults to 50. Use together with `offset` to page through large result
sets.

offset: Number of items to skip
offset: Number of items to skip before returning results. Combine with `limit` for
page-based pagination (e.g. `offset=50&limit=50` returns the second page).
Defaults to 0.

q: Search query (matches phone/email or contact name)

Expand Down Expand Up @@ -239,6 +243,10 @@ def share_contact_card(
will be piggybacked onto the next outgoing message (text or attachment) sent to
this chat. This is idempotent — calling it multiple times is harmless.

⚠️ **Plan requirement:** Contact card sharing is only available on **Dedicated
Commercial** and **Dedicated Enterprise** plans. Numbers on other plans receive
a `403`.

Args:
extra_headers: Send extra headers

Expand Down Expand Up @@ -279,7 +287,7 @@ def typing(self) -> AsyncTypingResource:

@cached_property
def background(self) -> AsyncBackgroundResource:
"""Set, get, and remove conversation backgrounds"""
"""View conversations and messages"""
return AsyncBackgroundResource(self._client)

@cached_property
Expand Down Expand Up @@ -353,9 +361,13 @@ async def list(
message.

Args:
limit: Maximum number of items to return (1-200)
limit: Maximum number of items to return in a single response. Must be between 1 and
200; defaults to 50. Use together with `offset` to page through large result
sets.

offset: Number of items to skip
offset: Number of items to skip before returning results. Combine with `limit` for
page-based pagination (e.g. `offset=50&limit=50` returns the second page).
Defaults to 0.

q: Search query (matches phone/email or contact name)

Expand Down Expand Up @@ -440,6 +452,10 @@ async def share_contact_card(
will be piggybacked onto the next outgoing message (text or attachment) sent to
this chat. This is idempotent — calling it multiple times is harmless.

⚠️ **Plan requirement:** Contact card sharing is only available on **Dedicated
Commercial** and **Dedicated Enterprise** plans. Numbers on other plans receive
a `403`.

Args:
extra_headers: Send extra headers

Expand Down Expand Up @@ -496,7 +512,7 @@ def typing(self) -> TypingResourceWithRawResponse:

@cached_property
def background(self) -> BackgroundResourceWithRawResponse:
"""Set, get, and remove conversation backgrounds"""
"""View conversations and messages"""
return BackgroundResourceWithRawResponse(self._chats.background)


Expand Down Expand Up @@ -536,7 +552,7 @@ def typing(self) -> AsyncTypingResourceWithRawResponse:

@cached_property
def background(self) -> AsyncBackgroundResourceWithRawResponse:
"""Set, get, and remove conversation backgrounds"""
"""View conversations and messages"""
return AsyncBackgroundResourceWithRawResponse(self._chats.background)


Expand Down Expand Up @@ -576,7 +592,7 @@ def typing(self) -> TypingResourceWithStreamingResponse:

@cached_property
def background(self) -> BackgroundResourceWithStreamingResponse:
"""Set, get, and remove conversation backgrounds"""
"""View conversations and messages"""
return BackgroundResourceWithStreamingResponse(self._chats.background)


Expand Down Expand Up @@ -616,5 +632,5 @@ def typing(self) -> AsyncTypingResourceWithStreamingResponse:

@cached_property
def background(self) -> AsyncBackgroundResourceWithStreamingResponse:
"""Set, get, and remove conversation backgrounds"""
"""View conversations and messages"""
return AsyncBackgroundResourceWithStreamingResponse(self._chats.background)
Loading
Loading