Skip to content

Mailbox API · Beta

Send and read mail

The Mailbox API lets you send and read mail from the mailboxes you own on builders.ac. It speaks Microsoft Graph, so if you already have a Graph client you keep it — you change the base URL and the credential, and nothing else.

Mailbox APIv1beta1Beta
Base URL
https://api.builders.ac/api/mailbox/v1beta1
API Key
age1…The shared builders.ac API Key. Send it as a bearer token.

Create a shared builders.ac API credential from the API credentials page. Use its age1… API Key as the bearer token. The matching API Secret stays local and is not used by the Mailbox API.

Every request goes to:

https://api.builders.ac/api/mailbox/v1beta1

The Graph surface lives under /azure/v1.0. Authenticate with your key as a bearer token:

Authorization: Bearer age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Most Graph SDKs only attach the bearer token to hosts they trust. Pointed at another base URL they send the request unauthenticated, and you get a 401 that looks like a bad key. Tell the SDK to trust our host:

import { Client } from '@microsoft/microsoft-graph-client';
const client = Client.init({
baseUrl: 'https://api.builders.ac/api/mailbox/v1beta1/azure',
defaultVersion: 'v1.0',
authProvider: (done) => done(null, process.env.BUILDERS_API_KEY),
// Required. Without this the SDK omits your key and every call returns 401.
customHosts: new Set(['api.builders.ac']),
});
var http = new HttpClient {
BaseAddress = new Uri("https://api.builders.ac/api/mailbox/v1beta1/azure/v1.0")
};
// Allow the credential to be sent to our host, as customHosts does in the JS SDK.
var graph = new GraphServiceClient(http, new StaticTokenProvider(buildersApiKey));

sendMail takes Graph’s own payload and returns 202 Accepted with an empty body once Microsoft accepts the message. Full request schema in the reference.

Terminal window
curl -X POST \
https://api.builders.ac/api/mailbox/v1beta1/azure/v1.0/users/alice@acme.com/sendMail \
-H "Authorization: Bearer $BUILDERS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"message":{"subject":"Hi","body":{"contentType":"Text","content":"hello"},
"toRecipients":[{"emailAddress":{"address":"lead@example.com"}}]}}'
await client.api("/users/alice@acme.com/sendMail").post({
message: {
subject: "Hi",
body: { contentType: "Text", content: "hello" },
toRecipients: [{ emailAddress: { address: "lead@example.com" } }],
},
saveToSentItems: true,
});

List messages with the OData parameters you already use — $select, $filter, $top, $orderby — forwarded to Microsoft untouched.

const inbox = await client
.api("/users/alice@acme.com/messages")
.select("id,subject,from,receivedDateTime")
.top(25)
.get();
Terminal window
curl -G \
https://api.builders.ac/api/mailbox/v1beta1/azure/v1.0/users/alice@acme.com/messages \
-H "Authorization: Bearer $BUILDERS_API_KEY" \
--data-urlencode '$select=id,subject,from,receivedDateTime' \
--data-urlencode '$top=25'

Always send $select. The default projection is large, and message bodies dominate the response. Every supported parameter is listed under List messages.

We rewrite @odata.nextLink to point back at us, so page iterators work unchanged and you never receive a raw graph.microsoft.com link that your key could not authenticate against.

import { PageIterator } from "@microsoft/microsoft-graph-client";
const first = await client.api("/users/alice@acme.com/messages").top(25).get();
await new PageIterator(client, first, (message) => {
console.log(message.subject);
return true;
}).iterate();

The proxy runs a strict allow-list. These four routes are reachable; anything else returns 404 even if it exists in Graph.

Method Path
POST /users/{email}/sendMail
GET /users/{email}/messages
GET /users/{email}/messages/{id}
GET /users/{email}/mailFolders

You can only address mailboxes belonging to your account. A mailbox that is not yours returns 404 rather than 403, so the API never confirms which addresses exist. A supported path with the wrong method returns 405.

Errors on the Graph surface come back in Microsoft’s own format, including errors we raise ourselves, so your existing Graph error handling keeps working.

{
"error": {
"code": "ResourceNotFound",
"message": "No such mailbox.",
"innerError": { "request-id": "…", "date": "…" }
}
}
Status Meaning
401 Missing, invalid, or revoked API Key.
403 The authenticated account is not permitted to perform the operation.
404 Unknown mailbox or path, including a mailbox that is not yours.
405 Supported path, unsupported method.
413 Request body above 10 MB.
429 Rate limit exceeded. See Retry-After.
502 We could not reach Microsoft. Ambiguous for sends.
503 Temporarily unavailable. Safe to retry with backoff.

60 requests per minute per API credential and per account. Creating another credential does not increase the account-wide allowance. Going over either bucket returns 429 with Retry-After and X-RateLimit-* headers — wait the number of seconds given and try again. Microsoft’s own throttling is passed through with its headers intact, so your SDK’s built-in backoff keeps working.

GET /events lists sent and received messages observed across your mailboxes over the last seven days. Use it when an integration needs classified activity such as replies or warmup traffic without polling every mailbox through Graph.

Terminal window
curl -G https://api.builders.ac/api/mailbox/v1beta1/events \
-H "Authorization: Bearer $BUILDERS_API_KEY" \
--data-urlencode 'classification=reply,other_inbound' \
--data-urlencode 'limit=100'

Continue with next_cursor as starting_after, keeping the same filters and order. Events can appear after their created_at time because classification is asynchronous; when following the feed, overlap the created[gte] window and deduplicate on event id. Coverage is limited to mailboxes with a live Microsoft Graph subscription, and classification is best-effort.

Two provider capabilities are reserved in the API reference but are not callable today:

  • Event webhooks — push subscriptions are future work. Poll the available /events feed for now.
  • Gmail — reserved under a /google/ prefix, which answers 501 so you can detect it deliberately. Only Microsoft 365 mailboxes work today.

The upstream Graph portion of the URL does not change. Only the builders.ac API version and credential change:

Retiring Current
Base https://api.builders.ac/api/mailbox/v1alpha1https://api.builders.ac/api/mailbox/v1beta1
Bearer Vibe sk_live_… Mailbox key Shared builders.ac age1… API Key
Graph suffix /azure/v1.0 /azure/v1.0

Create the new credential, replace the bearer value, and change v1alpha1 to v1beta1. The Microsoft Graph request paths and SDK calls stay the same.

When something goes wrong, quote the x-correlation-id response header — the same value appears as request-id inside our error bodies. It identifies the exact request, including Microsoft’s own id from x-ms-request-id, which is what we need to escalate on your behalf.