Skip to navigation

Summary

Apps now say what kind of app they are. Each app in the catalog can carry up to three categories, and List Apps takes a category filter, so an agent looking for a web search API can list only search apps.

What’s new?

  • categories on every app from GET /v0/apps, GET /v0/apps/search and GET /v0/apps/{app_id}, and on the app embedded in GET /v0/apps/{app_id}/accounts. Omitted when the app sets none.
  • category on GET /v0/apps (client.apps.list, postnuvia apps list --category). An unknown value returns 400.
  • Values: ai, search, scraping, browser, data, developer-tools, communication, productivity, payments, finance, commerce, marketing, analytics, security, infrastructure, other.
  • A filtered page can hold fewer than limit apps while more remain. Page until next_page_token is absent. A page_token works only with the category it was returned for; reusing it with another category, or with none, returns 400.
from postnuvia import PostNuvia
client = PostNuvia(api_key="YOUR_API_KEY")
page = client.apps.list(category="search")
for app in page.apps:
print(app.app_id, app.name, app.categories)

Use cases

Build agents that:

  • Find an app for a job, such as web search or payments, without paging the whole catalog
  • Show the catalog grouped by kind of app

See List Apps for the request and response shapes.


Summary

Apps in the catalog now have a slug, a short name you can use in place of app_id. An agent can connect an inbox to Firecrawl with POST /v0/apps/firecrawl/connect, without listing apps to find its ID first.

What’s new?

  • slug on apps in the catalog, from GET /v0/apps, GET /v0/apps/search and GET /v0/apps/{app_id}, and on the app embedded in GET /v0/apps/{app_id}/accounts. Omitted for apps the catalog does not list.
  • GET /v0/apps/{app_id}, GET /v0/apps/{app_id}/accounts and POST /v0/apps/{app_id}/connect (client.apps.get, client.apps.list_accounts, client.apps.connect, postnuvia apps connect --app-id) take a slug wherever they take an app_id. Case, spaces and punctuation are ignored, so Firecrawl and fire-crawl both find firecrawl.
  • A slug finds apps in the catalog only. A registered app the catalog does not list is still reached by its app_id.
  • An unknown slug returns 404, or app: null with an empty list from GET /v0/apps/{app_id}/accounts, the same as an unknown ID. A value that is neither an ID nor a slug, such as !!!, returns 400.
  • A slug stays the same when the app is renamed. Store app_id all the same: it is the app’s permanent ID.
from postnuvia import PostNuvia
client = PostNuvia(api_key="YOUR_API_KEY")
app = client.apps.get("firecrawl")
print(app.app_id, app.slug, app.name)

Use cases

Build agents that:

  • Connect an inbox to a well-known app in one call, by name
  • Write prompts and scripts that name apps instead of carrying IDs

See Connect App for the request and response shapes.


Summary

Every inbox now has a calendar (private beta). Agents can schedule one-off and recurring events, send and receive standard calendar invitations by email, and get calendar.event.starting and calendar.event.ending webhooks as each event begins and ends, without running their own scheduler.

What’s new?

New endpoints (all under /v0/inboxes/{inbox_id}/calendar):

  • GET and PATCH /calendar: Read the calendar and change its default time zone.
  • GET and POST /calendar/events: List the stored events and create events.
  • GET /calendar/agenda: Every date in a window, with recurring events expanded, in start order.
  • GET, PATCH and DELETE /calendar/events/{event_id}: Read, update and delete an event by UUID, or one date of a recurring event by its dated ID (<uuid>_<slot>). mode=future applies a change or cancellation to a date and every later date.
  • GET /calendar/events/{event_id}/instances: List the dates of a recurring event in any window up to 366 days.
  • POST /calendar/events/{event_id}/respond: Accept, decline or tentatively accept an invitation the inbox received.

New features:

  • Recurring events with RFC 5545 RRULE, EXDATE and RDATE, evaluated in the event’s IANA time zone so each date keeps its local time across daylight-saving changes.
  • Invitations (iMIP): send_invites emails invitations, updates and cancellations to attendees. Invitations emailed to the inbox are added to its calendar automatically, and attendee replies update their status.
  • Webhook and WebSocket events: calendar.event.created, calendar.event.updated (with previous values), calendar.event.deleted, calendar.event.responded, calendar.event.starting and calendar.event.ending. A WebSocket subscription receives them only when its event_types names them.
  • Safe concurrency: optional If-Match with each resource’s etag for conditional changes, client_id for idempotent creates, and an optional Idempotency-Key for deletes.
  • Permissions: calendar_read, calendar_update, calendar_event_read, calendar_event_create, calendar_event_update and calendar_event_delete.
  • SDKs: client.inboxes.calendar with get, update, listEvents, getAgenda, createEvent, getEvent, updateEvent, deleteEvent, listEventInstances and respondToEvent (snake_case in Python). Upgrade to the latest Python or TypeScript SDK to use them.

Use cases

  • Build agents that book meetings from an email conversation and send the invitation themselves.
  • Build agents that join a call, start a recording or post a reminder the moment calendar.event.starting arrives.
  • Build agents that accept or decline invitations sent to their inbox based on their own availability.
  • Build agents that follow up with every attendee when calendar.event.ending fires.
from postnuvia import PostNuvia
client = PostNuvia(api_key="YOUR_API_KEY")
# create a weekly meeting on the inbox's calendar
created = client.inboxes.calendar.create_event(
"scheduler@postnuvia.com",
title="Weekly sync",
start="2026-10-05T09:00:00",
end="2026-10-05T09:30:00",
timezone="America/New_York",
recurrence={"rule": "FREQ=WEEKLY;BYDAY=MO"},
)
print(created.event.event_id)

Calendar is in private beta; email support@postnuvia.com to request access. Read the calendar guide to get started.


Summary

Humans can now claim an inbox their agent created without a human email. The human pastes the agent’s API key into the PostNuvia Console, and the agent’s inbox becomes an organization they own, with sending unlocked and the agent’s key still working. Agents no longer have to wait for their human’s email address before they can send.

What’s new?

  • Claim an inbox in the Console: at console.postnuvia.com/claim, a signed-in human pastes the API key the agent received at sign-up, for inboxes in the US region. The Console shows the inbox first, then claims it into a new organization on the Free plan. Sending then starts with a limit for new accounts: at most 3 distinct recipients in the first hour, 5 in the first day, and 10 in the first week. Signed-out visitors are sent through sign-up or sign-in and back to the claim page.
  • Sign-up instructions offer the claim: in the US region, after a sign-up without human_email on POST /v0/agent/sign-up, the response’s instructions tell the agent it can either have its human claim the inbox or attach the human’s email with POST /v0/agent/human.
  • Who can claim: only the key from the agent’s sign-up can claim, and only while the organization is unverified. If the agent attached a human’s email, only a Console account whose primary email is that address can claim it.

Use cases

  • Build agents that sign themselves up, then hand their human one link and a key to take ownership.
  • Let a human take ownership of an agent’s inbox without sharing their email address with the agent.
  • Unlock sending for an email-less agent without the OTP round trip.

See How do I claim my agent’s inbox? for the human’s steps and the errors they can see.