Use solvethree in a Django view

By solvethree4 min read

Create the task in a POST view, return its ID, and let the caller retrieve its status. Don’t hold the creation request open until the solve finishes.

The supplied views use a configured reCAPTCHA Enterprise target and a single proxy. They belong in an existing Django project with authentication and standard CSRF middleware enabled.

On this page

Install the SDK and configure the target

  1. 1.

    Install in the Django environment

    The official SDK requires Python 3.10+. In the environment running Django, use python -m pip install https://solvethree.com/downloads/solvethree_sdk-0.1.0-py3-none-any.whl.

  2. 2.

    Set the server environment variables

    Set SOLVETHREE_API_KEY to your workspace API key, CAPTCHA_SITE to the target hostname—not a full URL—and SOLVETHREE_PROXY to the proxy used for solving and subsequent target submission. Keep the API key and proxy credentials on the server.

  3. 3.

    Activate the site's profile

    Configure an active profile for that hostname in the console, available to your workspace. Sending a hostname and action does not create a profile. See site profile setup.

The example fixes the action to login and takes no target settings from the caller. Change that action if your configured target requires another one. The request uses the default enterprise-v3 mode; it needs site, action, and exactly one of proxy or proxyCandidates, not type or url.

Add the authenticated views

Django · authenticated views with normal CSRF protection
# views.py in an existing Django project with authentication/CSRF configured.
import os
from django.contrib.auth.decorators import login_required
from django.http import JsonResponse
from django.views.decorators.http import require_GET, require_POST
from solvethree import Solvethree, SolvethreeError

def client():
    return Solvethree(os.environ["SOLVETHREE_API_KEY"])

@login_required
@require_POST
def create_captcha(request):
    task = {"site": os.environ["CAPTCHA_SITE"], "action": "login", "proxy": os.environ["SOLVETHREE_PROXY"]}
    if request.headers.get("X-Request-ID"):
        task["requestId"] = request.headers["X-Request-ID"]
    try:
        return JsonResponse(client().create_task(task, wait_ms=0, timeout=20))
    except ValueError:
        return JsonResponse({"error": "Invalid task input"}, status=400)
    except SolvethreeError as error:
        return JsonResponse({"requestId": error.request_id, "taskId": error.task_id}, status=502)

@login_required
@require_GET
def get_captcha(request, task_id):
    try:
        return JsonResponse(client().get_task(task_id, wait_ms=15000, timeout=25))
    except ValueError:
        return JsonResponse({"error": "Invalid task ID"}, status=400)
    except SolvethreeError as error:
        return JsonResponse({"requestId": error.request_id, "taskId": error.task_id}, status=502)

# urls.py: import these views and add to urlpatterns:
# path("captcha/tasks", create_captcha),
# path("captcha/tasks/<str:task_id>", get_captcha),

create_task uses wait_ms=0, so it returns the task without waiting for the whole solve. Its HTTP call has a 20-second timeout. The retrieval view can wait up to 15 seconds for a task update, with a 25-second HTTP timeout. These are synchronous SDK calls: the retrieval request still occupies its Django worker while waiting.

login_required restricts access to signed-in users; the method decorators allow POST for creation and GET for retrieval. Keep Django’s normal CSRF protection and include its CSRF token when posting. Don’t add csrf_exempt.

Wire the routes and start Django

  1. 1.

    Update the existing URLconf

    Import path from django.urls and import create_captcha and get_captcha from your app’s views module. Add the two route entries shown at the bottom of the example to the existing urlpatterns. If you use an app URLconf, make sure the project URLconf includes it.

  2. 2.

    Start the development server

    With the environment variables available to the process, run python manage.py runserver from the directory containing manage.py. Use your project’s existing login flow before calling the endpoints.

  3. 3.

    Use the registered paths

    Without an enclosing URL prefix, creation is POST /captcha/tasks and retrieval is GET /captcha/tasks/<task_id>. The supplied routes have no trailing slash. Include any prefix introduced by your project URLconf.

Create once, then retrieve the task

  1. 1.

    Save an ID before sending the POST

    Choose a new X-Request-ID for each logical task and keep it until creation is resolved. Use 1–64 ASCII letters, numbers, underscores, or hyphens. The view forwards this header as the task’s requestId.

  2. 2.

    Check HTTP success before task status

    The sample returns HTTP 400 for caught input-validation errors and 502 for caught SDK errors. A successful response contains the task payload; read its id and status. HTTP success means the request succeeded, not that a token is ready.

  3. 3.

    Retrieve until the task finishes

    Call the GET endpoint with the returned task ID. Continue for pending or solving. On ready, use the solution. On failed, stop polling and inspect errorCode and error; failed solves are refunded. Fix invalid inputs rather than retrying them unchanged.

  4. 4.

    Recover an uncertain creation

    If the POST times out or returns an SDK error, don’t immediately create another task with a fresh ID. Retrieve the existing task if its ID is known. Otherwise, repeat the POST with the original X-Request-ID and unchanged task inputs to recover it. Reusing that ID with different inputs conflicts—including changes to the configured hostname, action, or proxy.

The SDK-error response includes requestId and taskId from the exception for diagnosis. Keep the caller’s original X-Request-ID separately so recovery doesn’t depend on receiving that response. See CAPTCHA API errors for failure handling.

Submit the token with the same proxy and returned identity

Only a ready task contains a usable solution. The value to send to the intended target is solution.token, not the task ID. Use the returned solution.userAgent and solution.secChUa browser identity, together with the original proxy configured in SOLVETHREE_PROXY.

These views don’t submit anything to the target. Your submission code must retain that proxy and apply the returned identity; returning the token to an unrelated browser session doesn’t do this automatically. Keep proxy credentials server-side and don’t mix the solution with another target URL or browser identity.

Run your first task.

Start with $5 in workspace credit.

Create a workspace