Migrating from Fileforge
Wednesday, September 25, 2024
After 7 months of helping hundreds of businesses streamline their document workflows, we’ve made the difficult decision to discontinue Fileforge’s services as of December 25th, 2024. We understand this change may cause disruptions to your processes, and we’re committed to supporting you in making this transition as smooth as possible.
Why are we shutting down?
Fileforge was born from a mission to simplify document generation for businesses and individuals alike. Over the past 7 months, we’ve been proud to help hundreds of users create beautiful documents—from invoices to reports and everything in between. However, as the founding team moves in different directions, we’ve made the tough decision to wind down operations rather than pass the service onto a third party.
How will the migration happen?
All existing customers are welcome to book a hands-on migration session over the next week, where we will help with migrating your documents to other services.
You can book a session on my calendar.
Services will continue working until December 25th 2024.
Documents that are hosted on Fileforge will be available for download until December 25th 2024. Documents created from now on will have a maximum retention period capped to December 25th 2024.
Migration guide
We recommend that you use our migration chat to help you migrate your processes. You can also check the below guide for more information, and reach out to us if you need any help.
Methods:
Using the Migration Chat
We have set up an AI chatbot to help you migrate your processes. You can paste your existing code implementation and the chatbot will guide you through the migration process. The chatbot has knowledge of Fileforge, it’s API, most common use cases, as well as the recommended alternatives.
Migration Chat (interactive):
HTML to PDF
Our open-source library @fileforge/react-print will continue to work after the shutdown, although it will be archived and no longer maintained. You can still use it to generate HTML bundles to use with other services.
The DocRaptor API should provide a seamless transition for those who need a hosted solution, and we recommend it for its ease of use and reliability.
Those who would rather use a self-hosted solution can look into PrinceXML which will also provide a seamless transition.
Other renderers such as Puppeteer or wkhtmltopdf can also be used to generate PDFs from HTML, although most of the React-Print layout features will not be available.
Python Sample
1 | # ---------------------------- |
2 | # Fileforge API |
3 | # ---------------------------- |
4 | |
5 | import requests |
6 | |
7 | headers = { |
8 | 'accept': 'application/pdf', |
9 | 'X-API-Key': 'blabla', |
10 | } |
11 | |
12 | files = { |
13 | 'options': (None, '{"test":true,"host":false,"expiresAt":"2024-09-25T10:24:58.927Z","fileName":"document","allowViewing":false}', 'application/json'), |
14 | 'files': ('index.html', open('index.html', 'rb'), 'text/html'), |
15 | } |
16 | |
17 | response = requests.post('https://api.fileforge.com/pdf/generate/', headers=headers, files=files) |
18 | |
19 | # ---------------------------- |
20 | # DocRaptor API |
21 | # ---------------------------- |
22 | |
23 | import docraptor |
24 | |
25 | doc_api = docraptor.DocApi() |
26 | # this key works in test mode! |
27 | doc_api.api_client.configuration.username = 'YOUR_API_KEY_HERE' |
28 | |
29 | try: |
30 | response = doc_api.create_doc({ |
31 | 'test': True, # test documents are free but watermarked |
32 | 'document_type': 'pdf', |
33 | 'document_content': open('index.html', 'rb'), |
34 | 'prince_options': { |
35 | 'media': 'print' |
36 | }, |
37 | }) |
38 | |
39 | # create_doc() returns a binary string |
40 | with open('docraptor-hello.pdf', 'w+b') as f: |
41 | binary_formatted_response = bytearray(response) |
42 | f.write(binary_formatted_response) |
43 | f.close() |
44 | print('Successfully created docraptor-hello.pdf!') |
45 | except docraptor.rest.ApiException as error: |
46 | print(error.status) |
47 | print(error.reason) |
48 | print(error.body) |
Javascript Sample
1 | // ---------------------------- |
2 | // Fileforge API |
3 | // ---------------------------- |
4 | |
5 | import { FileforgeClient } from "@fileforge/client"; |
6 | |
7 | const ff = new FileforgeClient({ |
8 | apiKey: "xxx", |
9 | }); |
10 | |
11 | const html = await compile(<Document />); |
12 | |
13 | const file = await ff.pdf.generate( |
14 | [ |
15 | new File([html], "index.html", { |
16 | type: "text/html", |
17 | }), |
18 | ], |
19 | { |
20 | options: { |
21 | host: false, |
22 | test: false, |
23 | allowViewing: true, |
24 | }, |
25 | } |
26 | ); |
27 | |
28 | // ---------------------------- |
29 | // DocRaptor API |
30 | // ---------------------------- |
31 | |
32 | const html = await compile(<Document />); |
33 | |
34 | const response = await fetch("https://docraptor.com/docs", { |
35 | method: "POST", |
36 | headers: { |
37 | "Content-Type": "application/json", |
38 | Authorization: "xxx", |
39 | }, |
40 | body: JSON.stringify({ |
41 | test: true, |
42 | document_content: html, |
43 | document_type: "pdf", |
44 | }), |
45 | }); |
46 | |
47 | const blob = await response.blob(); |
DOCX to PDF, Merging, Splitting and Forms Operations
For other operations, we recommend using PDF.co which provides a wide range of operations on PDFs, including merging, splitting, and form filling. You can buy prepaid credits to use the service, or you can subscribe to a monthly plan.
Operations Table
We have selected PDF.co as the recommended alternative for the following operations:
Operation | Fileforge API | PDF.co |
---|---|---|
DOCX to PDF | /pdf/docx/ | Yes, without templated variables |
PDF Form Fields Identification | /pdf/form/detect/ | Yes |
Visual PDF Form Fields Identification | /pdf/form/mark/ | No |
PDF Form Fields Filling | /pdf/form/fill/ | Yes |
PDF Merge | /pdf/merge/ | Yes |
PDF Split | /pdf/split/ | Yes |
Specifics
File Upload
PDF.co works with URLs rather than files in its API. You can upload raw files via POST or via presigned URLs to PDF.co’s storage and then use them in your operations. You can also upload files by URL, for example to download a file using a presigned URL from your cloud storage.
Samples
Merging two PDF Files
Use PDF.co’s API to merge two PDF files. First, we upload the two PDF files, then we merge them, and finally, we download the merged PDF.
1 | import requests |
2 | |
3 | # Replace with your actual PDF.co API key |
4 | API_KEY = 'YOUR_PDF_CO_API_KEY' |
5 | |
6 | try: |
7 | # Upload first PDF file |
8 | upload_url = 'https://api.pdf.co/v1/file/upload/get-presigned-url' |
9 | headers = {'x-api-key': API_KEY} |
10 | payload = {'name': 'file1.pdf'} |
11 | |
12 | response = requests.post(upload_url, json=payload, headers=headers) |
13 | if response.status_code != 200: |
14 | raise Exception(f"File 1 upload failed: {response.text}") |
15 | |
16 | upload_data = response.json() |
17 | with open('path/to/your/first/file.pdf', 'rb') as file: |
18 | requests.put(upload_data['presignedUrl'], data=file) |
19 | file1_url = upload_data['url'] |
20 | print("File 1 uploaded successfully.") |
21 | |
22 | # Upload second PDF file |
23 | payload = {'name': 'file2.pdf'} |
24 | |
25 | response = requests.post(upload_url, json=payload, headers=headers) |
26 | if response.status_code != 200: |
27 | raise Exception(f"File 2 upload failed: {response.text}") |
28 | |
29 | upload_data = response.json() |
30 | with open('path/to/your/second/file.pdf', 'rb') as file: |
31 | requests.put(upload_data['presignedUrl'], data=file) |
32 | file2_url = upload_data['url'] |
33 | print("File 2 uploaded successfully.") |
34 | |
35 | # Merge the uploaded PDFs |
36 | merge_url = 'https://api.pdf.co/v1/pdf/merge' |
37 | payload = { |
38 | 'url': [file1_url, file2_url], |
39 | 'async': False |
40 | } |
41 | |
42 | response = requests.post(merge_url, json=payload, headers=headers) |
43 | if response.status_code != 200: |
44 | raise Exception(f"PDF merge failed: {response.text}") |
45 | |
46 | result = response.json() |
47 | if result['error']: |
48 | raise Exception(result['message']) |
49 | |
50 | merged_url = result['url'] |
51 | print(f"PDFs merged successfully. Merged file URL: {merged_url}") |
52 | |
53 | # Download the merged file |
54 | response = requests.get(merged_url) |
55 | if response.status_code == 200: |
56 | with open('merged_output.pdf', 'wb') as file: |
57 | file.write(response.content) |
58 | print("Merged PDF downloaded successfully as 'merged_output.pdf'") |
59 | else: |
60 | print(f"Failed to download merged PDF: {response.text}") |
61 | |
62 | except Exception as e: |
63 | print(f"An error occurred: {str(e)}") |
Detecting PDF Form Fields
Use PDF.co’s API to identify form fields in a PDF. First, upload the PDF form, then identify the form fields, and finally, process and print the form fields.
1 | import requests |
2 | |
3 | # Replace with your actual PDF.co API key |
4 | API_KEY = 'YOUR_PDF_CO_API_KEY' |
5 | |
6 | try: |
7 | # Upload the PDF form |
8 | upload_url = 'https://api.pdf.co/v1/file/upload/get-presigned-url' |
9 | headers = {'x-api-key': API_KEY} |
10 | payload = {'name': 'form.pdf'} |
11 | |
12 | response = requests.post(upload_url, json=payload, headers=headers) |
13 | if response.status_code != 200: |
14 | raise Exception(f"File upload failed: {response.text}") |
15 | |
16 | upload_data = response.json() |
17 | with open('path/to/your/form.pdf', 'rb') as file: |
18 | requests.put(upload_data['presignedUrl'], data=file) |
19 | file_url = upload_data['url'] |
20 | print("PDF form uploaded successfully.") |
21 | |
22 | # Identify form fields |
23 | fields_url = 'https://api.pdf.co/v1/pdf/info/fields' |
24 | payload = { |
25 | 'url': file_url, |
26 | 'async': False |
27 | } |
28 | |
29 | response = requests.post(fields_url, json=payload, headers=headers) |
30 | if response.status_code != 200: |
31 | raise Exception(f"Form field identification failed: {response.text}") |
32 | |
33 | result = response.json() |
34 | if result['error']: |
35 | raise Exception(result['message']) |
36 | |
37 | # Process and print the form fields |
38 | fields = result['fields'] |
39 | print(f"Found {len(fields)} form fields:") |
40 | for field in fields: |
41 | print(f"Name: {field['name']}") |
42 | print(f"Type: {field['type']}") |
43 | print(f"Value: {field['value']}") |
44 | print(f"Page: {field['page']}") |
45 | print(f"Rectangle: {field['rect']}") |
46 | print("---") |
47 | |
48 | except Exception as e: |
49 | print(f"An error occurred: {str(e)}") |
Filling PDF Form Fields
Use PDF.co’s API to fill form fields in a PDF. First, upload the PDF form, then fill the form fields, and finally, download the filled form.
1 | import requests |
2 | import json |
3 | |
4 | # Replace with your actual PDF.co API key |
5 | API_KEY = 'YOUR_PDF_CO_API_KEY' |
6 | |
7 | # Replace with the path to your local PDF form |
8 | LOCAL_PDF_PATH = 'path/to/your/form.pdf' |
9 | |
10 | # Replace with the desired output path for the filled form |
11 | OUTPUT_PDF_PATH = 'path/to/your/filled_form.pdf' |
12 | |
13 | # Define the form fields to fill (replace with your actual field names and values) |
14 | FORM_FIELDS = { |
15 | 'name': 'John Doe', |
16 | 'email': 'john.doe@example.com', |
17 | 'age': '30' |
18 | } |
19 | |
20 | try: |
21 | # Step 1: Upload the PDF form |
22 | upload_url = 'https://api.pdf.co/v1/file/upload/get-presigned-url' |
23 | headers = {'x-api-key': API_KEY} |
24 | payload = {'name': 'form.pdf'} |
25 | |
26 | response = requests.post(upload_url, json=payload, headers=headers) |
27 | if response.status_code != 200: |
28 | raise Exception(f"File upload failed: {response.text}") |
29 | |
30 | upload_data = response.json() |
31 | with open(LOCAL_PDF_PATH, 'rb') as file: |
32 | requests.put(upload_data['presignedUrl'], data=file) |
33 | file_url = upload_data['url'] |
34 | print("PDF form uploaded successfully.") |
35 | |
36 | # Step 2: Fill the form fields |
37 | fill_url = 'https://api.pdf.co/v1/pdf/edit/fill-form' |
38 | payload = { |
39 | 'url': file_url, |
40 | 'fields': json.dumps(FORM_FIELDS), |
41 | 'async': False |
42 | } |
43 | |
44 | response = requests.post(fill_url, json=payload, headers=headers) |
45 | if response.status_code != 200: |
46 | raise Exception(f"Form filling failed: {response.text}") |
47 | |
48 | result = response.json() |
49 | if result['error']: |
50 | raise Exception(result['message']) |
51 | |
52 | filled_form_url = result['url'] |
53 | print("Form filled successfully.") |
54 | |
55 | # Step 3: Download the filled form |
56 | response = requests.get(filled_form_url) |
57 | if response.status_code != 200: |
58 | raise Exception("Failed to download the filled form") |
59 | |
60 | with open(OUTPUT_PDF_PATH, 'wb') as file: |
61 | file.write(response.content) |
62 | print(f"Filled form downloaded and saved to {OUTPUT_PDF_PATH}") |
63 | |
64 | except Exception as e: |
65 | print(f"An error occurred: {str(e)}") |
DOCX to PDF Conversion
Use PDF.co’s API to convert a DOCX file to PDF. First, upload the DOCX file, then convert it to PDF, and finally, download the converted PDF.
1 | # Replace with your actual PDF.co API key |
2 | API_KEY = 'YOUR_PDF_CO_API_KEY' |
3 | |
4 | # Replace with the path to your local DOCX file |
5 | LOCAL_DOCX_PATH = 'path/to/your/document.docx' |
6 | |
7 | # Replace with the desired output path for the PDF |
8 | OUTPUT_PDF_PATH = 'path/to/your/output.pdf' |
9 | |
10 | try: |
11 | # Step 1: Upload the DOCX file |
12 | upload_url = 'https://api.pdf.co/v1/file/upload/get-presigned-url' |
13 | headers = {'x-api-key': API_KEY} |
14 | payload = {'name': 'document.docx'} |
15 | |
16 | response = requests.post(upload_url, json=payload, headers=headers) |
17 | if response.status_code != 200: |
18 | raise Exception(f"File upload failed: {response.text}") |
19 | |
20 | upload_data = response.json() |
21 | with open(LOCAL_DOCX_PATH, 'rb') as file: |
22 | requests.put(upload_data['presignedUrl'], data=file) |
23 | file_url = upload_data['url'] |
24 | print("DOCX file uploaded successfully.") |
25 | |
26 | # Step 2: Convert DOCX to PDF |
27 | convert_url = 'https://api.pdf.co/v1/pdf/convert/from/doc' |
28 | payload = { |
29 | 'url': file_url, |
30 | 'name': 'result.pdf', |
31 | 'async': True |
32 | } |
33 | |
34 | response = requests.post(convert_url, json=payload, headers=headers) |
35 | if response.status_code != 200: |
36 | raise Exception(f"Conversion initiation failed: {response.text}") |
37 | |
38 | result = response.json() |
39 | if result['error']: |
40 | raise Exception(result['message']) |
41 | |
42 | job_id = result['jobId'] |
43 | print(f"Conversion job initiated. Job ID: {job_id}") |
44 | |
45 | # Step 3: Wait for the conversion to complete |
46 | # NOTE: this is because we use 'async': True in the conversion request |
47 | # This is best suited for long running document conversions. |
48 | status_url = f'https://api.pdf.co/v1/job/check' |
49 | while True: |
50 | response = requests.post(status_url, json={'jobId': job_id}, headers=headers) |
51 | if response.status_code != 200: |
52 | raise Exception(f"Job status check failed: {response.text}") |
53 | |
54 | status = response.json() |
55 | if status['status'] == 'working': |
56 | print("Conversion in progress...") |
57 | time.sleep(3) |
58 | elif status['status'] == 'success': |
59 | print("Conversion completed successfully.") |
60 | result_url = status['url'] |
61 | break |
62 | else: |
63 | raise Exception(f"Conversion failed: {status['status']}") |
64 | |
65 | # Step 4: Download the converted PDF |
66 | response = requests.get(result_url) |
67 | if response.status_code != 200: |
68 | raise Exception("Failed to download the converted PDF") |
69 | |
70 | with open(OUTPUT_PDF_PATH, 'wb') as file: |
71 | file.write(response.content) |
72 | print(f"Converted PDF downloaded and saved to {OUTPUT_PDF_PATH}") |
73 | |
74 | except Exception as e: |
75 | print(f"An error occurred: {str(e)}") |
File Hosting
For file hosting, we recommend using your native cloud provider, such as AWS S3, Google Cloud Storage, or Azure Blob Storage.
Fileforge’s file hosting service will be discontinued on December 25th 2024. Files will have a capped date of December 25th 2024 until then.
Other Alternatives
- PSPDFKit for a more advanced PDF SDK. See their API at https://pspdfkit.com/api/
A Final Thank You
As we wind down Fileforge, we want to extend our heartfelt thanks to every one of you who supported us along the way. Your feedback, usage, and trust helped us build something we’re proud of. While Fileforge’s chapter is coming to a close, our journey doesn’t end here, and we hope our paths will cross again in the future.
If you have any concerns or need further assistance during the migration process, please don’t hesitate to reach out. We’re here to make this transition as smooth as possible.
Thank you for being part of the Fileforge story.