Skip to main content
  1. Writing/

First Explorations of Twitter Verification API

·776 words

Twitter just announced that they are re-launching their verification program, and now you can check whether you are eligible directly from your Twitter account settings. Neat! Which naturally made me curious as to what they used behind the scenes, since in previous instances of the process they used a form that likely was manually reviewed. Before I dive in, I want to call out - no, I am not important enough to be verified, nor do I care about getting the blue tick. Personal API curiosity for me truly has no bounds, as I was experimenting with this stuff since the Xbox 360 era.

Let’s start by looking at where exactly the verification request starts - right there in your profile, in Account Information:

Twitter Account Settings

Because I’ve already tried (unsuccessfully, I might add) submitting a request before , I no longer get a Request Verification button, but that only persists until the next refresh of the page. Once I do that, I can kick-start the process.

A link on Twitter’s website that allows requesting verification

One click, and I was set on my journey to joining the ranks!

Requesting verification through Twitter’s automated form

I guess not. But that was awfully fast for a decision - I wonder if Twitter automated the process somehow. To figure that out, I started Fiddler on Windows and quickly spotted that there are three requests going out every time I initialize the process, to the following endpoints, respectively:

https://twitter.com/i/api/verify/1.0/account-eligibility
https://twitter.com/i/api/verify/1.0/badge-violation/violations
https://twitter.com/i/api/verify/1.0/document-formats

The first one (account-eligibility) is responsible for checking if you meet the audience and volume of mentions requirements. It’s a GET request that is bound to your Twitter identity, and doesn’t carry any query parameters or a request body. It returns a JSON response of the form:

{
    "followers_eligible": false,
    "mentions_eligible": false
}

The second request (badge-violations) is similarly bland - it just asks Twitter if you had a history of Terms of Service (TOS) violations. If all is well, you’ll get an empty JSON array in return.

Lastly, document-formats returns a list of identity documents that may be required for verification, bucketed by country. Some interesting data here on requirements to provide the backside of the document or not.

{
    "AD": {
        "cca3": "AND",
        "country": "Andorra",
        "id_types": {
            "passport": {
                "id_type": "passport",
                "name": "Passport",
                "needs_backside": false
            }
        }
    },
    "AE": {
        "cca3": "ARE",
        "country": "United Arab Emirates",
        "id_types": {
            "driving_license": {
                "id_type": "driving_license",
                "name": "Driving License",
                "needs_backside": false
            },
            "id_card": {
                "id_type": "id_card",
                "name": "ID Card",
                "needs_backside": true
            },
            "passport": {
                "id_type": "passport",
                "name": "Passport",
                "needs_backside": false
            },
            "permanent_resident_card": {
                "id_type": "permanent_resident_card",
                "name": "Permanent Resident Card",
                "needs_backside": true
            }
        }
    }
    ...
}

Clearly by executing these three requests, and specifically - by verifying my eligibility through account-eligibility, Twitter was able to quickly tell me that I should buzz off and not bother.

But what happens if I try to tell Twitter that I am eligible? It seems that the client-side decision is made by the account eligibility call, and based on the returned JSON body the UI decides whether to proceed or not. What if I could intercept the JSON mid-flight and tweak it to match this:

{
    "followers_eligible": true,
    "mentions_eligible": true
}

Thankfully, Fiddler has this exact functionality with automatic breakpoints:

Automatic breakpoints menu in Fiddler

What’s great about this functionality is that it doesn’t interfere with the request in any capacity, but allows me to intercept the response right before it’s returned to the client, thus removing the need for me to deal with custom-built API requests.

By altering the returned JSON and then returning the positive eligibility values, I managed to get much further!

Filled out form for the Twitter verification application

But as you can see, it still errored out at the end. What the heck - so I have access to the form, but still can’t submit the application. Why is that?

Well, there is one last-step, and it is gated behind server-side checks. The form issues a POST request to:

https://twitter.com/i/api/verify/1.0/intake 

The request content is wrapped in a JSON envelope, following this format:

{
    "authenticity_claim": {
        "authenticity_type": "website",
        "site_url": "https://theworkitem.com"
    },
    "notability_claim": {
        "category": "influencer_other",
        "main_reference_url": "https://theworkitem.com",
        "news_reference_urls": [
            "https://theworkitem.com",
            "https://den.dev",
            "https://pmtrack.co"
        ],
        "notability_subcategory": "content_creator"
    }
}

The response was a HTTP 400, with another JSON body:

{
    "errors": [
        "If activity requirement is not met, the Influencer category is not allowed."
    ]
}

Alas, clearly filling out the form was not enough - there is one check that is done by the service prior to filing the verification request that automatically disqualified me.

While clearly I have some room to grow to be able to verify myself, this was a fun weekend exploration to take a look at. Kudos to the Twitter engineers for not relying on just client-side verification - after all, you can never trust the client.