{"openapi":"3.1.0","info":{"title":"SelfPing API","version":"1.0.0","summary":"Send a text message to your own phone.","description":"SelfPing is a simple API that sends a text message to your own phone from any app, website, server, or API. One endpoint, one API key, no Twilio account required.\n\nAn API key is bound to the phone number that created it, so there is no recipient parameter and a key cannot message anyone else.","contact":{"url":"https://www.selfping.com/contact"}},"servers":[{"url":"https://www.selfping.com"}],"security":[{"bearerAuth":[]}],"paths":{"/api/sms":{"post":{"operationId":"sendPing","summary":"Send a text to the account owner's phone","description":"Delivers the message as an SMS to the phone number that owns the API key. Consumes one credit.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendPingRequest"},"examples":{"jobFinished":{"summary":"Notify yourself that a job finished","value":{"message":"Nightly backup finished in 4m12s"}}}}}},"responses":{"200":{"description":"Message accepted for delivery.","content":{"text/plain":{"schema":{"type":"string"},"example":"SMS sent successfully"}}},"400":{"description":"The message field is missing, or the key has no phone number attached.","content":{"text/plain":{"schema":{"type":"string"}}}},"403":{"description":"The API key is invalid, revoked, or out of credits.","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"Unexpected server error.","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/api/mcp":{"post":{"operationId":"mcp","summary":"Model Context Protocol endpoint","description":"Streamable HTTP MCP transport exposing the send_ping tool. Speaks JSON-RPC 2.0.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"JSON-RPC response.","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid bearer token."}}}},"/api/hooks/claude-code":{"post":{"operationId":"hookClaudeCode","summary":"Receive a Claude Code completion event","description":"Translates a Claude Code hook event into a text to the account owner. Reads `message`, falling back to `last_assistant_message`. Point a Notification or Stop hook at this URL.\n\nAlways answers 200 with `{\"continue\": true}`, including when the key is missing, rejected or out of credits, so a SelfPing problem can never interrupt an agent session. When nothing was sent, the reason comes back in `systemMessage`. Consumes one credit per text delivered.","security":[{"bearerAuth":[]}],"parameters":[{"name":"label","in":"query","required":false,"description":"Optional prefix identifying the project, truncated to 24 characters.","schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HookEvent"},"examples":{"hookClaudeCode":{"summary":"A Claude Code event","value":{"session_id":"abc123","cwd":"/Users/you/project","message":"Migration finished. 1.2M rows, 0 errors."}}}}}},"responses":{"200":{"description":"Always returned. The agent should carry on regardless of whether a text went out.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HookResponse"}}}},"405":{"description":"Returned for any method other than POST."}}}},"/api/hooks/cursor":{"post":{"operationId":"hookCursor","summary":"Receive a Cursor completion event","description":"Translates a Cursor hook event into a text to the account owner. Cursor sends no message with its stop event, only `status`, so the text reads Finished. or Stopped. Use the label query parameter to tell projects apart.\n\nAlways answers 200 with `{\"continue\": true}`, including when the key is missing, rejected or out of credits, so a SelfPing problem can never interrupt an agent session. When nothing was sent, the reason comes back in `systemMessage`. Consumes one credit per text delivered.","security":[{"bearerAuth":[]}],"parameters":[{"name":"label","in":"query","required":false,"description":"Optional prefix identifying the project, truncated to 24 characters.","schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HookEvent"},"examples":{"hookCursor":{"summary":"A Cursor event","value":{"status":"completed"}}}}}},"responses":{"200":{"description":"Always returned. The agent should carry on regardless of whether a text went out.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HookResponse"}}}},"405":{"description":"Returned for any method other than POST."}}}},"/api/hooks/codex":{"post":{"operationId":"hookCodex","summary":"Receive a Codex completion event","description":"Translates a Codex hook event into a text to the account owner. Reads `last_assistant_message`, falling back to `message`. Codex discards stdout and stderr from hooks, so run the command by hand once before trusting it.\n\nAlways answers 200 with `{\"continue\": true}`, including when the key is missing, rejected or out of credits, so a SelfPing problem can never interrupt an agent session. When nothing was sent, the reason comes back in `systemMessage`. Consumes one credit per text delivered.","security":[{"bearerAuth":[]}],"parameters":[{"name":"label","in":"query","required":false,"description":"Optional prefix identifying the project, truncated to 24 characters.","schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HookEvent"},"examples":{"hookCodex":{"summary":"A Codex event","value":{"last_assistant_message":"Deploy finished, 0 errors."}}}}}},"responses":{"200":{"description":"Always returned. The agent should carry on regardless of whether a text went out.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HookResponse"}}}},"405":{"description":"Returned for any method other than POST."}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"A SelfPing API key, generated at https://www.selfping.com/dashboard. See https://www.selfping.com/auth.md."}},"schemas":{"SendPingRequest":{"type":"object","required":["message"],"additionalProperties":false,"properties":{"message":{"type":"string","minLength":1,"maxLength":1600,"description":"Text to deliver. Keep under 160 characters to stay within a single SMS segment."}}},"HookEvent":{"type":"object","additionalProperties":true,"description":"The client's own event JSON, forwarded unchanged. SelfPing reads whichever field that client carries and ignores the rest, so an unrecognised or empty body still answers 200 and sends Finished.","properties":{"message":{"type":"string","description":"Claude Code's notification text."},"last_assistant_message":{"type":"string","description":"The agent's final message, sent by Claude Code and Codex."},"status":{"type":"string","description":"Cursor's run outcome. Anything reading as abort, cancel, stop, error or fail becomes Stopped."}}},"HookResponse":{"type":"object","required":["continue"],"properties":{"continue":{"type":"boolean","const":true,"description":"Always true. SelfPing never halts an agent session."},"systemMessage":{"type":"string","description":"Present only when no text was sent, explaining why. Absent on success."}}}}}}