API Documentation
gitmd2pdf provides a RESTful API for programmatic markdown-to-PDF conversion. The API supports two authentication methods: HMAC-SHA256 for direct request signing, and OAuth 2.0 client credentials for token-based access. Both support asynchronous job processing with optional webhooks.
Authentication
You'll need a Premium subscription to access the API. Two authentication methods are available:
| Method | Best For | Token Management |
|---|---|---|
| HMAC | Server-to-server, CI/CD, scripts | No tokens - sign each request |
| OAuth | Long-running sessions, SDKs | Obtain token, use for 1 hour |
Getting API Credentials
- Log in to your gitmd2pdf account
- Navigate to Account > API Keys
- Click Generate New Credentials
- Select credential type: HMAC or OAuth
- Save your
client_idandclient_secretsecurely (secret shown only once)
HMAC Authentication
HMAC authentication signs each request directly using your client secret. No token exchange required.
Request Headers
| Header | Description |
|---|---|
Authorization |
HMAC <client_id>:<signature> |
X-Timestamp |
Unix timestamp in milliseconds |
Computing the Signature
The signature is computed as follows:
signing_string = METHOD + PATH + TIMESTAMP + BODY
secret_hash = SHA256(client_secret)
signature = HMAC-SHA256(secret_hash, signing_string)
Example (JavaScript/Node.js):
const crypto = require('crypto');
function signRequest({ clientId, clientSecret, method, path, body, timestamp }) {
// Hash the client secret
const secretHash = crypto.createHash('sha256')
.update(clientSecret)
.digest('hex');
// Build signing string: METHOD + PATH + TIMESTAMP + BODY
const signingString = `${method}${path}${timestamp}${body}`;
// Compute HMAC-SHA256 signature
const signature = crypto.createHmac('sha256', secretHash)
.update(signingString)
.digest('hex');
return `HMAC ${clientId}:${signature}`;
}
// Usage
const timestamp = String(Date.now());
const body = JSON.stringify({ type: 'repo', repoUrl: 'https://github.com/user/repo' });
const authorization = signRequest({
clientId: 'your_client_id',
clientSecret: 'your_client_secret',
method: 'POST',
path: '/api/v1/convert',
body,
timestamp
});
// Make request
fetch('https://gitmd2pdf.com/api/v1/convert', {
method: 'POST',
headers: {
'Authorization': authorization,
'X-Timestamp': timestamp,
'Content-Type': 'application/json'
},
body
});
Example (Python):
import hashlib
import hmac
import time
import json
import requests
def sign_request(client_id, client_secret, method, path, body, timestamp):
# Hash the client secret
secret_hash = hashlib.sha256(client_secret.encode()).hexdigest()
# Build signing string
signing_string = f"{method}{path}{timestamp}{body}"
# Compute HMAC-SHA256 signature
signature = hmac.new(
secret_hash.encode(),
signing_string.encode(),
hashlib.sha256
).hexdigest()
return f"HMAC {client_id}:{signature}"
# Usage
timestamp = str(int(time.time() * 1000))
body = json.dumps({"type": "repo", "repoUrl": "https://github.com/user/repo"})
authorization = sign_request(
client_id="your_client_id",
client_secret="your_client_secret",
method="POST",
path="/api/v1/convert",
body=body,
timestamp=timestamp
)
response = requests.post(
"https://gitmd2pdf.com/api/v1/convert",
headers={
"Authorization": authorization,
"X-Timestamp": timestamp,
"Content-Type": "application/json"
},
data=body
)
Example (Bash/curl):
#!/bin/bash
CLIENT_ID="your_client_id"
CLIENT_SECRET="your_client_secret"
TIMESTAMP=$(date +%s000)
METHOD="POST"
PATH="/api/v1/convert"
BODY='{"type":"repo","repoUrl":"https://github.com/user/repo"}'
# Hash the secret
SECRET_HASH=$(echo -n "$CLIENT_SECRET" | sha256sum | cut -d' ' -f1)
# Build signing string and compute signature
SIGNING_STRING="${METHOD}${PATH}${TIMESTAMP}${BODY}"
SIGNATURE=$(echo -n "$SIGNING_STRING" | openssl dgst -sha256 -hmac "$SECRET_HASH" | cut -d' ' -f2)
curl -X POST "https://gitmd2pdf.com${PATH}" \
-H "Authorization: HMAC ${CLIENT_ID}:${SIGNATURE}" \
-H "X-Timestamp: ${TIMESTAMP}" \
-H "Content-Type: application/json" \
-d "$BODY"
Replay Protection
Timestamps must be within 5 minutes of server time. Requests with stale or future timestamps will be rejected.
OAuth Authentication
OAuth 2.0 client credentials flow for obtaining bearer tokens.
Obtaining an Access Token
curl -X POST https://gitmd2pdf.com/api/v1/oauth/token \
-H "Content-Type: application/json" \
-d '{
"grant_type": "client_credentials",
"client_id": "your_client_id",
"client_secret": "your_client_secret"
}'
Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600
}
Use the access token in subsequent requests:
Authorization: Bearer <access_token>
Tokens expire after 1 hour. Request a new token when expired.
Endpoints
POST /api/v1/convert
Enqueue a markdown-to-PDF conversion job.
Authentication: Required (Bearer token)
Content-Type: application/json or multipart/form-data (for file uploads)
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
type |
string | Yes | Conversion type: file, url, or repo |
url |
string | For url type |
URL to a markdown file |
repoUrl |
string | For repo type |
Git repository URL |
branch |
string | No | Branch name (default: main/master) |
title |
string | No | Custom title for the PDF (max 256 chars) |
callbackUrl |
string | No | Webhook URL for job completion notification |
callbackAuthHeader |
string | No | Authorization header for callback requests |
Example: Convert a File
curl -X POST https://gitmd2pdf.com/api/v1/convert \
-H "Authorization: Bearer <access_token>" \
-F "type=file" \
-F "file=@README.md" \
-F "title=My Documentation"
Example: Convert a Repository
curl -X POST https://gitmd2pdf.com/api/v1/convert \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"type": "repo",
"repoUrl": "https://github.com/user/repo",
"branch": "main",
"title": "Project Documentation"
}'
Example: Convert a URL
curl -X POST https://gitmd2pdf.com/api/v1/convert \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"type": "url",
"url": "https://raw.githubusercontent.com/user/repo/main/README.md"
}'
Response (202 Accepted):
{
"jobId": "job_abc123def456",
"status": "queued"
}
GET /api/v1/jobs/:jobId/status
Check the status of a conversion job.
Authentication: Required (Bearer token)
Response:
{
"jobId": "job_abc123def456",
"status": "completed",
"createdAt": "2024-01-15T10:30:00Z",
"completedAt": "2024-01-15T10:30:15Z"
}
Status Values:
queued- Job is waiting to be processedprocessing- Job is currently being convertedcompleted- Conversion successful, PDF ready for downloadfailed- Conversion failed (seeerrorfield)
GET /api/v1/jobs/:jobId/download
Download the converted PDF file.
Authentication: Required (Bearer token)
Response: Binary PDF file with Content-Type: application/pdf
curl -X GET https://gitmd2pdf.com/api/v1/jobs/job_abc123def456/download \
-H "Authorization: Bearer <access_token>" \
-o output.pdf
Webhooks
For asynchronous workflows, configure a callback URL to receive job completion notifications.
Setting Up Webhooks
- Add callback domain to allowlist:
curl -X POST https://gitmd2pdf.com/api/v1/callback-allowlist \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{"domain": "api.yourapp.com"}'
- Include callback URL in conversion request:
curl -X POST https://gitmd2pdf.com/api/v1/convert \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"type": "repo",
"repoUrl": "https://github.com/user/repo",
"callbackUrl": "https://api.yourapp.com/webhooks/gitmd2pdf",
"callbackAuthHeader": "Bearer your-webhook-secret"
}'
Webhook Payload
{
"jobId": "job_abc123def456",
"status": "completed",
"downloadUrl": "https://gitmd2pdf.com/api/v1/jobs/job_abc123def456/download"
}
Managing Callback Allowlist
List allowed domains:
GET /api/v1/callback-allowlist
Remove a domain:
DELETE /api/v1/callback-allowlist/:domain
API Credentials Management
POST /api/v1/credentials
Generate new API credentials.
Authentication: Required (Session token)
GET /api/v1/credentials
List your API credentials.
Authentication: Required (Session token)
DELETE /api/v1/credentials/:clientId
Revoke API credentials.
Authentication: Required (Session token)
Rate Limits
| Plan | Requests/minute | Concurrent jobs |
|---|---|---|
| Premium | 60 | 10 |
Rate limit headers are included in all responses:
X-RateLimit-Limit- Maximum requests per windowX-RateLimit-Remaining- Requests remainingX-RateLimit-Reset- Unix timestamp when the limit resets
Error Responses
All errors follow a consistent format:
{
"error": "Error message describing the issue"
}
| Status Code | Description |
|---|---|
| 400 | Bad Request - Invalid parameters |
| 401 | Unauthorized - Invalid or expired token |
| 403 | Forbidden - Insufficient permissions or plan |
| 404 | Not Found - Resource doesn't exist |
| 429 | Too Many Requests - Rate limit exceeded |
| 500 | Internal Server Error |
| 503 | Service Unavailable - Try again later |
OpenAPI Specification
The complete OpenAPI 3.0 specification is available at:
GET /api/v1/openapi.json
You can import this into tools like Postman, Insomnia, or Swagger UI for interactive API exploration.
Code Examples
Python
import requests
# Get access token
auth_response = requests.post(
"https://gitmd2pdf.com/api/v1/oauth/token",
json={
"grant_type": "client_credentials",
"client_id": "your_client_id",
"client_secret": "your_client_secret"
}
)
token = auth_response.json()["access_token"]
# Convert a repository
headers = {"Authorization": f"Bearer {token}"}
convert_response = requests.post(
"https://gitmd2pdf.com/api/v1/convert",
headers=headers,
json={
"type": "repo",
"repoUrl": "https://github.com/user/repo"
}
)
job_id = convert_response.json()["jobId"]
# Poll for completion
import time
while True:
status = requests.get(
f"https://gitmd2pdf.com/api/v1/jobs/{job_id}/status",
headers=headers
).json()
if status["status"] == "completed":
break
time.sleep(2)
# Download PDF
pdf = requests.get(
f"https://gitmd2pdf.com/api/v1/jobs/{job_id}/download",
headers=headers
)
with open("output.pdf", "wb") as f:
f.write(pdf.content)
Node.js
const axios = require('axios');
const fs = require('fs');
async function convertRepo(repoUrl) {
// Get access token
const { data: auth } = await axios.post(
'https://gitmd2pdf.com/api/v1/oauth/token',
{
grant_type: 'client_credentials',
client_id: process.env.GITMD2PDF_CLIENT_ID,
client_secret: process.env.GITMD2PDF_CLIENT_SECRET
}
);
const headers = { Authorization: `Bearer ${auth.access_token}` };
// Start conversion
const { data: job } = await axios.post(
'https://gitmd2pdf.com/api/v1/convert',
{ type: 'repo', repoUrl },
{ headers }
);
// Poll for completion
let status;
do {
await new Promise(r => setTimeout(r, 2000));
const { data } = await axios.get(
`https://gitmd2pdf.com/api/v1/jobs/${job.jobId}/status`,
{ headers }
);
status = data.status;
} while (status !== 'completed' && status !== 'failed');
// Download PDF
const pdf = await axios.get(
`https://gitmd2pdf.com/api/v1/jobs/${job.jobId}/download`,
{ headers, responseType: 'arraybuffer' }
);
fs.writeFileSync('output.pdf', pdf.data);
}
convertRepo('https://github.com/user/repo');
Support
For API support, contact us at support@mods-software.com or visit our FAQ.