One document, three SDKs

Every SDK is generated from the API's OpenAPI document (openapi.json), so it never lags the API, and every one is tested against the API on each change. Operation ids in the API reference name the same operation in every SDK:

TypeScript Python Go
Package @minket/sdk (packages/sdk) minket (sdks/python) github.com/blawand/minket/sdks/go/minket
sendEmail becomes minket.emails.send(body) minket.api.emails.send_email.sync(client=…, body=…) client.SendEmailWithResponse(ctx, body)
Regenerate pnpm generate bash sdks/python/generate.sh bash sdks/go/generate.sh

TypeScript

TypeScript
import { Minket } from "@minket/sdk";

const minket = new Minket({ apiKey: process.env.MINKET_API_KEY ?? "" });

const sent = await minket.emails.send({
  from: "Acme <billing@mail.acme.example>",
  to: "jane@example.com",
  subject: "Your receipt for order 10452",
  text: "Thanks, Jane.",
  tags: [{ name: "type", value: "receipt" }],
});
// sent.id, sent.status ("queued"), sent.idempotent_replay

const email = await minket.emails.get(sent.id);
const bounces = await minket.events.list({ types: "email.bounced", limit: 50 });

The guides' TypeScript samples use this minket. baseUrl points it at another API address. Resource methods follow the API's groups: emails, uploads, attachments, templates, domains, webhooks, events, inbound (with inbound.routes), mailboxes, suppressions, contacts (with contacts.imports and contacts.properties), segments (with segments.contacts), topics, broadcasts, automations, keys, logs and members. Path parameters come first, then the body or the query, then options: minket.webhooks.replay(id, { since }), minket.contacts.get("jane@example.com"). Each returns the typed success body; the operation table names the method for every operation.

Idempotency

Every POST carries an Idempotency-Key: a fresh UUIDv7 unless you give one, so a retry by a proxy or a network layer can never send twice. To retry safely yourself, pass the same key again (Idempotency):

TypeScript
await minket.emails.send(receipt, { idempotencyKey: `receipt-${order.id}` });

A key in the body (idempotency_key) is sent as the header too, since the API prefers the header.

Errors

Every failure throws MinketError:

TypeScript
import { isMinketError } from "@minket/sdk";

try {
  await minket.emails.send(receipt, { idempotencyKey });
} catch (error) {
  if (isMinketError(error) && error.retryable) {
    // safe to retry with the same idempotency key, after error.retryAfterSeconds if set
  }
  throw error;
}
Property
code The API's error code (validation_error, not_found, ...), or network_error when no response arrived and unexpected_response for a body that is not the API's
status HTTP status, 0 without a response
message What happened and what to do next
retryable True when the same request with the same idempotency key can succeed
requestId The request's id, for minket.logs.list() and support
issues Validation issues: [{ path: "to.0", message }]
retryAfterSeconds From retry-after, on rate limits and in-flight idempotency keys

error.toJSON() gives the snake_case wire shape for logs; it never contains request content.

Files and lists

minket.uploads.upload({ purpose, filename, content_type, content }) creates a presigned upload, stores the bytes (without the API key) and returns the completed upload, ready for minket.attachments.create({ upload_id }) or minket.contacts.import({ upload_id }). Use it for attachments and imports above 4 MB.

paginate walks a list with its after cursor:

TypeScript
import { paginate } from "@minket/sdk";

for await (const entry of paginate((cursor) => minket.suppressions.list({ ...cursor, reason: "hard_bounce" }))) {
  console.log(entry.email);
}

Any operation, and the raw client

minket.request(operationId, { path, query, body }) calls any operation by its id, typed from the document, with the same auth, idempotency and errors. The generated functions are exported too, for code that prefers { data, error } results to exceptions:

TypeScript
import { createMinketClient, getEmail } from "@minket/sdk";

const client = createMinketClient({ apiKey: process.env.MINKET_API_KEY ?? "" });
const { data, error, response } = await getEmail({ client, path: { id } });

verifyWebhook is exported for receivers (Verify signatures). Pass your own fetch to new Minket({ fetch }) in tests.

Python

