API de Parley Notes, versión 1.Lee notas, crea notas y entérate cuando una esté lista.
La API de Parley Notes permite que una app que conectes lea tus notas de reunión, cree notas a partir de texto o audio y reciba un aviso en cuanto una nota está lista. Es la base de la integración de Parley Notes para Zapier, y cualquier app registrada en Parley Notes puede usarla de la misma forma.
- URL base:
https://app.parleynotes.com/api/v1 - Formato: JSON de entrada y de salida, UTF-8. Envía
Content-Type: application/jsoncon un cuerpo. - Autenticación: OAuth 2.0, flujo de código de autorización. Cada llamada lleva
Authorization: Bearer <access token>. - Las notas de salud nunca se devuelven. Una nota redactada como conversación de salud (una visita al médico, una sesión de terapia, una nota en una carpeta analizada como médica) no se lista, no se encuentra, no se lee ni se envía a un hook, por ningún endpoint.
1. Autenticación
Las apps se registran a mano: Parley Notes da a cada app un client id y un client secret (escribe al equipo de Parley Notes para registrar una). Esta API no tiene registro de autoservicio.
Scopes
| Scope | Permite |
|---|---|
notes:read | GET /me, GET /notes, GET /notes/find, GET /notes/{id}, GET /action-items, GET /hooks/sample |
notes:write | POST /notes |
hooks | POST /hooks, DELETE /hooks/{id} |
Pide varios scopes separados por espacios (las comas también valen). Si no pides ninguno, se conceden los tres.
Paso 1: envía a la persona a autorizar
GET https://app.parleynotes.com/api/v1/oauth/authorize
?client_id=YOUR_CLIENT_ID
&redirect_uri=https%3A%2F%2Fyour.app%2Foauth%2Fcallback
&response_type=code
&scope=notes%3Aread%20notes%3Awrite%20hooks
&state=YOUR_STATE
La persona inicia sesión en Parley Notes (con su inicio de sesión habitual) y ve lo que pide tu app. Si lo permite, Parley Notes redirige a tu redirect_uri con un código y tu state exactamente como lo enviaste:
https://your.app/oauth/callback?code=pn_code_...&state=YOUR_STATE
Si cancela: ?error=access_denied&error_description=...&state=YOUR_STATE. El redirect_uri debe ser uno registrado para tu app. PKCE (code_challenge con code_challenge_method=S256) está admitido y se comprueba cuando lo envías.
Paso 2: canjea el código (en 5 minutos, una sola vez)
curl -X POST https://app.parleynotes.com/api/v1/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d grant_type=authorization_code \
-d code=pn_code_... \
-d redirect_uri=https://your.app/oauth/callback \
-d client_id=YOUR_CLIENT_ID \
-d client_secret=YOUR_CLIENT_SECRET
El cliente puede autenticarse con HTTP Basic en lugar de los dos campos del cuerpo. También se aceptan cuerpos JSON.
{
"access_token": "pn_at_...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "pn_rt_...",
"scope": "notes:read notes:write hooks"
}
Paso 3: llama a la API
curl https://app.parleynotes.com/api/v1/me -H "Authorization: Bearer pn_at_..."
Renovación
Los access tokens duran una hora. Cuando una llamada responde 401, renueva y vuelve a intentarlo:
curl -X POST https://app.parleynotes.com/api/v1/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d grant_type=refresh_token \
-d refresh_token=pn_rt_... \
-d client_id=YOUR_CLIENT_ID \
-d client_secret=YOUR_CLIENT_SECRET
La respuesta es un nuevo par. Los refresh tokens rotan: guarda el nuevo refresh token y descarta el anterior. Reutilizar un refresh token antiguo más de un minuto después de haberse canjeado cierra la conexión (se trata como una copia robada); dos renovaciones simultáneas dentro de ese minuto tienen éxito las dos. Un refresh token sin usar durante 90 días caduca.
| Situación | Respuesta |
|---|---|
| Access token ausente, desconocido, caducado o revocado | 401 invalid_token, con WWW-Authenticate: Bearer ... (nunca 403) |
| Refresh token desconocido, caducado, reutilizado o revocado | 400 {"error": "invalid_grant"} |
Código desconocido, usado, caducado, o con otro redirect_uri | 400 {"error": "invalid_grant"} |
| Client id o client secret incorrectos en el endpoint de token | 401 {"error": "invalid_client"} |
Revocación
curl -X POST https://app.parleynotes.com/api/v1/oauth/revoke -d token=pn_rt_...
Siempre responde 200; la conexión termina. La persona también puede desconectar tu app en cualquier momento en Parley Notes, en Ajustes, Conexiones, Apps conectadas; sus tokens dejan de funcionar al instante y sus hooks se detienen.
2. El objeto nota
Cada nota tiene todas las claves de abajo en cada respuesta. Un valor vacío es "" (texto), [] (lista) o 0 (duración), nunca null, así que un campo asignado en un flujo de trabajo nunca desaparece.
| Campo | Tipo | Qué es |
|---|---|---|
id | string | El id de la nota |
title | string | El título de la nota |
date_iso | string | Cuándo se grabó o se creó la nota, ISO 8601 en UTC |
duration_min | integer | Duración en minutos (0 si la nota no es hablada) |
occasion | string | Cómo se redactó la nota, por ejemplo sales_call, standup, minutes, one_on_one |
summary_text | string | El resumen, en texto plano |
summary_html | string | El resumen en HTML simple (párrafos, listas, negrita) |
share_url | string | Enlace que abre la nota en Parley Notes (para su propietario) |
participant_emails | string[] | Direcciones de correo de las personas invitadas, en minúsculas |
participant_names | string[] | Nombres de las personas que hablaron o fueron invitadas |
action_items | object[] | {text, owner_name, owner_email, due_date} cada uno; due_date es YYYY-MM-DD |
decisions | string[] | Decisiones tomadas |
next_steps | string[] | Primero el siguiente paso acordado (con su fecha si se dijo una), luego los seguimientos |
participant_emails_text | string | participant_emails unidos con , |
participant_names_text | string | participant_names unidos con , |
action_items_text | string | Una línea por elemento: - text (owner, email; due YYYY-MM-DD) |
decisions_text | string | Una línea por decisión, que empieza con - |
next_steps_text | string | Una línea por siguiente paso, que empieza con - |
El correo de un responsable solo se rellena cuando el responsable coincidió con alguien de la invitación; nunca se adivina.
{
"id": "meet_1761213600000123",
"title": "Acme renewal call",
"date_iso": "2026-10-20T14:00:00.000Z",
"duration_min": 30,
"occasion": "sales_call",
"summary_text": "Acme wants to renew for two years. Budget is approved; legal reviews the contract this week.",
"summary_html": "<p>Acme wants to renew for two years. Budget is approved; legal reviews the contract this week.</p>",
"share_url": "https://app.parleynotes.com/?note=Xk3pQ9vRt2LmN8wA",
"participant_emails": ["dana@acme.example", "lee@acme.example"],
"participant_names": ["Dana Reyes", "Lee Park"],
"action_items": [
{ "text": "Send the renewal quote", "owner_name": "Bruno", "owner_email": "bruno@parleynotes.com", "due_date": "2026-10-24" },
{ "text": "Share the case study", "owner_name": "Dana Reyes", "owner_email": "dana@acme.example", "due_date": "" }
],
"decisions": ["Renew for two years"],
"next_steps": ["Quote to Dana (2026-10-24)", "Check in after the legal review"],
"participant_emails_text": "dana@acme.example, lee@acme.example",
"participant_names_text": "Dana Reyes, Lee Park",
"action_items_text": "- Send the renewal quote (Bruno, bruno@parleynotes.com; due 2026-10-24)\n- Share the case study (Dana Reyes, dana@acme.example)",
"decisions_text": "- Renew for two years",
"next_steps_text": "- Quote to Dana (2026-10-24)\n- Check in after the legal review"
}
La fila de acción
GET /action-items y el hook action_item.created dan una fila por cada acción abierta:
| Campo | Tipo | Qué es |
|---|---|---|
id | string | noteId:itemId, estable para el mismo elemento |
text, owner_name, owner_email, due_date | string | Como en el objeto nota |
priority | string | low, medium, high, o "" cuando la conversación no lo dijo |
note_id, note_title, note_date_iso, share_url | string | La nota de la que salió |
{
"id": "meet_1761213600000123:ai_1761213600000_0",
"text": "Send the renewal quote",
"owner_name": "Bruno",
"owner_email": "bruno@parleynotes.com",
"due_date": "2026-10-24",
"priority": "high",
"note_id": "meet_1761213600000123",
"note_title": "Acme renewal call",
"note_date_iso": "2026-10-20T14:00:00.000Z",
"share_url": "https://app.parleynotes.com/?note=Xk3pQ9vRt2LmN8wA"
}
3. Endpoints
Las listas y las búsquedas cubren las 500 notas más recientes de la cuenta. Una nota que aún se está redactando no se devuelve hasta que su resumen está listo.
GET /me
A quién pertenece el token. Scope: cualquiera.
curl https://app.parleynotes.com/api/v1/me -H "Authorization: Bearer pn_at_..."
{ "id": "Zr8kq2...", "email": "dana@example.com", "name": "Dana Reyes", "plan": "regular" }
plan es free, starter, regular o power.
GET /notes
Las notas, la más reciente primero. Scope: notes:read.
| Parámetro | Significado |
|---|---|
since | Solo las notas de esta fecha en adelante: YYYY-MM-DD o ISO 8601 |
until | Solo las notas hasta esta fecha (YYYY-MM-DD significa el final de ese día) |
occasion | Solo las notas redactadas para esta ocasión, por ejemplo sales_call |
participant_email | Solo las notas a las que se invitó a esta dirección |
q | Palabras que buscar en el título, el resumen y los temas |
limit | De 1 a 100, por defecto 25 |
cursor | El next_cursor de la página anterior |
curl "https://app.parleynotes.com/api/v1/notes?since=2026-10-01&participant_email=dana@acme.example&limit=10" \
-H "Authorization: Bearer pn_at_..."
{
"data": [ { "id": "meet_1761213600000123", "title": "Acme renewal call", "...": "every field of the note object" } ],
"next_cursor": "MjAyNi0xMC0yMFQxNDowMDowMC4wMDBaAW1lZXRfMTc2MTIxMzYwMDAwMDEyMw"
}
next_cursor es "" en la última página. Los cursores son opacos; devuélvelos sin cambios.
GET /notes/find
Encuentra notas por título, correo de un participante o fecha (al menos uno). Responde con una lista, como máximo 10, la más reciente primero, y [] cuando nada coincide. Scope: notes:read.
| Parámetro | Significado |
|---|---|
title | Palabras del título (no distingue mayúsculas) |
participant_email | Una dirección que fue invitada |
date | El día de la nota, YYYY-MM-DD |
curl "https://app.parleynotes.com/api/v1/notes/find?title=renewal" -H "Authorization: Bearer pn_at_..."
[ { "id": "meet_1761213600000123", "title": "Acme renewal call", "...": "every field of the note object" } ]
GET /notes/{id}
Una nota. Scope: notes:read. 404 not_found para un id que no existe, que no es de esta cuenta, que aún se está redactando o que es una nota de salud.
curl https://app.parleynotes.com/api/v1/notes/meet_1761213600000123 -H "Authorization: Bearer pn_at_..."
Responde con el objeto nota.
POST /notes
Crea una nota a partir de texto o de un enlace de audio. Scope: notes:write. Envía exactamente uno de text y audio_url.
| Campo | Tipo | Significado |
|---|---|---|
text | string | Una transcripción, un correo o cualquier texto, de hasta 120.000 caracteres |
audio_url | string | Un enlace http o https a un archivo de audio o a un episodio de pódcast (Apple Podcasts, Spotify, un feed RSS o una página de pódcast) |
title | string | Opcional. Sin él, Parley Notes pone nombre a la nota |
folder | string | Opcional. La carpeta de Parley Notes donde archivarla |
curl -X POST https://app.parleynotes.com/api/v1/notes \
-H "Authorization: Bearer pn_at_..." \
-H "Content-Type: application/json" \
-d '{"text": "Dana: we can sign by Friday if legal agrees.\nBruno: I will send the quote today.", "title": "Call with Acme"}'
Responde en segundos con 202 Accepted:
{ "id": "meet_1761213600000123", "status": "processing" }
Parley Notes transcribe (si es audio) y redacta el resumen en segundo plano, lo que puede tardar unos minutos en una grabación larga. Cuando la nota está lista, aparece en el Parley Notes de la persona con este id, y el hook note.ready se dispara con ella. Las importaciones cuentan para los límites de la cuenta como cualquier importación en la app: un resumen usa el cupo del plan, y un enlace de audio necesita un plan de pago cuando se han agotado las importaciones gratuitas de la cuenta.
| Rechazo | Respuesta |
|---|---|
Ambos o ninguno de text y audio_url, o una URL incorrecta | 400 invalid_request |
text de más de 120.000 caracteres | 413 too_large |
| Audio en un plan gratuito sin importaciones gratuitas disponibles | 402 plan_required |
| El límite diario de importaciones de la cuenta, o 30 notas nuevas en una hora | 429 daily_limit o rate_limited, con Retry-After |
Si la importación falla más tarde (un enlace inaccesible, sin voz), no se crea ninguna nota y no se dispara ningún hook. Si falla el resumen, la nota se guarda con su transcripción y espera en la app a que la persona la resuma.
GET /action-items
Las acciones abiertas de todas las notas, una fila por elemento, la nota más reciente primero. Scope: notes:read.
| Parámetro | Significado |
|---|---|
since | Solo los elementos de notas de esta fecha en adelante |
owner_email | Solo los elementos cuyo responsable es esta dirección |
limit, cursor | Como en GET /notes |
curl "https://app.parleynotes.com/api/v1/action-items?owner_email=bruno@parleynotes.com" -H "Authorization: Bearer pn_at_..."
{ "data": [ { "id": "meet_1761213600000123:ai_1761213600000_0", "text": "Send the renewal quote", "...": "every field of the action item row" } ], "next_cursor": "" }
4. REST hooks
En lugar de consultar cada poco, suscribe una URL y Parley Notes le hace un POST.
| Evento | Cuándo | Cuerpo |
|---|---|---|
note.ready | Se redacta el primer resumen de una nota (no un nuevo resumen posterior) | El objeto nota |
action_item.created | En el mismo momento, una vez por cada acción abierta de esa nota | La fila de acción |
Suscribirse: POST /hooks
Scope: hooks. target_url debe ser https en un host público.
curl -X POST https://app.parleynotes.com/api/v1/hooks \
-H "Authorization: Bearer pn_at_..." \
-H "Content-Type: application/json" \
-d '{"event": "note.ready", "target_url": "https://hooks.example.com/parley"}'
201 Created:
{ "id": "hk_Q2x9...", "event": "note.ready", "target_url": "https://hooks.example.com/parley", "created_at": "2026-10-23T10:00:00.000Z" }
Una cuenta admite como máximo 100 suscripciones.
Cancelar la suscripción: DELETE /hooks/{id}
Scope: hooks. Responde 200 {"id": "hk_Q2x9...", "deleted": true}, o "deleted": false cuando ya no existía (cancelar dos veces no es un error).
Datos de ejemplo: GET /hooks/sample?event=
Scope: notes:read. Los tres últimos, exactamente en la forma que envía el hook: notas para note.ready, filas de acción para action_item.created. Zapier lo usa para mostrar datos de ejemplo mientras se configura un Zap.
curl "https://app.parleynotes.com/api/v1/hooks/sample?event=action_item.created" -H "Authorization: Bearer pn_at_..."
Entrega
POSTconContent-Type: application/jsonyUser-Agent: ParleyNotes-Hooks/1; un evento por solicitud.- Cualquier 2xx significa entregado.
- 410 Gone elimina la suscripción; no se le envía nada más.
- Un 429 se reintenta tras su
Retry-After. - Un 5xx, un tiempo de espera agotado (10 segundos) o un fallo de red se reintenta a los 2 segundos, a los 10 segundos y a los 60 segundos, y luego se abandona.
- Cualquier otro 4xx se abandona de inmediato.
- Parley Notes nunca envía más rápido de 30 solicitudes por segundo ni más de 10.000 en cinco minutos; pasado ese límite, las entregas esperan.
- Una nota de salud nunca dispara un hook. Cuando la persona desconecta tu app, sus suscripciones se detienen al instante.
5. Límites de uso
| Límite | Valor | Al superarlo |
|---|---|---|
| Solicitudes por conexión | 120 por minuto | 429 rate_limited con Retry-After (segundos) |
| Notas nuevas por cuenta | 30 por hora | 429 rate_limited con Retry-After |
| Importaciones de audio | el límite diario de la cuenta (compartido con la app) | 429 daily_limit con Retry-After |
Espera los segundos de Retry-After y vuelve a intentarlo.
6. Errores
Todo error de la API (salvo el endpoint de token de OAuth, que sigue su propio formato) es:
{ "error": { "code": "not_found", "message": "No note with that id, or it is still being written." } }
| Estado | code | Significado |
|---|---|---|
| 400 | invalid_request | Falta un parámetro o no es válido; message dice cuál |
| 401 | invalid_token | No hay token, o es desconocido, caducado o revocado. Renueva y vuelve a intentarlo. Viene con WWW-Authenticate |
| 402 | plan_required | El plan de la cuenta no incluye esto |
| 403 | insufficient_scope | El token es válido pero no recibió el scope que necesita este endpoint. Vuelve a conectar con él |
| 404 | not_found | No existe esa nota, o no existe ese endpoint |
| 413 | too_large | El texto es demasiado largo |
| 429 | rate_limited, daily_limit, too_many_hooks | Se alcanzó un límite; mira Retry-After |
| 500 | server_error | Algo falló por nuestra parte. Inténtalo de nuevo |
7. Versiones
La versión va en la ruta: /api/v1. Dentro de v1, Parley Notes puede añadir endpoints, parámetros de consulta, campos en las respuestas y eventos de hook; tu código debe ignorar lo que no conozca. Quitar o renombrar un campo, cambiar su tipo, o cambiar lo que hace un endpoint significa una versión nueva (/api/v2), y v1 sigue funcionando entonces al menos 12 meses después de anunciar v2.
Dudas o un client id para tu app: escribe al equipo de Parley Notes a través de la página de soporte.