Human approvals
Find out which actions a Met left waiting for a person's approval —publishing, charging, invoicing, spending ad budget— and how they ended.
Some actions a Met does not take on its own. When it asks to publish on social media, charge, issue an invoice, spend ad budget, send a template that Meta bills for, or delete something, the action does not run: it becomes an approval waiting for a person at the business. That person approves or rejects it in Met —on the chat card, on the Home screen or over WhatsApp— and only then does it happen.
With the API you see those approvals: what was requested, who decided it and what came out of it. You do not decide them. Approving something that charges or publishes belongs to a person, never to a key.
Before you start
Your key needs approvals:read. Keys issued before this scope existed do not carry it: add it in Settings › Developers or issue a new one. It also works with a test key (met_test_), because it only reads.
A Run that was left waiting
When a Run asks for one of those actions, the Met replies with something like "this is pending your approval" and the Run ends as completed. The response tells you the action was not taken:
import Met from '@meteor.ia/sdk';
const met = new Met(process.env.METEOR_API_KEY!);
const run = await met.runs.create({ input: 'Publica en Facebook el post de la promo de otoño' });
if (run.awaiting_approval) {
for (const a of run.approvals ?? []) {
console.log(`Awaiting approval: ${a.action} (${a.approval_id})`);
}
}
| Run field | What it is |
|---|---|
awaiting_approval | true if it left at least one action waiting. |
approvals[] | Each action with its approval_id, action, status and requested_at. |
When the Run is created, status is the one at that moment. On GET /runs/{id} (runs.retrieve) it is the current one: if someone already approved it, you see it there. The run.completed event carries the same two fields when there are approvals.
If a Run asks again for something that was already waiting (a retry of yours, or the Met insisting), no new approval is created: the existing one still belongs to the Run that asked first, and the new Run does not list it. To see everything that is waiting, no matter which Run asked for it: approvals.list({ status: 'pending' }).
Reading approvals
// What is waiting for a person right now
const { data } = await met.approvals.list({ status: 'pending' });
// Everything a Run left behind
const fromRun = await met.approvals.list({ run_id: run.id });
// A single one, with all its detail
const a = await met.approvals.retrieve(run.approvals![0].approval_id);
console.log(a.status, a.decided_by?.name, a.result?.text);curl "https://api.met.meteor.com.co/api/v1/workspaces/$WS/approvals?status=pending,approved" \
-H "Authorization: Bearer $METEOR_API_KEY"Filters on GET /workspaces/{workspaceId}/approvals:
| Parameter | What for |
|---|---|
status | One or several, comma-separated: pending, approved, rejected, executed, failed. |
run_id | The ones an API Run left behind. |
conversation_id | The ones requested in a conversation (its 100 most recent turns). |
since / until | By request date, ISO 8601 with time and zone. since is included, until is not. |
limit / starting_after | Pagination: 1–100 per page; pass next_cursor exactly as it arrived. |
The list goes from newest to oldest and returns { data, has_more, next_cursor }. To walk all of it, met.approvals.iterate({ ... }).
The statuses
status | What happened |
|---|---|
pending | Waiting for a person. |
approved | A person approved it and it is running (a video can take minutes). |
executed | It ran. result says what came out, with the pieces it produced. |
failed | It was approved but failed to run. result.error_code says why: execution_failed (the tool responded with an error) or interrupted (it was cut off before finishing). The business sees the error detail in Met. |
rejected | It was not done. rejection_reason tells apart rejected, changes_requested (they asked for a change: it is in change_request) and replaced (the Met asked for a newer version: it is in replaced_by). |
What each approval carries
| Field | What it is |
|---|---|
action | Which action it is, in words: "Publicar una imagen en Instagram", "Crear una factura en Siigo". |
summary, details | About what: the data needed to decide, readable ("vertical 9:16", "Monto: 120000"). No emails, phone numbers or documents of your customers. |
draft | What the Met wrote (the text or the instruction for the piece). |
preview | The text and images that would be published, and the ad budget if it spends. |
met | Which Met asked for it (id: null is the main Met). |
origin | Where it came from: api_run, routine, channel or panel. |
decided_by, decided_at | Who decided it and when. decided_by.user_id is the same id as in met.team.list(). |
result | What came out when it ran: a line of text, the files (files) and, if it failed, error_code. |
It never carries the raw input of the tool, credentials (not even inside a text, like a provider's error), contact data of your customers, internal ids or the name of a model.
Finding out without polling
Subscribe your endpoint to two events (see Webhooks). Both carry the full approval, with the same shape as approvals.retrieve:
| Event | When |
|---|---|
approval.requested | A Met asked for an action that needs approval. |
approval.decided | A person approved it (status: approved) or rejected it (status: rejected). |
await met.webhooks.subscriptions.create({
url: 'https://your-system.com/met/events',
enabled_events: ['approval.requested', 'approval.decided'],
});
To find out how an approved one ended, read the approval after approval.decided (executed or failed).
From an assistant (MCP)
Meteor's MCP server has met_list_approvals and met_get_approval, also read-only. If you ask your assistant "what do I have pending approval?", it tells you; to approve, it sends you to Met.
Why approvals are not made through the API
The actions that wait for approval are precisely the ones that cannot be undone: a charge, an electronic invoice, a post, a campaign with a budget. If a key could approve them, an instruction hidden in a contact's message, or a bug in your integration, would be enough to carry them out without anyone at the business seeing it. That is why the decision lives in Met, with the person the business chose under Settings › Roles › Who approves?.