bash sdks/python/generate.sh writes the project to sdks/python/minket; install it with pip install ./sdks/python/minket. Every operation is a module under minket.api.<group> with sync, sync_detailed, asyncio and asyncio_detailed; the detailed variants return the status code, headers and parsed body, and error statuses parse into ApiError.

Python
import os

from minket import AuthenticatedClient
from minket.api.emails import get_email, send_email
from minket.models import ApiError, SendEmailRequest

base_url = "https://api.minket.com"
token = os.environ["MINKET_API_KEY"]
client = AuthenticatedClient(base_url=base_url, token=token)

# A client per idempotency key: with_headers() also changes a client that has made a request.
keyed = AuthenticatedClient(base_url=base_url, token=token, headers={"Idempotency-Key": "receipt-10452"})
sent = send_email.sync_detailed(
    client=keyed,
    body=SendEmailRequest(
        from_="Acme <billing@mail.acme.example>",
        to=["jane@example.com"],
        subject="Your receipt for order 10452",
        text="Thanks, Jane.",
    ),
)
if isinstance(sent.parsed, ApiError):
    print(sent.parsed.error.code, sent.parsed.error.retryable)
else:
    email = get_email.sync(sent.parsed.id, client=client)

from is from_ because it is a keyword. Path parameters are positional, query parameters keyword arguments, and bodies model instances (or Model.from_dict({...})).

Go

bash sdks/go/generate.sh writes package minket (client.gen.go): a typed client with request and response types for every operation. Add the bearer token and an idempotency key with a request editor:

Go
client, err := minket.NewClientWithResponses(
	"https://api.minket.com",
	minket.WithRequestEditorFn(func(ctx context.Context, req *http.Request) error {
		req.Header.Set("Authorization", "Bearer "+os.Getenv("MINKET_API_KEY"))
		if req.Method == http.MethodPost && req.Header.Get("Idempotency-Key") == "" {
			req.Header.Set("Idempotency-Key", newKey())
		}
		return nil
	}),
)
if err != nil {
	return err
}

var to minket.SendEmailRequest_To
_ = to.FromSendEmailRequestTo1([]string{"jane@example.com"})
from, subject, text := "Acme <billing@mail.acme.example>", "Your receipt", "Thanks, Jane."
res, err := client.SendEmailWithResponse(ctx, minket.SendEmailRequest{From: &from, To: to, Subject: &subject, Text: &text})
if err != nil {
	return err
}
if res.JSON200 != nil {
	fmt.Println(res.JSON200.Id, res.JSON200.Status)
} else if res.JSON422 != nil {
	fmt.Println(res.JSON422.Error.Code, res.JSON422.Error.Message)
}

Response structs carry one field per documented status (JSON200, JSON404, ...), so error bodies are typed. Fields that take one address or a list are unions set with From...To0 (a string) or From...To1 (a slice).

Operations

Every operation in the current document, by group, with its name in each SDK. The operation links to its reference entry.

Emails

OperationTypeScriptPythonGo
getEmailMetricsminket.emails.metricsminket.api.emails.get_email_metricsGetEmailMetricsWithResponse
sendEmailminket.emails.sendminket.api.emails.send_emailSendEmailWithResponse
listEmailsminket.emails.listminket.api.emails.list_emailsListEmailsWithResponse
sendBatchminket.emails.sendBatchminket.api.emails.send_batchSendBatchWithResponse
getEmailminket.emails.getminket.api.emails.get_emailGetEmailWithResponse
rescheduleEmailminket.emails.rescheduleminket.api.emails.reschedule_emailRescheduleEmailWithResponse
cancelEmailminket.emails.cancelminket.api.emails.cancel_emailCancelEmailWithResponse
listEmailEventsminket.emails.eventsminket.api.emails.list_email_eventsListEmailEventsWithResponse
listEmailAttachmentsminket.emails.attachmentsminket.api.emails.list_email_attachmentsListEmailAttachmentsWithResponse
shareEmailminket.emails.shareminket.api.emails.share_emailShareEmailWithResponse

Attachments

OperationTypeScriptPythonGo
createAttachmentminket.attachments.createminket.api.attachments.create_attachmentCreateAttachmentWithResponse
listAttachmentsminket.attachments.listminket.api.attachments.list_attachmentsListAttachmentsWithResponse
getAttachmentminket.attachments.getminket.api.attachments.get_attachmentGetAttachmentWithResponse
deleteAttachmentminket.attachments.deleteminket.api.attachments.delete_attachmentDeleteAttachmentWithResponse

