gitmd2pdf

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

  1. Log in to your gitmd2pdf account
  2. Navigate to Account > API Keys
  3. Click Generate New Credentials
  4. Select credential type: HMAC or OAuth
  5. Save your client_id and client_secret securely (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:


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

  1. 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"}'
  1. 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:


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.