API Documentation
Everything you need to integrate YesSigned into your application.
Overview
The YesSigned API allows you to programmatically create and manage agreements, templates, webhooks, and API tokens. All API endpoints return JSON responses and use standard HTTP status codes.
https://api.yessigned.com/api/v1
All requests must include the header:
Content-Type: application/json Accept: application/json
Authentication
The API uses Bearer token authentication via Laravel Sanctum. Include your API token in the Authorization header of every request.
Authorization: Bearer YOUR_API_TOKEN
You can generate API tokens from the Tokens API or through the Telegram bot. Tokens are scoped to your account and inherit your plan's rate limits.
If the token is missing or invalid, the API returns:
{ "message": "Unauthenticated." }
Rate Limits
API requests are rate-limited to protect the platform. The default limit is 60 requests per minute per token.
Rate limit headers are included in every response:
X-RateLimit-Limit: 60 // Your per-minute limit X-RateLimit-Remaining: 58 // Requests remaining in current window
When the rate limit is exceeded, the API returns:
{ "message": "Too Many Attempts.", "retry_after": 30 }
Agreements
Create, retrieve, send, and cancel agreements programmatically.
Endpoints
Returns a paginated list of your agreements.
| Parameters | |
|---|---|
| page | Page number (default: 1) |
| per_page | Items per page (default: 20, max: 100) |
| status | Filter by status: draft, pending, confirmed, disputed, expired |
Returns a single agreement with participants and confirmations.
Creates a new agreement in draft status.
| Parameters | |
|---|---|
| title | Agreement title (required, max 255 chars) |
| body | Full agreement text (required) |
| deadline | ISO 8601 deadline date (optional) |
| template_id | Template ID to use (optional) |
{ "title": "NDA Agreement", "body": "Both parties agree to...", "deadline": "2025-12-31T23:59:59Z" }
Sends a draft agreement to participants. Changes status to pending.
Cancels a pending agreement. Only the creator can cancel.
Templates
Manage reusable agreement templates for your team.
Endpoints
Returns all templates for your account.
Returns a single template by ID.
Creates a new agreement template.
| Parameters | |
|---|---|
| name | Template name (required, max 255 chars) |
| body | Template body with placeholders (required) |
Updates an existing template.
Permanently deletes a template.
Webhooks
Register webhook endpoints to receive real-time notifications about agreement events.
Endpoints
Returns all registered webhook endpoints.
Returns a single webhook endpoint with delivery history.
Registers a new webhook endpoint.
| Parameters | |
|---|---|
| url | HTTPS endpoint URL (required) |
| events | Array of event types to subscribe to (required) |
| secret | Signing secret for HMAC verification (optional, auto-generated if omitted) |
{ "url": "https://example.com/webhooks/yessigned", "events": [ "agreement.created", "agreement.confirmed" ] }
Updates a webhook endpoint configuration.
Deletes a webhook endpoint. Pending deliveries will be cancelled.
API Tokens
Manage API tokens for authentication. Each token is scoped to your account.
Endpoints
Returns all active API tokens for your account.
Creates a new API token. The plain-text token is only returned once.
| Parameters | |
|---|---|
| name | Token name for identification (required) |
Store the token securely — it cannot be retrieved again.
{ "token": "1|a3kD9f...", "name": "my-integration", "created_at": "2025-06-15T10:30:00Z" }
Revokes an API token. It will immediately stop working.
Webhook Events
When subscribed events occur, YesSigned sends a POST request to your webhook URL with a JSON payload.
Event Types
Payload Format
All webhook payloads follow this structure:
{ "event": "agreement.confirmed", "timestamp": "2025-06-15T10:30:00Z", "data": { "id": 42, "title": "NDA Agreement", "status": "confirmed", "confirmed_at": "2025-06-15T10:30:00Z", "participants": [ { "user_id": 1, "role": "creator" }, { "user_id": 5, "role": "participant" } ] } }
Webhook Signature Verification
Every webhook request includes an X-Signature header containing an HMAC-SHA256 signature. Use this to verify that the request came from YesSigned and wasn't tampered with.
How It Works
YesSigned signs the raw JSON request body using your webhook's secret key with HMAC-SHA256. The resulting hex digest is sent in the X-Signature header.
- Read the raw request body (do not parse JSON first)
- Compute HMAC-SHA256 of the body using your webhook secret
- Compare the computed signature with the X-Signature header
Code Examples
$payload = file_get_contents('php://input'); $secret = 'your-webhook-secret'; $expected = hash_hmac('sha256', $payload, $secret); $signature = $_SERVER['HTTP_X_SIGNATURE']; if (!hash_equals($expected, $signature)) { http_response_code(403); exit('Invalid signature'); } // hash_equals() is timing-safe $data = json_decode($payload, true);
import hmac, hashlib payload = request.get_data() secret = b'your-webhook-secret' signature = request.headers.get('X-Signature') expected = hmac.new( secret, payload, hashlib.sha256 ).hexdigest() if not hmac.compare_digest(expected, signature): abort(403) # hmac.compare_digest() is timing-safe data = request.get_json()
const crypto = require('crypto'); const payload = req.rawBody; const secret = 'your-webhook-secret'; const signature = req.headers['x-signature']; const expected = crypto .createHmac('sha256', secret) .update(payload) .digest('hex'); const valid = crypto.timingSafeEqual( Buffer.from(expected), Buffer.from(signature) ); if (!valid) return res.status(403).send('Invalid signature'); // crypto.timingSafeEqual() prevents timing attacks const data = JSON.parse(payload);
Always use a timing-safe comparison function to prevent timing attacks. Never use simple string equality (== or ===) for signature comparison.