Uploads

OperationTypeScriptPythonGo
createUploadminket.uploads.createminket.api.uploads.create_uploadCreateUploadWithResponse
getUploadminket.uploads.getminket.api.uploads.get_uploadGetUploadWithResponse

Templates

OperationTypeScriptPythonGo
createTemplateminket.templates.createminket.api.templates.create_templateCreateTemplateWithResponse
listTemplatesminket.templates.listminket.api.templates.list_templatesListTemplatesWithResponse
getTemplateminket.templates.getminket.api.templates.get_templateGetTemplateWithResponse
updateTemplateminket.templates.updateminket.api.templates.update_templateUpdateTemplateWithResponse
deleteTemplateminket.templates.deleteminket.api.templates.delete_templateDeleteTemplateWithResponse
publishTemplateminket.templates.publishminket.api.templates.publish_templatePublishTemplateWithResponse
duplicateTemplateminket.templates.duplicateminket.api.templates.duplicate_templateDuplicateTemplateWithResponse
listTemplateVersionsminket.templates.versionsminket.api.templates.list_template_versionsListTemplateVersionsWithResponse
getTemplateVersionminket.templates.versionminket.api.templates.get_template_versionGetTemplateVersionWithResponse
previewTemplateminket.templates.previewminket.api.templates.preview_templatePreviewTemplateWithResponse

Domains

OperationTypeScriptPythonGo
createDomainminket.domains.createminket.api.domains.create_domainCreateDomainWithResponse
listDomainsminket.domains.listminket.api.domains.list_domainsListDomainsWithResponse
getDomainminket.domains.getminket.api.domains.get_domainGetDomainWithResponse
updateDomainminket.domains.updateminket.api.domains.update_domainUpdateDomainWithResponse
deleteDomainminket.domains.deleteminket.api.domains.delete_domainDeleteDomainWithResponse
verifyDomainminket.domains.verifyminket.api.domains.verify_domainVerifyDomainWithResponse
listDomainDmarcReportsminket.domains.dmarcReportsminket.api.domains.list_domain_dmarc_reportsListDomainDmarcReportsWithResponse
getDomainReputationminket.domains.reputationminket.api.domains.get_domain_reputationGetDomainReputationWithResponse
runSeedTestminket.domains.seedTestminket.api.domains.run_seed_testRunSeedTestWithResponse

Webhooks

OperationTypeScriptPythonGo
createWebhookminket.webhooks.createminket.api.webhooks.create_webhookCreateWebhookWithResponse
listWebhooksminket.webhooks.listminket.api.webhooks.list_webhooksListWebhooksWithResponse
getWebhookminket.webhooks.getminket.api.webhooks.get_webhookGetWebhookWithResponse
updateWebhookminket.webhooks.updateminket.api.webhooks.update_webhookUpdateWebhookWithResponse
deleteWebhookminket.webhooks.deleteminket.api.webhooks.delete_webhookDeleteWebhookWithResponse
rotateWebhookSecretminket.webhooks.rotateSecretminket.api.webhooks.rotate_webhook_secretRotateWebhookSecretWithResponse
listWebhookDeliveriesminket.webhooks.deliveriesminket.api.webhooks.list_webhook_deliveriesListWebhookDeliveriesWithResponse
getWebhookDeliveryminket.webhooks.deliveryminket.api.webhooks.get_webhook_deliveryGetWebhookDeliveryWithResponse
replayWebhookDeliveriesminket.webhooks.replayminket.api.webhooks.replay_webhook_deliveriesReplayWebhookDeliveriesWithResponse
testWebhookminket.webhooks.testminket.api.webhooks.test_webhookTestWebhookWithResponse

Events

OperationTypeScriptPythonGo
listEventsminket.events.listminket.api.events.list_eventsListEventsWithResponse
getEventminket.events.getminket.api.events.get_eventGetEventWithResponse

Inbound

