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/sdk

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.

ts
const { data, error } = await identitiesGet({ path: { id } });

if (error) {
console.error(error.error.code, error.error.message);
}

Python raises on an unexpected status and otherwise returns the parsed body, or None where the response has no JSON to parse.

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:

ts
import { verifyWebhook } from '@pidgeon-ai/sdk';

const event = await verifyWebhook({
rawBody: await request.text(),
headers: request.headers,
secret: process.env.PIDGEON_WEBHOOK_SECRET!,
});

Verifying a signature has the whole of it, including what to do in Python, where the package does not ship a verifier.

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.