Skip to main content
The Partner API is a REST API for partners. You can use it for partner authentication, user token issuance, and asynchronous audio transcription workflows.
Note:
This documentation site is for SaaS companies that want to integrate directly with Plaud devices and leverage Plaud’s ASR, diarization, and AI pipelines in their own SaaS product. If you are interested in integrating with existing Plaud users’ accounts via the OAuth API (currently in early beta), please fill out this survey here to join the waitlist and we will notify you as soon as it’s available..

Prerequisites

  1. You need to have an iOS/Android app that your users can download, OR
  2. Your users need to have bluetooth-enabled computers/laptops that they can use to transfer recordings over to your web app

Service regions

  • US: https://platform.plaud.ai/developer/api
  • JP: https://platform-jp.plaud.ai/developer/api
  • EU: https://platform-eu.plaud.ai/developer/api (coming soon)

Authentication model

The Partner API uses two token types:
  • Partner access token: for partner-level endpoints (for example, transcription endpoints)
  • Partner user access token: for user-level partner endpoints. Using it in sdk module.

1) Get a partner access token

POST /oauth/partner/access-token
  • Auth method: HTTP Basic Auth (client_id:secret_key)
  • Rate limit: 10 requests per minute per client_id
Example:
curl -X POST "https://platform.plaud.ai/developer/api/oauth/partner/access-token" \
  -u "<client_id>:<secret_key>"
Response example:
{
  "access_token": "eyJ...",
  "refresh_token": "eyJ...",
  "token_type": "bearer",
  "expires_in": 86400
}

2) Refresh a partner access token

POST /oauth/partner/access-token/refresh
  • Body: refresh_token (form field)
curl -X POST "https://platform.plaud.ai/developer/api/oauth/partner/access-token/refresh" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "refresh_token=<refresh_token>"

3) get a partner user token

POST /open/partner/users/access-token
  • Header: Authorization: Bearer <partner_access_token>
  • Body fields:
    • user_id (string, required, max length 120)
    • expires_in (integer, optional, range 300-86400)
  • Rate limit: 10 requests per minute per client_id + user_id
  • Returns: access_token (no refresh_token)
curl -X POST "https://platform.plaud.ai/developer/api/open/partner/users/access-token" \
  -H "Authorization: Bearer <partner_access_token>" \
  -H "Content-Type: application/json" \
  -d '{"user_id":"external-user-123","expires_in":3600}'

AI transcription (beta)

1) Submit a transcription task

POST /open/partner/ai/transcriptions/
  • Header: Authorization: Bearer <partner_access_token>
  • Body fields:
    • file_url (string, required)
    • params (object, optional), supports:
      • transcribe.language (default: auto)
      • transcribe.detection_level (default: segment)
      • vad.decode_silence (default: false)
      • diarization.enabled (default: false)
      • diarization.return_embedding (default: false)
  • Rate limit: based on client config qpm_transcription, default 60 requests per minute
curl -X POST "https://platform.plaud.ai/developer/api/open/partner/ai/transcriptions/" \
  -H "Authorization: Bearer <partner_access_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "file_url":"https://example.com/demo.wav",
    "params":{
      "transcribe":{"language":"auto", "detection_level":"segment"},
      "vad":{"decode_silence":false},
      "diarization":{"enabled":false,"return_embedding":false}
    }
  }'
Response example:
{
  "transcription_id": "task_exec_xxx",
  "status": "RECEIVED",
  "data": {}
}

2) Get transcription result

GET /open/partner/ai/transcriptions/{transcription_id}
  • Header: Authorization: Bearer <partner_access_token>
  • Status values: RECEIVED | PROGRESS | SUCCESS | FAILURE | REVOKED
curl "https://platform.plaud.ai/developer/api/open/partner/ai/transcriptions/task_exec_xxx" \
  -H "Authorization: Bearer <partner_access_token>"
Response example (when status is SUCCESS):
{
  "transcription_id": "task_exec_xxx",
  "status": "SUCCESS",
  "data": {
	"results": [
      {
        "speaker_id": "SPEAKER_00",
        "start": 0.0,
        "end": 5.2,
        "text": "Hello everyone, today we are going to discuss the project progress.",
        "language": "en-US"
      },
      {
        "speaker_id": "SPEAKER_01",
        "start": 5.5,
        "end": 10.8,
        "text": "Okay, I'll first introduce the current situation.",
        "language": "en-US"
      }
    ],
    "embeddings": {
      "SPEAKER_00": [0.123, 0.456, ...],
      "SPEAKER_01": [0.789, 0.012, ...]
    }
  }
}

Webhooks

When a transcription task reaches a completed state, the system sends a webhook event to your configured webhook URL.

Event trigger

  • Event type: audio_transcribe.completed
  • Trigger states: SUCCESS, FAILURE, or REVOKED
  • Method: POST

Event payload

{
  "event_id": "event_12345678-1234-1234-1234-1234567890ab",
  "event_type": "audio_transcribe.completed",
  "event_data": {
    "transcription_id": "task_exec_xxx",
    "status": "SUCCESS",
    "data": {}
  },
  "event_datetime": "2026-02-24T12:34:56.000000+00:00"
}

Signature header

If your client webhook has a secret_key, the webhook includes:
  • X-Signature: <hex_digest>
Signature algorithm: hmac-sha256. Signature verification steps
1

Read inputs

Read the webhook payload JSON, your webhook secret key, and header X-Signature.
2

Sort top-level fields

Sort payload keys alphabetically.
3

Build source string

Create key=value pairs from sorted fields, skip null values, join with &, then append &secret_key=<secret_key>.
4

Compute digest

Run HMAC-SHA256 using secret_key as key and the source string bytes as input, output as lowercase hex.
5

Compare

Compare computed digest with X-Signature using constant-time comparison.
Python example:
import hmac
import hashlib

def create_signature(payload: dict, secret_key: str) -> str:
    sorted_items = sorted(payload.items(), key=lambda x: x[0])
    filtered_items = [(k, v) for k, v in sorted_items if v is not None]
    source = "&".join([f"{k}={v}" for k, v in filtered_items])
    source += f"&secret_key={secret_key or ''}"
    return hmac.new(
        secret_key.encode("utf-8"),
        source.encode("utf-8"),
        hashlib.sha256
    ).hexdigest()

def verify_signature(payload: dict, secret_key: str, x_signature: str) -> bool:
    expected = create_signature(payload, secret_key)
    return hmac.compare_digest(expected, x_signature)

Common errors

Common detail error codes:
  • CLIENT_NOT_FOUND
  • SECRET_KEY_INVALID
  • ACCESS_TOKEN_INVALID
  • REFRESH_TOKEN_INVALID
  • SIGNATURE_INVALID