OperationTypeScriptPythonGo
listInboundRoutesminket.inbound.routes.listminket.api.inbound.list_inbound_routesListInboundRoutesWithResponse
createInboundRouteminket.inbound.routes.createminket.api.inbound.create_inbound_routeCreateInboundRouteWithResponse
updateInboundRouteminket.inbound.routes.updateminket.api.inbound.update_inbound_routeUpdateInboundRouteWithResponse
deleteInboundRouteminket.inbound.routes.deleteminket.api.inbound.delete_inbound_routeDeleteInboundRouteWithResponse
listInboundminket.inbound.listminket.api.inbound.list_inboundListInboundWithResponse
getInboundminket.inbound.getminket.api.inbound.get_inboundGetInboundWithResponse
listInboundAttachmentsminket.inbound.attachmentsminket.api.inbound.list_inbound_attachmentsListInboundAttachmentsWithResponse
getInboundAttachmentminket.inbound.attachmentminket.api.inbound.get_inbound_attachmentGetInboundAttachmentWithResponse
forwardInboundminket.inbound.forwardminket.api.inbound.forward_inboundForwardInboundWithResponse
shareInboundminket.inbound.shareminket.api.inbound.share_inboundShareInboundWithResponse

Mailboxes

OperationTypeScriptPythonGo
listMailboxesminket.mailboxes.listminket.api.mailboxes.list_mailboxesListMailboxesWithResponse
createMailboxminket.mailboxes.createminket.api.mailboxes.create_mailboxCreateMailboxWithResponse
getMailboxminket.mailboxes.getminket.api.mailboxes.get_mailboxGetMailboxWithResponse
deleteMailboxminket.mailboxes.deleteminket.api.mailboxes.delete_mailboxDeleteMailboxWithResponse

Suppressions

OperationTypeScriptPythonGo
listSuppressionsminket.suppressions.listminket.api.suppressions.list_suppressionsListSuppressionsWithResponse
createSuppressionminket.suppressions.createminket.api.suppressions.create_suppressionCreateSuppressionWithResponse
deleteSuppressionminket.suppressions.deleteminket.api.suppressions.delete_suppressionDeleteSuppressionWithResponse

Contacts

OperationTypeScriptPythonGo
createContactminket.contacts.createminket.api.contacts.create_contactCreateContactWithResponse
listContactsminket.contacts.listminket.api.contacts.list_contactsListContactsWithResponse
importContactsminket.contacts.importminket.api.contacts.import_contactsImportContactsWithResponse
listImportsminket.contacts.imports.listminket.api.contacts.list_importsListImportsWithResponse
getImportminket.contacts.imports.getminket.api.contacts.get_importGetImportWithResponse
exportContactsminket.contacts.exportminket.api.contacts.export_contactsExportContactsWithResponse
sendContactEventminket.contacts.sendEventminket.api.contacts.send_contact_eventSendContactEventWithResponse
listContactPropertiesminket.contacts.properties.listminket.api.contacts.list_contact_propertiesListContactPropertiesWithResponse
createContactPropertyminket.contacts.properties.createminket.api.contacts.create_contact_propertyCreateContactPropertyWithResponse
deleteContactPropertyminket.contacts.properties.deleteminket.api.contacts.delete_contact_propertyDeleteContactPropertyWithResponse
getContactminket.contacts.getminket.api.contacts.get_contactGetContactWithResponse
updateContactminket.contacts.updateminket.api.contacts.update_contactUpdateContactWithResponse
deleteContactminket.contacts.deleteminket.api.contacts.delete_contactDeleteContactWithResponse
listContactConsentminket.contacts.consentminket.api.contacts.list_contact_consentListContactConsentWithResponse
sendContactOptinminket.contacts.optinminket.api.contacts.send_contact_optinSendContactOptinWithResponse

Segments

OperationTypeScriptPythonGo
createSegmentminket.segments.createminket.api.segments.create_segmentCreateSegmentWithResponse
listSegmentsminket.segments.listminket.api.segments.list_segmentsListSegmentsWithResponse
getSegmentminket.segments.getminket.api.segments.get_segmentGetSegmentWithResponse
updateSegmentminket.segments.updateminket.api.segments.update_segmentUpdateSegmentWithResponse
deleteSegmentminket.segments.deleteminket.api.segments.delete_segmentDeleteSegmentWithResponse
listSegmentContactsminket.segments.contacts.listminket.api.segments.list_segment_contactsListSegmentContactsWithResponse
addSegmentContactsminket.segments.contacts.addminket.api.segments.add_segment_contactsAddSegmentContactsWithResponse
removeSegmentContactsminket.segments.contacts.removeminket.api.segments.remove_segment_contactsRemoveSegmentContactsWithResponse

