{
  "openapi": "3.1.0",
  "info": {
    "title": "Sahifa API",
    "version": "2026-09-24",
    "description": "HTML to PDF and screenshot API hosted in Jeddah, Saudi Arabia. Compatible with PDFShift v3 and ScreenshotOne. Documentation: https://sahifa.dev/docs",
    "contact": {
      "email": "support@sahifa.dev",
      "url": "https://sahifa.dev/docs"
    }
  },
  "servers": [
    {
      "url": "https://api.sahifa.dev",
      "description": "Jeddah (me-jeddah-1)"
    }
  ],
  "security": [
    {
      "basicAuth": []
    },
    {
      "apiKeyHeader": []
    },
    {
      "accessKey": []
    }
  ],
  "paths": {
    "/v3/convert/pdf": {
      "post": {
        "operationId": "convertPdf",
        "summary": "Convert HTML or a URL to PDF (PDFShift v3 compatible)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "source"
                ],
                "properties": {
                  "source": {
                    "type": "string",
                    "description": "http(s) URL or HTML document."
                  },
                  "format": {
                    "type": "string",
                    "default": "A4",
                    "description": "A0-A6, Letter, Legal, Tabloid, Ledger, or {width}x{height} such as 210mmx297mm."
                  },
                  "landscape": {
                    "type": "boolean",
                    "default": false
                  },
                  "margin": {
                    "oneOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "object",
                        "properties": {
                          "top": {
                            "type": "string"
                          },
                          "right": {
                            "type": "string"
                          },
                          "bottom": {
                            "type": "string"
                          },
                          "left": {
                            "type": "string"
                          }
                        }
                      }
                    ]
                  },
                  "header": {
                    "type": "object",
                    "required": [
                      "source"
                    ],
                    "properties": {
                      "source": {
                        "type": "string",
                        "description": "HTML; variables {{page}}, {{total}}, {{date}}, {{title}}, {{url}}."
                      },
                      "height": {
                        "type": "string",
                        "description": "Accepted; the space comes from margin."
                      }
                    }
                  },
                  "footer": {
                    "type": "object",
                    "required": [
                      "source"
                    ],
                    "properties": {
                      "source": {
                        "type": "string",
                        "description": "HTML; variables {{page}}, {{total}}, {{date}}, {{title}}, {{url}}."
                      },
                      "height": {
                        "type": "string",
                        "description": "Accepted; the space comes from margin."
                      }
                    }
                  },
                  "pages": {
                    "type": "string",
                    "examples": [
                      "1,3-5"
                    ]
                  },
                  "zoom": {
                    "type": "number",
                    "minimum": 0.1,
                    "maximum": 2
                  },
                  "use_print": {
                    "type": "boolean",
                    "default": false
                  },
                  "disable_backgrounds": {
                    "type": "boolean",
                    "default": false
                  },
                  "disable_javascript": {
                    "type": "boolean",
                    "default": false
                  },
                  "delay": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 10000,
                    "description": "Milliseconds."
                  },
                  "wait_for": {
                    "type": "string",
                    "description": "Name of a global function that returns truthy when the page is ready."
                  },
                  "timeout": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100,
                    "description": "Seconds; capped at 30."
                  },
                  "raise_for_status": {
                    "type": "boolean",
                    "default": false
                  },
                  "css": {
                    "type": "string"
                  },
                  "javascript": {
                    "type": "string"
                  },
                  "auth": {
                    "type": "object",
                    "required": [
                      "username",
                      "password"
                    ],
                    "properties": {
                      "username": {
                        "type": "string"
                      },
                      "password": {
                        "type": "string"
                      }
                    }
                  },
                  "http_headers": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "string"
                    }
                  },
                  "cookies": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": [
                        "name",
                        "value"
                      ],
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "value": {
                          "type": "string"
                        },
                        "domain": {
                          "type": "string"
                        },
                        "path": {
                          "type": "string"
                        },
                        "secure": {
                          "type": "boolean"
                        },
                        "http_only": {
                          "type": "boolean"
                        }
                      }
                    }
                  },
                  "encode": {
                    "type": "boolean",
                    "default": false,
                    "description": "Return JSON with base64 data."
                  },
                  "sandbox": {
                    "type": "boolean",
                    "description": "Accepted and ignored."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The PDF, or JSON when encode is true",
            "headers": {
              "X-Response-Duration": {
                "schema": {
                  "type": "integer"
                },
                "description": "Render time in milliseconds"
              },
              "X-Quota-Limit": {
                "schema": {
                  "type": "integer"
                },
                "description": "Monthly render allowance of the key"
              },
              "X-Quota-Remaining": {
                "schema": {
                  "type": "integer"
                },
                "description": "Renders left this month before this request"
              }
            },
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "string",
                      "contentEncoding": "base64"
                    },
                    "filesize": {
                      "type": "integer"
                    },
                    "duration": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Invalid request"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Missing or invalid API key"
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Monthly render allowance used up"
          },
          "408": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Rendering timed out"
          },
          "413": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Request body over 10 MB"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Render queue full; retry"
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Rendering error"
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Temporarily unavailable; retry"
          }
        }
      }
    },
    "/take": {
      "get": {
        "operationId": "takeScreenshot",
        "summary": "Screenshot of a URL or HTML (ScreenshotOne compatible)",
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uri",
              "description": "Public http(s) address to capture. Send exactly one of url and html."
            },
            "description": "Public http(s) address to capture. Send exactly one of url and html."
          },
          {
            "name": "html",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "description": "HTML document to capture."
            },
            "description": "HTML document to capture."
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "png",
                "jpeg",
                "jpg",
                "webp",
                "pdf"
              ],
              "default": "png"
            },
            "description": ""
          },
          {
            "name": "image_quality",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "description": "For jpeg and webp."
            },
            "description": "For jpeg and webp."
          },
          {
            "name": "omit_background",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "description": ""
          },
          {
            "name": "full_page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "description": ""
          },
          {
            "name": "viewport_width",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 1280,
              "maximum": 10000
            },
            "description": ""
          },
          {
            "name": "viewport_height",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 720,
              "maximum": 10000
            },
            "description": ""
          },
          {
            "name": "device_scale_factor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number",
              "default": 1,
              "minimum": 0.1,
              "maximum": 4
            },
            "description": ""
          },
          {
            "name": "selector",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "description": "CSS selector of one element to capture; 404 if nothing matches."
            },
            "description": "CSS selector of one element to capture; 404 if nothing matches."
          },
          {
            "name": "clip_x",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": ""
          },
          {
            "name": "clip_y",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": ""
          },
          {
            "name": "clip_width",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": ""
          },
          {
            "name": "clip_height",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": ""
          },
          {
            "name": "dark_mode",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "description": ""
          },
          {
            "name": "reduced_motion",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "description": ""
          },
          {
            "name": "user_agent",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": ""
          },
          {
            "name": "authorization",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "description": "Authorization header sent to the page."
            },
            "description": "Authorization header sent to the page."
          },
          {
            "name": "headers",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Name=value pairs."
            },
            "description": "Name=value pairs."
          },
          {
            "name": "cookies",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "name=value pairs."
            },
            "description": "name=value pairs."
          },
          {
            "name": "delay",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 30,
              "description": "Seconds."
            },
            "description": "Seconds."
          },
          {
            "name": "timeout",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number",
              "minimum": 1,
              "maximum": 100,
              "description": "Seconds; capped at 30."
            },
            "description": "Seconds; capped at 30."
          },
          {
            "name": "wait_until",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "load",
                "domcontentloaded",
                "networkidle",
                "commit"
              ],
              "default": "load"
            },
            "description": ""
          },
          {
            "name": "wait_for_selector",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": ""
          },
          {
            "name": "response_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "by_format",
                "json"
              ],
              "default": "by_format"
            },
            "description": ""
          },
          {
            "name": "cache",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "description": "Accepted and ignored."
            },
            "description": "Accepted and ignored."
          },
          {
            "name": "block_ads",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "description": ""
          },
          {
            "name": "block_trackers",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "description": ""
          },
          {
            "name": "block_cookie_banners",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "description": ""
          },
          {
            "name": "block_chats",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "description": ""
          },
          {
            "name": "hide_selectors",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": ""
          },
          {
            "name": "block_requests",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "URL patterns, * as wildcard."
            },
            "description": "URL patterns, * as wildcard."
          },
          {
            "name": "block_resources",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "image",
                  "font",
                  "media",
                  "script",
                  "stylesheet",
                  "xhr",
                  "fetch",
                  "websocket",
                  "other",
                  "document"
                ]
              }
            },
            "description": ""
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Screenshot"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Selector not found"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Invalid request"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Missing or invalid API key"
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Monthly render allowance used up"
          },
          "408": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Rendering timed out"
          },
          "413": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Request body over 10 MB"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Render queue full; retry"
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Rendering error"
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Temporarily unavailable; retry"
          }
        }
      },
      "post": {
        "operationId": "takeScreenshotPost",
        "summary": "Screenshot with a JSON body",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Public http(s) address to capture. Send exactly one of url and html."
                  },
                  "html": {
                    "type": "string",
                    "description": "HTML document to capture."
                  },
                  "format": {
                    "type": "string",
                    "enum": [
                      "png",
                      "jpeg",
                      "jpg",
                      "webp",
                      "pdf"
                    ],
                    "default": "png"
                  },
                  "image_quality": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100,
                    "description": "For jpeg and webp."
                  },
                  "omit_background": {
                    "type": "boolean"
                  },
                  "full_page": {
                    "type": "boolean"
                  },
                  "viewport_width": {
                    "type": "integer",
                    "default": 1280,
                    "maximum": 10000
                  },
                  "viewport_height": {
                    "type": "integer",
                    "default": 720,
                    "maximum": 10000
                  },
                  "device_scale_factor": {
                    "type": "number",
                    "default": 1,
                    "minimum": 0.1,
                    "maximum": 4
                  },
                  "selector": {
                    "type": "string",
                    "description": "CSS selector of one element to capture; 404 if nothing matches."
                  },
                  "clip_x": {
                    "type": "integer"
                  },
                  "clip_y": {
                    "type": "integer"
                  },
                  "clip_width": {
                    "type": "integer"
                  },
                  "clip_height": {
                    "type": "integer"
                  },
                  "dark_mode": {
                    "type": "boolean"
                  },
                  "reduced_motion": {
                    "type": "boolean"
                  },
                  "user_agent": {
                    "type": "string"
                  },
                  "authorization": {
                    "type": "string",
                    "description": "Authorization header sent to the page."
                  },
                  "headers": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Name=value pairs."
                  },
                  "cookies": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "name=value pairs."
                  },
                  "delay": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 30,
                    "description": "Seconds."
                  },
                  "timeout": {
                    "type": "number",
                    "minimum": 1,
                    "maximum": 100,
                    "description": "Seconds; capped at 30."
                  },
                  "wait_until": {
                    "type": "string",
                    "enum": [
                      "load",
                      "domcontentloaded",
                      "networkidle",
                      "commit"
                    ],
                    "default": "load"
                  },
                  "wait_for_selector": {
                    "type": "string"
                  },
                  "response_type": {
                    "type": "string",
                    "enum": [
                      "by_format",
                      "json"
                    ],
                    "default": "by_format"
                  },
                  "cache": {
                    "type": "boolean",
                    "description": "Accepted and ignored."
                  },
                  "block_ads": {
                    "type": "boolean"
                  },
                  "block_trackers": {
                    "type": "boolean"
                  },
                  "block_cookie_banners": {
                    "type": "boolean"
                  },
                  "block_chats": {
                    "type": "boolean"
                  },
                  "hide_selectors": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "block_requests": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "URL patterns, * as wildcard."
                  },
                  "block_resources": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "image",
                        "font",
                        "media",
                        "script",
                        "stylesheet",
                        "xhr",
                        "fetch",
                        "websocket",
                        "other",
                        "document"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/Screenshot"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Selector not found"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Invalid request"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Missing or invalid API key"
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Monthly render allowance used up"
          },
          "408": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Rendering timed out"
          },
          "413": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Request body over 10 MB"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Render queue full; retry"
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Rendering error"
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Temporarily unavailable; retry"
          }
        }
      }
    },
    "/health": {
      "get": {
        "operationId": "health",
        "summary": "Service status",
        "security": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "basicAuth": {
        "type": "http",
        "scheme": "basic",
        "description": "User 'api', password = your API key (PDFShift style)."
      },
      "apiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key"
      },
      "accessKey": {
        "type": "apiKey",
        "in": "query",
        "name": "access_key",
        "description": "ScreenshotOne style."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": false
          },
          "error": {
            "type": "string"
          }
        }
      }
    },
    "responses": {
      "Screenshot": {
        "description": "The image or PDF, or JSON when response_type=json",
        "headers": {
          "X-Response-Duration": {
            "schema": {
              "type": "integer"
            },
            "description": "Render time in milliseconds"
          },
          "X-Quota-Limit": {
            "schema": {
              "type": "integer"
            },
            "description": "Monthly render allowance of the key"
          },
          "X-Quota-Remaining": {
            "schema": {
              "type": "integer"
            },
            "description": "Renders left this month before this request"
          }
        },
        "content": {
          "image/png": {
            "schema": {
              "type": "string",
              "format": "binary"
            }
          },
          "image/jpeg": {
            "schema": {
              "type": "string",
              "format": "binary"
            }
          },
          "image/webp": {
            "schema": {
              "type": "string",
              "format": "binary"
            }
          },
          "application/pdf": {
            "schema": {
              "type": "string",
              "format": "binary"
            }
          },
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "success": {
                  "type": "boolean"
                },
                "content_type": {
                  "type": "string"
                },
                "data": {
                  "type": "string",
                  "contentEncoding": "base64"
                },
                "size": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    }
  }
}
