Search the docs
Find a page, a section, or an endpoint.
SDKs
The TypeScript and Python clients, generated from one document.
Two clients, TypeScript and Python, both generated from
openapi.json — which is itself generated
from the schemas the API validates with. An operation has the same name in
both, because both take it from the same field.
npm install @pidgeon-ai/sdkThe Python package needs Python 3.11 or later.
Configure once
import { client } from '@pidgeon-ai/sdk';
client.setConfig({ auth: () => process.env.PIDGEON_API_KEY! });TypeScript has a module-level client the functions use when you do not pass one; Python threads it through each call. That difference is each language's idiom rather than a disagreement about the API.
Call an operation
import { messagesSend } from '@pidgeon-ai/sdk';
const { data, error } = await messagesSend({
body: {
from: 'you@yourdomain.com',
to: 'someone@example.com',
subject: 'First one',
text: 'It works.',
},
});messagesSend and messages_send are the same operation. Every one is named
this way, so a method you find in one language tells you what to look for in
the other.
Errors
TypeScript answers, it does not throw. A call returns { data, error, response }, and error carries the API's own code and message. Pass
throwOnError: true on a call that should raise instead.
const { data, error } = await identitiesGet({ path: { id } });
if (error) {
console.error(error.error.code, error.error.message);
}Python raises. Any failure, a status of 400 or above, raises
PidgeonError, whether the contract declares that status or not. A call
returns its success model or does not return, so a refused send cannot pass
for a sent one. code is the API's own and is what to branch on; message
is safe to show a person; retry_after is in seconds when a limit says when
to come back.
from pidgeon.errors import PidgeonError
try:
result = identities_get.sync(client=client, id=identity_id)
print(result.data)
except PidgeonError as error:
print(error.status_code, error.code, error.message)Before 1.19.0 a declared failure came back as an Error and an undeclared one
as None; a 403 on a send was one of the second kind, and a site read it
as sent.
Verifying a webhook
The one thing in the TypeScript package that is written rather than generated, because HMAC is a security contract and not an endpoint:
import { verifyWebhook } from '@pidgeon-ai/sdk';
const event = await verifyWebhook({
rawBody: await request.text(),
headers: request.headers,
secret: process.env.PIDGEON_WEBHOOK_SECRET!,
});The Python package ships the same thing — pidgeon.webhooks.verify_webhook,
keyword arguments, raising WebhookVerificationError rather than returning a
boolean nobody checks. Verifying a signature has
both, and the three ways to get it wrong by hand.
What message/rfc822 does in Python
GET /messages/{id}/raw returns the original message rather than JSON, and
the Python generator will not parse a non-JSON body. The call works: the
bytes are on .content, and .parsed is None.