Topics

OperationTypeScriptPythonGo
createTopicminket.topics.createminket.api.topics.create_topicCreateTopicWithResponse
listTopicsminket.topics.listminket.api.topics.list_topicsListTopicsWithResponse
getTopicminket.topics.getminket.api.topics.get_topicGetTopicWithResponse
updateTopicminket.topics.updateminket.api.topics.update_topicUpdateTopicWithResponse
deleteTopicminket.topics.deleteminket.api.topics.delete_topicDeleteTopicWithResponse

Broadcasts

OperationTypeScriptPythonGo
createBroadcastminket.broadcasts.createminket.api.broadcasts.create_broadcastCreateBroadcastWithResponse
listBroadcastsminket.broadcasts.listminket.api.broadcasts.list_broadcastsListBroadcastsWithResponse
getBroadcastminket.broadcasts.getminket.api.broadcasts.get_broadcastGetBroadcastWithResponse
updateBroadcastminket.broadcasts.updateminket.api.broadcasts.update_broadcastUpdateBroadcastWithResponse
deleteBroadcastminket.broadcasts.deleteminket.api.broadcasts.delete_broadcastDeleteBroadcastWithResponse
sendBroadcastminket.broadcasts.sendminket.api.broadcasts.send_broadcastSendBroadcastWithResponse
cancelBroadcastminket.broadcasts.cancelminket.api.broadcasts.cancel_broadcastCancelBroadcastWithResponse
duplicateBroadcastminket.broadcasts.duplicateminket.api.broadcasts.duplicate_broadcastDuplicateBroadcastWithResponse
testBroadcastminket.broadcasts.testminket.api.broadcasts.test_broadcastTestBroadcastWithResponse
listBroadcastRecipientsminket.broadcasts.recipientsminket.api.broadcasts.list_broadcast_recipientsListBroadcastRecipientsWithResponse
listBroadcastLinksminket.broadcasts.linksminket.api.broadcasts.list_broadcast_linksListBroadcastLinksWithResponse

Automations

OperationTypeScriptPythonGo
createAutomationminket.automations.createminket.api.automations.create_automationCreateAutomationWithResponse
listAutomationsminket.automations.listminket.api.automations.list_automationsListAutomationsWithResponse
getAutomationminket.automations.getminket.api.automations.get_automationGetAutomationWithResponse
updateAutomationminket.automations.updateminket.api.automations.update_automationUpdateAutomationWithResponse
deleteAutomationminket.automations.deleteminket.api.automations.delete_automationDeleteAutomationWithResponse
publishAutomationminket.automations.publishminket.api.automations.publish_automationPublishAutomationWithResponse
stopAutomationminket.automations.stopminket.api.automations.stop_automationStopAutomationWithResponse
duplicateAutomationminket.automations.duplicateminket.api.automations.duplicate_automationDuplicateAutomationWithResponse
listAutomationVersionsminket.automations.versionsminket.api.automations.list_automation_versionsListAutomationVersionsWithResponse
listAutomationRunsminket.automations.runsminket.api.automations.list_automation_runsListAutomationRunsWithResponse
getAutomationRunminket.automations.runminket.api.automations.get_automation_runGetAutomationRunWithResponse

Keys

OperationTypeScriptPythonGo
listKeysminket.keys.listminket.api.keys.list_keysListKeysWithResponse
createKeyminket.keys.createminket.api.keys.create_keyCreateKeyWithResponse
getCurrentKeyminket.keys.currentminket.api.keys.get_current_keyGetCurrentKeyWithResponse
revokeKeyminket.keys.revokeminket.api.keys.revoke_keyRevokeKeyWithResponse

Logs

OperationTypeScriptPythonGo
listLogsminket.logs.listminket.api.logs.list_logsListLogsWithResponse
getLogminket.logs.getminket.api.logs.get_logGetLogWithResponse

Members

OperationTypeScriptPythonGo
listMembersminket.members.listminket.api.members.list_membersListMembersWithResponse

Updated