Header phone horse emoji

Two Factor Authentication as a ServicePay with lightning

The Scenario

You have a user that would like to authenticate to an account associated with the phone number 555-867-5309.

You (HTTP, cURL)
The 2fa.horse
POST /v1/jobs/ HTTP/1.1 Host: api.2fa.horse Content-Type: application/json Content-Length: 32 {"phone_number": "+15558675309"}
HTTP/1.1 201 CREATED Date: Thurs, 01 Jan 1970 00:00:00 GMT Content-Length: 212 Content-Type: application/json; charset=utf8 { "href": "https://api.2fa.horse/v1/jobs/3ixdELtMgr/", "verification_phrase": "3718375", "sender_id": "hdbjf", "lightning_invoice": "lnbcfoobarbazfoobarbazfoobarbaz...", "paid": false, "sent": false }
phoneTo: 555-867-5309 phone phoneYou have received the code 3718375 from sender hdbjf.phone phoneTo block these messages, you may reply with STOP.phone

Now you can ask your visitor for the code that they received via text message.

You can also check the status of a job, although the initial 201 response is your only opportunity to retrieve the verification_phrase and sender_id values:

GET /v1/jobs/3ixdELtMgr/ HTTP/1.1 Host: api.2fa.horse
HTTP/1.1 200 OK Date: Thurs, 01 Jan 1970 00:00:00 GMT Content-Length: 212 Content-Type: application/json; charset=utf8 { "href": "https://api.2fa.horse/v1/jobs/3ixdELtMgr/", "lightning_invoice": "lnbcfoobarbazfoobarbazfoobarbaz...", "paid": true, "sent": true }

The price is currently $0.05 per job plus my cost to send the SMS. This cost varies by country, but ranges mostly between $0.01 and $0.10. The price may come down if this application sees significant use.


This is currently a demonstration project, but for the future:

  1. If I am unable to keep this project up, I will open source it.
  2. If the service becomes popular or gets moderate interest:
    1. I'll include more helpful features.
    2. I'll construct a strong service guarantee and terms of service.

If you think that this is an awesome project and would like to build a cool service on it sooner rather than later, contact me.


Bitcoin means different things to different people. Bitcoin excites me because it facilitates computer-to-computer payments. With the lightning network, Bitcoin supports computer-to-computer micropayments.

And now, your lightning-enabled software and devices can purchase 2FA services from the 2fa.horse. I've created the 2fa.horse as an example of a useful, lightning-enabled, microservice provider.

The coolest project that I could imagine using this for is a lightning-network hardware wallet. If the user needed to perform some administrative function, like retrieving their wallet seed, then the wallet could autonomously issue a request to the 2fa.horse to help authenticate the user.

Service Guarantee

This service is for demonstration purposes only. The service guarantee is that there currently is no service guarantee. There are no refunds.

Furthermore, I haven't yet worked out all of the edge cases and it's possible that the 2FA SMS could fail without notifying you.


In no event shall the 2fa.horse be liable for any special, direct, indirect, consequential, or incidental damages or any damages whatsoever, whether in an action of contract, negligence or other tort, arising out of or in connection with the use of the Service or the contents of the Service. The 2fa.horse reserves the right to make additions, deletions, or modification to the contents on the Service at any time without prior notice.

Once again, this service is for demonstrations purposes only.


400 Bad Request: "Bad Number or Format"

HTTP/1.1 400 Bad Request Content-Type: application/json; charset=utf8 { "cause": "Bad number format or number", "detail": "Your phone number is invalid or is formatted incorrectly. Please use the format +nnnnnnnn according to the format of your country." }

Fix your number format.

400 Bad Request: "Unavailable Locale"

HTTP/1.1 400 Bad Request Content-Type: application/json; charset=utf8 { "cause": "Unavailable locale", "detail": "We're unable to send messages to this locale." }


400 Bad Request: "Rate Limit"

HTTP/1.1 400 Bad Request Content-Type: application/json; charset=utf8 { "cause": "Rate Limit", "detail": "This phone number is rate-limit saturated and we will not send another text at this time.", "duration": 25 }

We have sent multiple text messages to this number recently, and we will not send another for at least duration seconds.

400 Bad Request: "Blocked"

HTTP/1.1 400 Bad Request Content-Type: application/json; charset=utf8 { "cause": "Blocked", "detail": "Recipient has blocked our texts. Advise your visitor to text the indicated phrase to the indicated phone number." "phrase": "START", "phone_number": "+1555FOOBAAR" }

This recipient has asked us not to text them. You can ask them to turn our texts back on.

404 Not Found

HTTP/1.1 404 Not Found

You can get this error for any of the usual reasons.

500 Internal Server Error

HTTP/1.1 500 Internal Server Error

This error indicates that our server encountered an error for a reason that we didn't anticipate.


Made something cool with this service? Contact us and we'll link it here.


Give a star or raise on issue on the docs.2fa.horse GitHub.