# Apply Guy Job Application API — Full Reference > Search current U.S. jobs and submit real employer applications over pure HTTP. API base: https://api.applyguy.ai OpenAPI: https://applyguy.ai/developers/openapi.json Human docs: https://applyguy.ai/developers/docs Reference: https://applyguy.ai/developers/docs/reference ## Version scope - Developer API v1 is U.S.-only. The catalog returns U.S. jobs and candidate facts are normalized for U.S. applications. - A raw employer URL is caller-selected; use one for a U.S.-appropriate role. Its live availability is resolved while the application runs. ## Pricing and human setup - 20 credits per US dollar. - Managed applications cost 2 credits. - Bring-your-own-agent applications cost 1 credit. - Stripe Checkout requires human payment approval. Workday also requires a one-time human Google Account step to create a Gmail app password; the returned bootstrap accessToken can then configure it through PUT /secrets/email-integration. ## Core workflow 1. POST /developer/bootstrap to create an account and receive the only copy of the first API key and refresh token. 2. PUT /v1/profile and PUT /v1/profile/resume to establish candidate facts and the primary resume. 3. For Workday, check GET /secrets/status and use the bootstrap accessToken with PUT /secrets/email-integration when needed. 4. GET /v1/jobs to find a current listing, then POST /v1/applications/preflight. 5. POST /v1/applications with an Idempotency-Key. 6. Poll GET /v1/applications/{id} or receive signed webhooks. 7. In agent mode, handle every awaiting_answers round by fetching the answer request and POSTing JSON that satisfies its responseSchema. ## POST /developer/bootstrap Create an account and first API key Creates a zero-balance, API-credit-only developer account, an API key, and account access tokens in one call while new registrations are enabled. The API key and refresh token are returned only once. No application can run until credits are purchased. Authentication: No authentication Parameters: - None Request body: application/json (required) ```json { "$ref": "#/components/schemas/DeveloperBootstrap" } ``` Responses: - 201: Account, one-time API key, account tokens, and next setup endpoints. - 400: The account or key configuration is invalid. - 403: New account registration is currently paused. - 409: An account already exists for this email. - 413: The bootstrap payload exceeds 64 KB. - 429: Too many bootstrap attempts from this address. Example: ```bash curl --request POST \ --url 'https://api.applyguy.ai/developer/bootstrap' \ --header 'Content-Type: application/json' \ --data '{"email":"agent-builder@example.com","password":"correct-horse-battery-staple","name":"Production agent"}' ``` --- ## GET /developer/api-keys List API keys Lists key metadata. Full secrets are never returned after creation. Authentication: Account access token Parameters: - None Request body: None Responses: - 200: API key metadata. - 401: The account access token is missing or invalid. Example: ```bash curl --request GET \ --url 'https://api.applyguy.ai/developer/api-keys' \ --header "Authorization: Bearer $APPLYGUY_ACCESS_TOKEN" ``` --- ## POST /developer/api-keys Create an API key Creates a scoped developer key. Store the returned key immediately because it cannot be retrieved again. Authentication: Account access token Parameters: - None Request body: application/json (required) ```json { "$ref": "#/components/schemas/ApiKeyCreate" } ``` Responses: - 201: One-time API key and metadata. - 400: The key configuration is invalid. - 401: The account access token is missing or invalid. - 409: The account already has the maximum 20 active API keys. - 413: The management payload exceeds 64 KB. Example: ```bash curl --request POST \ --url 'https://api.applyguy.ai/developer/api-keys' \ --header "Authorization: Bearer $APPLYGUY_ACCESS_TOKEN" \ --header 'Content-Type: application/json' \ --data '{"name":"CI application agent","scopes":["jobs:read","credits:spend","applications:read","applications:write"]}' ``` --- ## POST /auth/refresh Rotate account access and refresh tokens Uses the latest refresh token returned by bootstrap or a prior refresh. The old token is revoked; store the replacement atomically. This account token is for API-key and integration management, not /v1 requests. Authentication: No authentication Parameters: - None Request body: application/json (required) ```json { "$ref": "#/components/schemas/SessionRefresh" } ``` Responses: - 200: Rotated account tokens. - 400: A refresh token is required. - 401: The refresh token is invalid, expired, or revoked. - 409: Another request rotated this token first; retry with the token returned by that request. - 429: Too many refresh attempts. Example: ```bash curl --request POST \ --url 'https://api.applyguy.ai/auth/refresh' \ --header 'Content-Type: application/json' \ --data '{"refreshToken":"the-latest-refresh-token"}' ``` --- ## DELETE /developer/api-keys/{id} Revoke an API key Immediately revokes a developer API key owned by the account. Authentication: Account access token Parameters: - path `id` (required): API key ID. Request body: None Responses: - 204: Key revoked. - 400: The API key ID must be a UUID. - 401: The account access token is missing or invalid. - 404: The key does not exist or was already revoked. Example: ```bash curl --request DELETE \ --url 'https://api.applyguy.ai/developer/api-keys/24a9829d-7ec5-4fcc-917c-229006d22b06' \ --header "Authorization: Bearer $APPLYGUY_ACCESS_TOKEN" ``` --- ## GET /secrets/status Check Workday email integration readiness Uses the account accessToken returned by bootstrap, not a developer API key. No email secret is ever returned. Authentication: Account access token Parameters: - None Request body: None Responses: - 200: Email integration readiness and the ATSes that require it. - 401: The account access token is missing or invalid. Example: ```bash curl --request GET \ --url 'https://api.applyguy.ai/secrets/status' \ --header "Authorization: Bearer $APPLYGUY_ACCESS_TOKEN" ``` --- ## PUT /secrets/email-integration Verify and save Gmail IMAP credentials Uses the account accessToken returned by bootstrap. Apply Guy verifies the Gmail username and 16-character app password over IMAP before encrypting both values. Creating the Gmail app password requires a one-time human Google Account setup; it is required for Workday even though the API call itself is automatable. Authentication: Account access token Parameters: - None Request body: application/json (required) ```json { "$ref": "#/components/schemas/EmailIntegrationCreate" } ``` Responses: - 200: Credentials verified and stored. - 400: The email address or Gmail app-password shape is invalid. - 401: The account access token is missing or invalid. - 413: The integration payload exceeds the management API limit. - 422: Gmail rejected the IMAP credentials. - 503: Gmail credential validation is temporarily unavailable. Example: ```bash curl --request PUT \ --url 'https://api.applyguy.ai/secrets/email-integration' \ --header "Authorization: Bearer $APPLYGUY_ACCESS_TOKEN" \ --header 'Content-Type: application/json' \ --data '{"gmailUser":"candidate@gmail.com","gmailAppPassword":"abcd efgh ijkl mnop"}' ``` --- ## GET /v1/jobs Search fresh jobs Requires both jobs:read and credits:spend. jobs:read alone returns 403 without charging; credits:spend is explicit authorization for this key to incur catalog-read charges and grants no read access by itself. Searches active, non-stale U.S. jobs ordered by recency. A successful 200 costs 0.05 credit per requested block of up to 25 results: limits 1–25 cost 0.05, 26–50 cost 0.10, 51–75 cost 0.15, and 76–100 cost 0.20. Billing uses the requested limit, not the number of matches returned. Invalid requests, authorization failures, rate limits, and 5xx responses are not charged. Use the returned job ID directly when creating an application. Developer API v1 does not expose other country catalogs. Authentication: API key Parameters: - query `q`: Text matched against job title and company. - query `ats`: Filter by applicant tracking system. - query `country`: Developer API v1 country. Only US is accepted. - query `remote`: string - query `limit`: integer - query `cursor`: Numeric offset returned as nextCursor. Request body: None Responses: - 200: A page of current jobs. With jobs:read and credits:spend, this response is charged and includes decimal cost plus post-charge balance headers, with exact milli-credit equivalents. - 400: One or more search filters are invalid. - 401: Authentication failed. Code is unauthenticated when the Bearer token is missing and invalid_api_key when the key is invalid, expired, or revoked. - 402: The account does not have enough credits for the requested search page. - 403: The key lacks a required scope (insufficient_scope), or the developer account is frozen for manual review after a payment dispute (account_frozen). - 429: The developer API rate limit was exceeded. Retry after the number of seconds in Retry-After. Example: ```bash curl --include --request GET \ --url 'https://api.applyguy.ai/v1/jobs?q=software%20engineer&ats=greenhouse&country=US&remote=remote&limit=25&cursor=0' \ --header "Authorization: Bearer $APPLYGUY_API_KEY" ``` --- ## GET /v1/jobs/{id} Get a job and cached description Requires both jobs:read and credits:spend. jobs:read alone returns 403 without charging; credits:spend is explicit authorization for this key to incur catalog-read charges and grants no read access by itself. Returns one active U.S. catalog job, enriched role metadata, and the cached employer-provided description. A successful 200 costs 0.01 credit. Invalid IDs, unavailable or stale jobs, authorization failures, rate limits, and 5xx responses are not charged. Description HTML can be loaded from Apply Guy object storage when the database copy is absent. Stale and non-U.S. jobs intentionally return 404. Authentication: API key Parameters: - path `id` (required): Catalog job ID. Request body: None Responses: - 200: Current job detail. With jobs:read and credits:spend, this response is charged and includes decimal cost plus post-charge balance headers, with exact milli-credit equivalents. - 400: The job ID must be a UUID. - 401: Authentication failed. Code is unauthenticated when the Bearer token is missing and invalid_api_key when the key is invalid, expired, or revoked. - 402: The account does not have enough credits to retrieve this job detail. - 403: The key lacks a required scope (insufficient_scope), or the developer account is frozen for manual review after a payment dispute (account_frozen). - 404: The job is unavailable or stale. - 429: The developer API rate limit was exceeded. Retry after the number of seconds in Retry-After. Example: ```bash curl --include --request GET \ --url 'https://api.applyguy.ai/v1/jobs/951f7024-bbf7-4aa5-98fc-f45625584f9b' \ --header "Authorization: Bearer $APPLYGUY_API_KEY" ``` --- ## GET /v1/profile Get the candidate profile Returns the stored candidate context plus resume presence. Requires profile:read. Authentication: API key Parameters: - None Request body: None Responses: - 200: Candidate profile and resume metadata. - 401: Authentication failed. Code is unauthenticated when the Bearer token is missing and invalid_api_key when the key is invalid, expired, or revoked. - 403: The key lacks a required scope (insufficient_scope), or the developer account is frozen for manual review after a payment dispute (account_frozen). - 429: The developer API rate limit was exceeded. Retry after the number of seconds in Retry-After. Example: ```bash curl --request GET \ --url 'https://api.applyguy.ai/v1/profile' \ --header "Authorization: Bearer $APPLYGUY_API_KEY" ``` --- ## PUT /v1/profile Merge candidate profile facts Merges supplied candidateContext properties into the existing profile. Deterministic fields such as name, contact information, address, and LinkedIn are reused directly during applications. Authentication: API key Parameters: - None Request body: application/json (required) ```json { "type": "object", "required": [ "candidateContext" ], "properties": { "candidateContext": { "$ref": "#/components/schemas/CandidateContext" } } } ``` Responses: - 200: Merged candidate profile. - 400: candidateContext is required. - 401: Authentication failed. Code is unauthenticated when the Bearer token is missing and invalid_api_key when the key is invalid, expired, or revoked. - 403: The key lacks a required scope (insufficient_scope), or the developer account is frozen for manual review after a payment dispute (account_frozen). - 413: The profile payload exceeds 256 KB. - 422: The candidate profile contains invalid values. - 429: The developer API rate limit was exceeded. Retry after the number of seconds in Retry-After. Example: ```bash curl --request PUT \ --url 'https://api.applyguy.ai/v1/profile' \ --header "Authorization: Bearer $APPLYGUY_API_KEY" \ --header 'Content-Type: application/json' \ --data '{"candidateContext":{"firstName":"Jordan","lastName":"Bamber","email":"jordan@example.com","phone":"+1 415 555 0199","location":"San Francisco, CA","linkedin":"https://www.linkedin.com/in/jordan-bamber"}}' ``` --- ## PUT /v1/profile/resume Upload the primary resume Uploads a PDF, DOC, or DOCX resume up to 5 MB as multipart field file. The resume safely replaces the prior upload and becomes the default document for applications. Uploads are limited to 5 per minute and 20 per hour per account. Authentication: API key Parameters: - None Request body: multipart/form-data (required) ```json { "type": "object", "required": [ "file" ], "properties": { "file": { "type": "string", "format": "binary" } } } ``` Responses: - 200: Resume uploaded. - 400: Upload a multipart field named file. - 401: Authentication failed. Code is unauthenticated when the Bearer token is missing and invalid_api_key when the key is invalid, expired, or revoked. - 403: The key lacks a required scope (insufficient_scope), or the developer account is frozen for manual review after a payment dispute (account_frozen). - 413: The multipart payload or resume exceeds the 5 MB file limit. - 422: The file type or size is unsupported. - 429: The developer API rate limit was exceeded. Retry after the number of seconds in Retry-After. - 503: Resume storage is temporarily unavailable. Example: ```bash curl --request PUT \ --url 'https://api.applyguy.ai/v1/profile/resume' \ --header "Authorization: Bearer $APPLYGUY_API_KEY" \ --form 'file=@./resume.pdf' ``` --- ## GET /v1/credits Get balance, pricing, and purchase bounds Returns the live balance and pricing. There are 20 credits per dollar. Search costs 0.05 credit per requested block of up to 25 results, a job-detail 200 costs 0.01 credit, managed applications cost 2 credits, and bring-your-own-agent applications cost 1 credit. Authentication: API key Parameters: - None Request body: None Responses: - 200: Credit account. - 401: Authentication failed. Code is unauthenticated when the Bearer token is missing and invalid_api_key when the key is invalid, expired, or revoked. - 403: The key lacks a required scope (insufficient_scope), or the developer account is frozen for manual review after a payment dispute (account_frozen). - 429: The developer API rate limit was exceeded. Retry after the number of seconds in Retry-After. Example: ```bash curl --request GET \ --url 'https://api.applyguy.ai/v1/credits' \ --header "Authorization: Bearer $APPLYGUY_API_KEY" ``` --- ## POST /v1/credits/checkout Create hosted checkout for a dollar amount Creates a Stripe-hosted checkout session for any whole-cent USD amount within the bounds returned by GET /v1/credits. Stripe requires human payment approval. Workday separately requires a one-time human Google Account step to create a Gmail app password. Authentication: API key Parameters: - None Request body: application/json (required) ```json { "type": "object", "required": [ "amountCents" ], "properties": { "amountCents": { "type": "integer", "example": 500, "description": "$5.00, yielding 100 credits at the current rate." } } } ``` Responses: - 201: Hosted checkout URL and expected credit grant. - 400: The amount is outside the advertised purchase bounds. - 401: Authentication failed. Code is unauthenticated when the Bearer token is missing and invalid_api_key when the key is invalid, expired, or revoked. - 403: The key lacks a required scope (insufficient_scope), or the developer account is frozen for manual review after a payment dispute (account_frozen). - 404: The developer credit account was not found. - 413: The JSON payload exceeds 256 KB. - 429: The developer API rate limit was exceeded. Retry after the number of seconds in Retry-After. - 503: Billing is temporarily unavailable. Example: ```bash curl --request POST \ --url 'https://api.applyguy.ai/v1/credits/checkout' \ --header "Authorization: Bearer $APPLYGUY_API_KEY" \ --header 'Content-Type: application/json' \ --data '{"amountCents":500}' ``` --- ## GET /v1/credits/checkout/{id} Poll checkout and reconcile paid credits Returns Stripe checkout state. If payment completed before the webhook arrived, this request safely reconciles the credit grant. Authentication: API key Parameters: - path `id` (required): Stripe Checkout Session ID. Request body: None Responses: - 200: Checkout state. A paid response means the credit grant has been reconciled. - 400: The checkout session ID is invalid. - 401: Authentication failed. Code is unauthenticated when the Bearer token is missing and invalid_api_key when the key is invalid, expired, or revoked. - 403: The key lacks a required scope (insufficient_scope), or the developer account is frozen for manual review after a payment dispute (account_frozen). - 404: The checkout session is not owned by this account. - 429: The developer API rate limit was exceeded. Retry after the number of seconds in Retry-After. - 503: Billing is temporarily unavailable. Example: ```bash curl --request GET \ --url 'https://api.applyguy.ai/v1/credits/checkout/cs_live_a1b2c3' \ --header "Authorization: Bearer $APPLYGUY_API_KEY" ``` --- ## GET /v1/usage Get application and credit usage analytics Returns outcome counts, success rate, completion-time percentiles, credit economics, time-series buckets, ATS/mode/API-key breakdowns, and normalized failure reasons. Requires usage:read. successRate is a 0–100 percentage computed as success / (success + failed) × 100, excluding in-progress and cancelled applications; it is 0 when no outcomes are resolved. Reports contain operational aggregates, not candidate PII. Authentication: API key Parameters: - query `range`: Rolling reporting range. Defaults to 30d. Request body: None Responses: - 200: Usage analytics for the selected range. - 400: The usage range is invalid. - 401: Authentication failed. Code is unauthenticated when the Bearer token is missing and invalid_api_key when the key is invalid, expired, or revoked. - 403: The key lacks a required scope (insufficient_scope), or the developer account is frozen for manual review after a payment dispute (account_frozen). - 429: The developer API rate limit was exceeded. Retry after the number of seconds in Retry-After. Example: ```bash curl --request GET \ --url 'https://api.applyguy.ai/v1/usage' \ --header "Authorization: Bearer $APPLYGUY_API_KEY" ``` --- ## GET /v1/usage/share-links List usage report links Lists revocable report-link metadata for this account. Requires usage:share. The one-time URL and its opaque token are never returned by list operations. Reports contain operational aggregates, not candidate PII. Authentication: API key Parameters: - None Request body: None Responses: - 200: Usage share-link metadata without URLs or tokens. - 401: Authentication failed. Code is unauthenticated when the Bearer token is missing and invalid_api_key when the key is invalid, expired, or revoked. - 403: The key lacks a required scope (insufficient_scope), or the developer account is frozen for manual review after a payment dispute (account_frozen). - 429: The developer API rate limit was exceeded. Retry after the number of seconds in Retry-After. Example: ```bash curl --request GET \ --url 'https://api.applyguy.ai/v1/usage/share-links' \ --header "Authorization: Bearer $APPLYGUY_API_KEY" ``` --- ## POST /v1/usage/share-links Create a read-only usage report link Creates a revocable report link containing operational aggregates but no candidate PII. Requires usage:share. The response is the only time the URL is available. Its opaque token appears only in the URL fragment after #, so browsers do not include it in the initial HTTP navigation request. Store or send the full URL immediately. An account can have at most 20 active links. Authentication: API key Parameters: - None Request body: application/json ```json { "$ref": "#/components/schemas/UsageShareLinkCreate" } ``` Responses: - 201: Share-link metadata plus its one-time fragment-token URL. - 400: The range or expiration is invalid. - 401: Authentication failed. Code is unauthenticated when the Bearer token is missing and invalid_api_key when the key is invalid, expired, or revoked. - 403: The key lacks a required scope (insufficient_scope), or the developer account is frozen for manual review after a payment dispute (account_frozen). - 409: The account already has the maximum 20 active report links. - 413: The share-link payload exceeds 256 KB. - 429: The developer API rate limit was exceeded. Retry after the number of seconds in Retry-After. Example: ```bash curl --request POST \ --url 'https://api.applyguy.ai/v1/usage/share-links' \ --header "Authorization: Bearer $APPLYGUY_API_KEY" \ --header 'Content-Type: application/json' \ --data '{"range":"30d","expiresInSeconds":86400}' ``` --- ## POST /v1/usage/share-links/exchange Exchange a report token for read-only usage analytics Public exchange used by a shared report page. Read the token from the URL fragment, remove the fragment from browser history, then send the token only in this JSON body. Expired, revoked, unknown, and malformed tokens all receive the same generic 404 response. Authentication: No authentication Parameters: - None Request body: application/json (required) ```json { "$ref": "#/components/schemas/UsageShareLinkExchange" } ``` Responses: - 200: The immutable range selected when the link was created. - 400: A token is required in the JSON body. - 404: The report link is unavailable. - 413: The exchange payload exceeds 256 KB. - 429: Too many exchange attempts. Retry after the number of seconds in Retry-After. Example: ```bash curl --request POST \ --url 'https://api.applyguy.ai/v1/usage/share-links/exchange' \ --header 'Content-Type: application/json' \ --data '{"token":"rpt_opaque_fragment_value"}' ``` --- ## DELETE /v1/usage/share-links/{id} Revoke a usage report link Immediately revokes a report link owned by the account. Requires usage:share. Later exchanges return the same generic 404 used for expired or unknown links. Authentication: API key Parameters: - path `id` (required): Usage share-link ID. Request body: None Responses: - 204: Report link revoked. - 400: The share-link ID must be a UUID. - 401: Authentication failed. Code is unauthenticated when the Bearer token is missing and invalid_api_key when the key is invalid, expired, or revoked. - 403: The key lacks a required scope (insufficient_scope), or the developer account is frozen for manual review after a payment dispute (account_frozen). - 404: The report link was not found. - 429: The developer API rate limit was exceeded. Retry after the number of seconds in Retry-After. Example: ```bash curl --request DELETE \ --url 'https://api.applyguy.ai/v1/usage/share-links/ID' \ --header "Authorization: Bearer $APPLYGUY_API_KEY" ``` --- ## POST /v1/applications/preflight Check readiness before spending credits Checks ATS availability, required profile facts, resume presence, inbox requirements, requested mode, and cost. A catalog jobId is also checked for current U.S. catalog eligibility and freshness. A caller-supplied raw jobUrl is validated for supported ATS ownership and URL shape, but its live availability and U.S. suitability are not known until the application runs. Preflight is free and no credits are reserved. Authentication: API key Parameters: - None Request body: application/json (required) ```json { "$ref": "#/components/schemas/ApplicationCreate" } ``` Responses: - 200: Readiness details and exact application cost. - 400: Provide exactly one jobId or jobUrl. - 401: Authentication failed. Code is unauthenticated when the Bearer token is missing and invalid_api_key when the key is invalid, expired, or revoked. - 403: The key lacks a required scope (insufficient_scope), or the developer account is frozen for manual review after a payment dispute (account_frozen). - 404: The catalog job is unavailable or stale. - 413: The JSON payload exceeds 256 KB. - 422: The ATS or raw employer URL is unsupported or unsafe. - 429: The developer API rate limit was exceeded. Retry after the number of seconds in Retry-After. Example: ```bash curl --request POST \ --url 'https://api.applyguy.ai/v1/applications/preflight' \ --header "Authorization: Bearer $APPLYGUY_API_KEY" \ --header 'Content-Type: application/json' \ --data '{"jobId":"951f7024-bbf7-4aa5-98fc-f45625584f9b","mode":"agent"}' ``` --- ## GET /v1/applications List developer applications Returns up to the 100 most recently queued developer applications for the account. applications:read exposes requiresAnswers, but answerRequest and submittedAnswers are redacted unless the key also has profile:read. Authentication: API key Parameters: - None Request body: None Responses: - 200: Recent developer applications. - 401: Authentication failed. Code is unauthenticated when the Bearer token is missing and invalid_api_key when the key is invalid, expired, or revoked. - 403: The key lacks a required scope (insufficient_scope), or the developer account is frozen for manual review after a payment dispute (account_frozen). - 429: The developer API rate limit was exceeded. Retry after the number of seconds in Retry-After. Example: ```bash curl --request GET \ --url 'https://api.applyguy.ai/v1/applications' \ --header "Authorization: Bearer $APPLYGUY_API_KEY" ``` --- ## POST /v1/applications Reserve credits and start an application Queues a job application and atomically reserves its credits. Reusing the same Idempotency-Key with the same API key and equivalent request returns the original application instead of charging twice; reusing it for a different job or mode returns idempotency_conflict. A user can have only one application in progress per canonical employer target. A prior success returns already_applied, and two failed runs for the same target in a rolling 24-hour window return application_retry_limit_reached until the Retry-After delay expires. Rotating API keys, changing idempotency keys, or adding tracking query parameters does not create a new target identity. Authentication: API key Parameters: - header `Idempotency-Key` (required): Unique operation key, at most 200 characters. Request body: application/json (required) ```json { "$ref": "#/components/schemas/ApplicationCreate" } ``` Responses: - 200: The equivalent idempotent request already exists. - 201: Application created and queued. - 400: The body or Idempotency-Key is invalid. - 401: Authentication failed. Code is unauthenticated when the Bearer token is missing and invalid_api_key when the key is invalid, expired, or revoked. - 402: The account does not have enough credits. - 403: The key lacks a required scope (insufficient_scope), or the developer account is frozen for manual review after a payment dispute (account_frozen). - 404: The catalog job is unavailable or stale. - 409: The ATS is disabled, the mode is unsupported, a required inbox is disconnected, an equivalent target is already active/successful, the target reached two failed attempts in 24 hours, or the Idempotency-Key was reused for a different request. Codes: ats_disabled, agent_mode_unsupported, email_integration_required, application_already_in_progress, already_applied, application_retry_limit_reached, idempotency_conflict. Retry-limit responses include failedAttempts, limit, windowHours, retryAt, and retryAfterSeconds details and a Retry-After header. - 413: The JSON payload exceeds 256 KB. - 422: Required profile fields are incomplete, or the ATS/raw employer URL is unsupported or unsafe. - 429: The developer API rate limit was exceeded. Retry after the number of seconds in Retry-After. Example: ```bash curl --request POST \ --url 'https://api.applyguy.ai/v1/applications' \ --header "Authorization: Bearer $APPLYGUY_API_KEY" \ --header 'Idempotency-Key: apply-job-951f7024-v1' \ --header 'Content-Type: application/json' \ --data '{"jobId":"951f7024-bbf7-4aa5-98fc-f45625584f9b","mode":"managed"}' ``` --- ## GET /v1/applications/{id} Get application state Returns the latest state and stable failure reason. requiresAnswers is always visible; candidate-sensitive answerRequest and submittedAnswers require profile:read in addition to applications:read. Authentication: API key Parameters: - path `id` (required): Application ID. Request body: None Responses: - 200: Application state. - 400: The application ID must be a UUID. - 401: Authentication failed. Code is unauthenticated when the Bearer token is missing and invalid_api_key when the key is invalid, expired, or revoked. - 403: The key lacks a required scope (insufficient_scope), or the developer account is frozen for manual review after a payment dispute (account_frozen). - 404: Application not found. - 429: The developer API rate limit was exceeded. Retry after the number of seconds in Retry-After. Example: ```bash curl --request GET \ --url 'https://api.applyguy.ai/v1/applications/529f67cf-7296-40ea-a90a-a1dcc09f1e8d' \ --header "Authorization: Bearer $APPLYGUY_API_KEY" ``` --- ## GET /v1/applications/{id}/answer-request Get a pending agent prompt and JSON Schema When an agent-mode application enters awaiting_answers, fetch this request and have your own model return JSON matching responseSchema. This endpoint requires both applications:read and profile:read because the prompt contains candidate data. Authentication: API key Parameters: - path `id` (required): Application ID. Request body: None Responses: - 200: Pending answer request. - 400: The application ID must be a UUID. - 401: Authentication failed. Code is unauthenticated when the Bearer token is missing and invalid_api_key when the key is invalid, expired, or revoked. - 403: The key lacks a required scope (insufficient_scope), or the developer account is frozen for manual review after a payment dispute (account_frozen). - 404: Application not found. - 409: The application is not awaiting answers. - 429: The developer API rate limit was exceeded. Retry after the number of seconds in Retry-After. Example: ```bash curl --request GET \ --url 'https://api.applyguy.ai/v1/applications/529f67cf-7296-40ea-a90a-a1dcc09f1e8d/answer-request' \ --header "Authorization: Bearer $APPLYGUY_API_KEY" ``` --- ## POST /v1/applications/{id}/answers Validate an agent answer and resume Validates answer against the exact responseSchema, rejects stale fingerprints, and resumes the application. A later form step may create another answer round. Authentication: API key Parameters: - path `id` (required): Application ID. Request body: application/json (required) ```json { "$ref": "#/components/schemas/AgentAnswer" } ``` Responses: - 202: Answer accepted and application re-queued. - 400: The answer envelope is invalid. - 401: Authentication failed. Code is unauthenticated when the Bearer token is missing and invalid_api_key when the key is invalid, expired, or revoked. - 403: The key lacks a required scope (insufficient_scope), or the developer account is frozen for manual review after a payment dispute (account_frozen). - 409: The request is stale or no longer pending. - 413: The external answer envelope exceeds 64 KB. - 422: The answer does not match responseSchema. - 429: The developer API rate limit was exceeded. Retry after the number of seconds in Retry-After. Example: ```bash curl --request POST \ --url 'https://api.applyguy.ai/v1/applications/529f67cf-7296-40ea-a90a-a1dcc09f1e8d/answers' \ --header "Authorization: Bearer $APPLYGUY_API_KEY" \ --header 'Content-Type: application/json' \ --data '{"requestId":"905c7655-7582-4556-a13d-bf49fcb63bf8","fingerprint":"b4fc0d55a3f819c70a37f2f8931f29fb848bff0e1f0b7976e5b04e49c015bbd2","answer":{"answers":[{"fieldId":"work_authorization","value":"Yes"}]}}' ``` --- ## POST /v1/applications/{id}/cancel Cancel before submission Cancels a queued or awaiting-answers application. Reserved developer credits are refunded idempotently. Authentication: API key Parameters: - path `id` (required): Application ID. Request body: None Responses: - 200: Application cancelled and credits refunded. - 400: The application ID must be a UUID. - 401: Authentication failed. Code is unauthenticated when the Bearer token is missing and invalid_api_key when the key is invalid, expired, or revoked. - 403: The key lacks a required scope (insufficient_scope), or the developer account is frozen for manual review after a payment dispute (account_frozen). - 404: Application not found. - 409: The application can no longer be cancelled. - 429: The developer API rate limit was exceeded. Retry after the number of seconds in Retry-After. Example: ```bash curl --request POST \ --url 'https://api.applyguy.ai/v1/applications/529f67cf-7296-40ea-a90a-a1dcc09f1e8d/cancel' \ --header "Authorization: Bearer $APPLYGUY_API_KEY" ``` --- ## GET /v1/webhooks List webhooks Lists webhook endpoints and subscribed events. Signing secrets are never returned after creation. Authentication: API key Parameters: - None Request body: None Responses: - 200: Registered webhooks. - 401: Authentication failed. Code is unauthenticated when the Bearer token is missing and invalid_api_key when the key is invalid, expired, or revoked. - 403: The key lacks a required scope (insufficient_scope), or the developer account is frozen for manual review after a payment dispute (account_frozen). - 429: The developer API rate limit was exceeded. Retry after the number of seconds in Retry-After. Example: ```bash curl --request GET \ --url 'https://api.applyguy.ai/v1/webhooks' \ --header "Authorization: Bearer $APPLYGUY_API_KEY" ``` --- ## POST /v1/webhooks Register a signed HTTPS webhook Registers a public HTTPS endpoint. The HMAC-SHA256 signing secret is returned once. If events is omitted, all application events are subscribed. An account can register at most 10 endpoints and cannot register the same URL twice. Authentication: API key Parameters: - None Request body: application/json (required) ```json { "$ref": "#/components/schemas/WebhookCreate" } ``` Responses: - 201: Webhook and one-time signing secret. - 400: The URL or event list is invalid. - 401: Authentication failed. Code is unauthenticated when the Bearer token is missing and invalid_api_key when the key is invalid, expired, or revoked. - 403: The key lacks a required scope (insufficient_scope), or the developer account is frozen for manual review after a payment dispute (account_frozen). - 409: The URL is already registered or the account has reached 10 webhooks. - 413: The JSON payload exceeds 256 KB. - 422: The URL is not a public HTTPS endpoint. - 429: The developer API rate limit was exceeded. Retry after the number of seconds in Retry-After. Example: ```bash curl --request POST \ --url 'https://api.applyguy.ai/v1/webhooks' \ --header "Authorization: Bearer $APPLYGUY_API_KEY" \ --header 'Content-Type: application/json' \ --data '{"url":"https://agent.example.com/webhooks/applyguy","events":["application.awaiting_answers","application.succeeded","application.failed"]}' ``` --- ## PATCH /v1/webhooks/{id} Update a webhook Changes the URL, event subscriptions, or active state of an existing webhook. Authentication: API key Parameters: - path `id` (required): Webhook ID. Request body: application/json (required) ```json { "type": "object", "properties": { "url": { "type": "string", "format": "uri" }, "events": { "type": "array", "items": { "$ref": "#/components/schemas/WebhookEventType" } }, "active": { "type": "boolean" } } } ``` Responses: - 200: Updated webhook. - 400: The webhook update is invalid. - 401: Authentication failed. Code is unauthenticated when the Bearer token is missing and invalid_api_key when the key is invalid, expired, or revoked. - 403: The key lacks a required scope (insufficient_scope), or the developer account is frozen for manual review after a payment dispute (account_frozen). - 404: Webhook not found. - 413: The JSON payload exceeds 256 KB. - 422: The URL is not a public HTTPS endpoint. - 429: The developer API rate limit was exceeded. Retry after the number of seconds in Retry-After. Example: ```bash curl --request PATCH \ --url 'https://api.applyguy.ai/v1/webhooks/ec41686d-d579-48c6-9b92-b47cfa086f93' \ --header "Authorization: Bearer $APPLYGUY_API_KEY" \ --header 'Content-Type: application/json' \ --data '{"active":false}' ``` --- ## DELETE /v1/webhooks/{id} Delete a webhook Permanently removes a webhook endpoint owned by the account. Authentication: API key Parameters: - path `id` (required): Webhook ID. Request body: None Responses: - 204: Webhook deleted. - 400: The webhook ID must be a UUID. - 401: Authentication failed. Code is unauthenticated when the Bearer token is missing and invalid_api_key when the key is invalid, expired, or revoked. - 403: The key lacks a required scope (insufficient_scope), or the developer account is frozen for manual review after a payment dispute (account_frozen). - 404: Webhook not found. - 429: The developer API rate limit was exceeded. Retry after the number of seconds in Retry-After. Example: ```bash curl --request DELETE \ --url 'https://api.applyguy.ai/v1/webhooks/ec41686d-d579-48c6-9b92-b47cfa086f93' \ --header "Authorization: Bearer $APPLYGUY_API_KEY" ``` --- ## Outbound webhook contract ```json { "applicationStatus": { "post": { "tags": [ "Webhooks" ], "operationId": "receiveApplicationWebhook", "summary": "Receive an application status event", "description": "Apply Guy delivers events at least once. Return any 2xx within 10 seconds to acknowledge. Network errors and non-2xx responses are retried up to 12 total attempts with exponential backoff beginning at 30 seconds and capped at one hour. Deduplicate with the stable event ID in the body or X-ApplyGuy-Delivery. Verify X-ApplyGuy-Signature before parsing or acting: compute the lowercase hex HMAC-SHA256 of `.` using the one-time webhook secret, then compare it to the value after `v1=` using a timing-safe comparison.", "parameters": [ { "name": "X-ApplyGuy-Event", "in": "header", "required": true, "description": "Event type.", "schema": { "$ref": "#/components/schemas/WebhookEventType" } }, { "name": "X-ApplyGuy-Delivery", "in": "header", "required": true, "description": "Stable event/delivery identifier.", "schema": { "type": "string", "format": "uuid" } }, { "name": "X-ApplyGuy-Timestamp", "in": "header", "required": true, "description": "Unix timestamp in seconds used in the signature input.", "schema": { "type": "string", "pattern": "^[0-9]+$" } }, { "name": "X-ApplyGuy-Signature", "in": "header", "required": true, "description": "Versioned HMAC-SHA256 signature of timestamp dot raw body.", "schema": { "type": "string", "pattern": "^v1=[a-f0-9]{64}$" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookEvent" }, "example": { "id": "f0279a18-4c2d-4973-8f26-37d60e88ada3", "type": "application.awaiting_answers", "createdAt": "2026-08-23T18:04:11.000Z", "data": { "applicationId": "529f67cf-7296-40ea-a90a-a1dcc09f1e8d", "status": "awaiting_answers" } } } } }, "responses": { "2XX": { "description": "Event acknowledged; no retry is scheduled." } } } } } ``` --- ## Component schemas Every request and response `$ref` used above resolves to one of these canonical schemas. ### Error ```json { "type": "object", "required": [ "error" ], "properties": { "error": { "type": "object", "required": [ "code", "message", "requestId" ], "properties": { "code": { "type": "string", "example": "invalid_request" }, "message": { "type": "string", "example": "The request could not be processed." }, "requestId": { "type": "string", "example": "req_01JYZ6K2R8YV4R8G9AWM7M6XBP" }, "details": { "description": "Optional structured validation or recovery details." } } } } } ``` ### ManagementError ```json { "type": "object", "required": [ "error" ], "description": "Error envelope used by account and API-key management routes.", "properties": { "error": { "type": "string", "example": "invalid_input" }, "details": { "description": "Optional structured validation details." }, "login": { "type": "string", "description": "Login path returned when the email already has an account." }, "retryAfter": { "type": "integer", "description": "Seconds until a rate-limited request can be retried." } } } ``` ### DeveloperScope ```json { "type": "string", "description": "A least-privilege API-key capability. jobs:read permits catalog access; credits:spend separately authorizes a key to incur the documented job-search and job-detail charges. Both are required for billable catalog reads, and credits:spend grants no read access by itself.", "enum": [ "jobs:read", "credits:spend", "profile:read", "profile:write", "credits:read", "credits:write", "applications:read", "applications:write", "webhooks:write", "usage:read", "usage:share" ] } ``` ### DeveloperBootstrap ```json { "type": "object", "required": [ "email", "password" ], "properties": { "email": { "type": "string", "format": "email", "example": "agent-builder@example.com" }, "password": { "type": "string", "format": "password", "minLength": 8, "writeOnly": true, "example": "correct-horse-battery-staple" }, "name": { "type": "string", "default": "Default agent", "maxLength": 80, "example": "Production agent" }, "scopes": { "type": "array", "minItems": 1, "items": { "$ref": "#/components/schemas/DeveloperScope" }, "example": [ "jobs:read", "credits:spend", "profile:read", "profile:write", "credits:read", "credits:write", "applications:read", "applications:write", "webhooks:write", "usage:read", "usage:share" ] }, "expiresAt": { "type": "string", "format": "date-time", "example": "2027-08-23T00:00:00.000Z" } } } ``` ### DeveloperBootstrapResult ```json { "type": "object", "required": [ "user", "apiKey", "accessToken", "refreshToken", "credits", "next", "warning" ], "properties": { "user": { "type": "object", "required": [ "id", "email", "createdAt" ], "properties": { "id": { "type": "string", "format": "uuid" }, "email": { "type": "string", "format": "email" }, "createdAt": { "type": "string", "format": "date-time" } } }, "apiKey": { "type": "object", "required": [ "id", "key", "prefix", "scopes" ], "properties": { "id": { "type": "string", "format": "uuid" }, "key": { "type": "string", "readOnly": true, "example": "ag_live_7ab4d918f903_••••••••••••••••" }, "prefix": { "type": "string", "example": "7ab4d918f903" }, "scopes": { "type": "array", "items": { "$ref": "#/components/schemas/DeveloperScope" } } } }, "accessToken": { "type": "string", "readOnly": true, "description": "Short-lived account JWT for API-key management." }, "refreshToken": { "type": "string", "readOnly": true, "description": "Long-lived account token. This is its only response." }, "credits": { "type": "number", "const": 0 }, "next": { "type": "object", "additionalProperties": { "type": "string" } }, "warning": { "type": "string", "example": "Store the API key and refresh token now. Neither can be retrieved again." } } } ``` ### SessionRefresh ```json { "type": "object", "required": [ "refreshToken" ], "properties": { "refreshToken": { "type": "string", "writeOnly": true, "description": "The latest refresh token. Refresh tokens rotate on every successful use." } }, "additionalProperties": false } ``` ### SessionRefreshResult ```json { "type": "object", "required": [ "accessToken", "refreshToken" ], "properties": { "accessToken": { "type": "string", "readOnly": true }, "refreshToken": { "type": "string", "readOnly": true, "description": "Replacement refresh token. Atomically replace the token sent in the request." } } } ``` ### ApiKeyCreate ```json { "type": "object", "properties": { "name": { "type": "string", "default": "Default agent", "maxLength": 80, "example": "CI application agent" }, "scopes": { "type": "array", "minItems": 1, "items": { "$ref": "#/components/schemas/DeveloperScope" }, "example": [ "jobs:read", "credits:spend", "applications:read", "applications:write" ] }, "expiresAt": { "type": "string", "format": "date-time", "example": "2027-08-23T00:00:00.000Z" } } } ``` ### ApiKey ```json { "type": "object", "required": [ "id", "name", "prefix", "scopes", "createdAt" ], "properties": { "id": { "type": "string", "format": "uuid" }, "name": { "type": "string" }, "prefix": { "type": "string", "example": "7ab4d918f903" }, "scopes": { "type": "array", "items": { "$ref": "#/components/schemas/DeveloperScope" } }, "lastUsedAt": { "type": [ "string", "null" ], "format": "date-time" }, "expiresAt": { "type": [ "string", "null" ], "format": "date-time" }, "revokedAt": { "type": [ "string", "null" ], "format": "date-time" }, "createdAt": { "type": "string", "format": "date-time" } } } ``` ### ApiKeyCreated ```json { "allOf": [ { "$ref": "#/components/schemas/ApiKey" }, { "type": "object", "required": [ "key", "warning" ], "properties": { "key": { "type": "string", "readOnly": true, "example": "ag_live_7ab4d918f903_••••••••••••••••" }, "warning": { "type": "string", "example": "Store this key now. It cannot be retrieved again." } } } ], "description": "API-key metadata plus the one-time plaintext secret returned only on creation." } ``` ### EmailIntegrationCreate ```json { "type": "object", "required": [ "gmailUser", "gmailAppPassword" ], "properties": { "gmailUser": { "type": "string", "format": "email", "example": "candidate@gmail.com" }, "gmailAppPassword": { "type": "string", "minLength": 16, "maxLength": 19, "writeOnly": true, "description": "A 16-character Gmail app password. Spaces are accepted and removed before validation; this is not the Gmail account password.", "example": "abcd efgh ijkl mnop" } }, "additionalProperties": false } ``` ### EmailIntegrationStatus ```json { "type": "object", "required": [ "emailIntegration" ], "properties": { "emailIntegration": { "type": "object", "required": [ "configured", "requiredAts" ], "properties": { "configured": { "type": "boolean" }, "requiredAts": { "type": "array", "items": { "type": "string" }, "example": [ "workday" ] } } } } } ``` ### JobSummary ```json { "type": "object", "required": [ "id", "title", "company", "ats", "url", "country" ], "properties": { "id": { "type": "string", "format": "uuid", "example": "951f7024-bbf7-4aa5-98fc-f45625584f9b" }, "title": { "type": "string", "example": "Software Engineer" }, "company": { "type": "string", "example": "Example Labs" }, "companySlug": { "type": [ "string", "null" ], "example": "example-labs" }, "ats": { "type": "string", "example": "greenhouse" }, "url": { "type": "string", "format": "uri", "example": "https://boards.greenhouse.io/example/jobs/123456" }, "location": { "type": [ "string", "null" ], "example": "New York, NY" }, "city": { "type": [ "string", "null" ], "example": "New York" }, "state": { "type": [ "string", "null" ], "example": "New York" }, "country": { "type": "string", "const": "US", "example": "US", "description": "Developer API v1 exposes U.S. catalog jobs only." }, "remoteType": { "type": [ "string", "null" ], "enum": [ "remote", "hybrid", "onsite", null ] }, "employmentType": { "type": [ "string", "null" ], "example": "full-time" }, "salaryMin": { "type": [ "number", "null" ], "example": 120000 }, "salaryMax": { "type": [ "number", "null" ], "example": 165000 }, "salaryCurrency": { "type": [ "string", "null" ], "example": "USD" }, "postedAt": { "type": [ "string", "null" ], "format": "date-time" }, "firstSeenAt": { "type": [ "string", "null" ], "format": "date-time" }, "canonicalTitle": { "type": [ "string", "null" ], "example": "Software Engineer" }, "roleFamily": { "type": [ "string", "null" ], "example": "software_engineering" }, "skills": { "type": [ "array", "null" ], "items": { "type": "string" }, "example": [ "TypeScript", "PostgreSQL" ] }, "minimumExperienceYears": { "type": [ "number", "null" ], "minimum": 0, "example": 2 }, "maximumExperienceYears": { "type": [ "number", "null" ], "minimum": 0, "example": 5 }, "educationLevel": { "type": [ "string", "null" ], "example": "bachelors" }, "sponsorship": { "type": [ "string", "null" ], "example": "not_available" }, "clearanceRequired": { "type": [ "boolean", "null" ], "example": false } } } ``` ### JobDetail ```json { "allOf": [ { "$ref": "#/components/schemas/JobSummary" }, { "type": "object", "properties": { "descriptionHtml": { "type": [ "string", "null" ], "description": "Employer-provided job description HTML." }, "descriptionSections": { "type": [ "object", "array", "null" ], "description": "Parsed description sections when available." }, "specialties": { "type": [ "array", "null" ], "items": { "type": "string" } }, "requiredSkills": { "type": [ "array", "null" ], "items": { "type": "string" } }, "clearanceLabel": { "type": [ "string", "null" ] }, "travelPercent": { "type": [ "number", "null" ], "minimum": 0, "maximum": 100 } } } ] } ``` ### Address ```json { "type": "object", "required": [ "line1", "city", "state", "postalCode", "country" ], "properties": { "line1": { "type": "string", "maxLength": 500, "example": "501 Delancey Street" }, "line2": { "type": "string", "maxLength": 500, "example": "Apt 4B" }, "city": { "type": "string", "maxLength": 500, "example": "San Francisco" }, "state": { "type": "string", "maxLength": 500, "description": "Full state or region name.", "example": "California" }, "postalCode": { "type": "string", "maxLength": 30, "example": "94107" }, "country": { "type": "string", "maxLength": 500, "description": "Full country descriptor. Candidate normalization is U.S.-centric in v1.", "example": "United States of America" }, "county": { "type": "string", "maxLength": 500, "example": "San Francisco County" } }, "additionalProperties": false } ``` ### WorkHistoryEntry ```json { "type": "object", "required": [ "company", "title", "startDate" ], "properties": { "company": { "type": "string", "maxLength": 500 }, "title": { "type": "string", "maxLength": 500 }, "startDate": { "type": "string", "maxLength": 7, "example": "2024-01" }, "endDate": { "type": "string", "maxLength": 7, "example": "2026-08" }, "current": { "type": "boolean" }, "location": { "type": "string", "maxLength": 500 }, "summary": { "type": "string", "maxLength": 10000 }, "highlights": { "type": "array", "maxItems": 100, "items": { "type": "string", "maxLength": 2000 } } }, "additionalProperties": false } ``` ### EducationEntry ```json { "type": "object", "required": [ "school", "city", "state" ], "properties": { "school": { "type": "string", "maxLength": 500 }, "city": { "type": "string", "maxLength": 500 }, "state": { "type": "string", "maxLength": 500 }, "degree": { "type": "string", "maxLength": 500 }, "discipline": { "type": "string", "maxLength": 500 }, "startDate": { "type": "string", "maxLength": 7 }, "endDate": { "type": "string", "maxLength": 7 }, "gpa": { "type": "string", "maxLength": 30 } }, "additionalProperties": false } ``` ### WorkAuthorization ```json { "type": "object", "required": [ "country", "status", "requiresSponsorship" ], "properties": { "country": { "type": "string", "minLength": 2, "maxLength": 2, "example": "US" }, "status": { "type": "string", "enum": [ "citizen", "permanent-resident", "work-visa", "requires-sponsorship", "student-visa", "other" ] }, "requiresSponsorship": { "type": "boolean" } }, "additionalProperties": false } ``` ### LegalDeclarations ```json { "type": "object", "properties": { "hasActiveNonCompete": { "type": "boolean" }, "legalWorkCountries": { "type": "array", "maxItems": 50, "items": { "type": "string", "minLength": 2, "maxLength": 2 } } }, "additionalProperties": false } ``` ### WorkPreferences ```json { "type": "object", "properties": { "remotePreference": { "type": "string", "enum": [ "remote", "hybrid", "onsite", "flexible" ] }, "willingToRelocate": { "type": "boolean" }, "willingToCommuteDaysPerWeek": { "type": "integer", "minimum": 0, "maximum": 7 }, "salaryRangeUsd": { "type": "object", "required": [ "min", "max" ], "properties": { "min": { "type": "number", "minimum": 0 }, "max": { "type": "number", "minimum": 0 } }, "additionalProperties": false }, "notes": { "type": "string", "maxLength": 10000 } }, "additionalProperties": false } ``` ### Demographics ```json { "type": "object", "properties": { "defaultDisclosure": { "type": "string", "enum": [ "share", "decline" ] }, "gender": { "type": "string", "maxLength": 500 }, "ethnicity": { "type": "string", "maxLength": 500 }, "hispanicOrLatino": { "type": "boolean" }, "veteranStatus": { "type": "string", "enum": [ "veteran", "not-veteran", "prefer-not-to-say" ] }, "militaryStatus": { "type": "string", "enum": [ "none", "active-duty", "reserve", "national-guard", "veteran", "prefer-not-to-say" ] }, "disabilityStatus": { "type": "string", "enum": [ "yes", "no", "prefer-not-to-say" ] }, "transgender": { "type": "boolean" }, "lgbtq": { "type": "boolean" } }, "additionalProperties": false } ``` ### CandidateContext ```json { "type": "object", "description": "Candidate facts used to fill employer forms. PUT merges supplied properties into the stored profile.", "properties": { "firstName": { "type": "string", "maxLength": 500, "example": "Jordan" }, "lastName": { "type": "string", "maxLength": 500, "example": "Bamber" }, "email": { "type": "string", "maxLength": 320, "example": "jordan@example.com" }, "phone": { "type": "string", "maxLength": 40, "example": "+1 415 555 0199" }, "location": { "type": "string", "maxLength": 500, "example": "San Francisco, CA" }, "address": { "anyOf": [ { "$ref": "#/components/schemas/Address" }, { "type": "null" } ] }, "linkedin": { "type": "string", "maxLength": 2048, "example": "https://www.linkedin.com/in/jordan-bamber" }, "website": { "type": "string", "maxLength": 2048 }, "github": { "type": "string", "maxLength": 2048, "example": "https://github.com/jordan" }, "portfolio": { "type": "string", "maxLength": 2048 }, "resumeText": { "type": "string", "maxLength": 100000, "description": "Extracted resume text used for open-ended answers." }, "workHistory": { "type": "array", "maxItems": 100, "items": { "$ref": "#/components/schemas/WorkHistoryEntry" } }, "education": { "type": "array", "maxItems": 50, "items": { "$ref": "#/components/schemas/EducationEntry" } }, "skills": { "type": "array", "maxItems": 500, "items": { "type": "string", "maxLength": 500 }, "example": [ "TypeScript", "PostgreSQL", "AWS" ] }, "yearsOfExperience": { "type": "object", "additionalProperties": { "type": "number", "minimum": 0, "maximum": 100 } }, "bio": { "type": "string", "maxLength": 20000 }, "motivations": { "type": "string", "maxLength": 20000 }, "discoverySource": { "type": "string", "maxLength": 500, "example": "internet" }, "workAuthorization": { "$ref": "#/components/schemas/WorkAuthorization" }, "legalDeclarations": { "$ref": "#/components/schemas/LegalDeclarations" }, "workPreferences": { "$ref": "#/components/schemas/WorkPreferences" }, "demographics": { "$ref": "#/components/schemas/Demographics" } }, "additionalProperties": false } ``` ### ApplicationCreate ```json { "type": "object", "oneOf": [ { "required": [ "jobId" ] }, { "required": [ "jobUrl" ] } ], "properties": { "jobId": { "type": "string", "format": "uuid", "description": "A job returned by the catalog.", "example": "951f7024-bbf7-4aa5-98fc-f45625584f9b" }, "jobUrl": { "type": "string", "format": "uri", "maxLength": 2048, "description": "A supported platform-owned HTTPS employer application URL for a caller-selected U.S.-appropriate role. Raw URL availability is resolved during application execution.", "example": "https://boards.greenhouse.io/example/jobs/123456" }, "ats": { "type": "string", "minLength": 1, "maxLength": 50, "description": "Optional ATS hint when submitting a URL. It must agree with the URL host.", "example": "greenhouse" }, "mode": { "type": "string", "enum": [ "managed", "agent" ], "default": "managed", "description": "Managed costs 2 credits. Agent mode costs 1 credit and requests structured answers from your agent." } } } ``` ### ApplicationStatus ```json { "type": "string", "description": "Applications in agent mode can enter awaiting_answers one or more times.", "enum": [ "queued", "running", "awaiting_answers", "success", "failed", "cancelled" ] } ``` ### ApplicationOutcomeCode ```json { "type": [ "string", "null" ], "pattern": "^[a-z][a-z0-9_]*$", "description": "Stable, public failure classification. Known codes are job_no_longer_available, invalid_job_url, profile_missing, resume_missing, email_integration_required, captcha_failed, application_input_required, submission_outcome_unknown, already_applied, application_limit_reached, and application_failed. New codes may be added without a version bump; branch on known values and keep an unknown fallback.", "examples": [ "job_no_longer_available", "invalid_job_url", "profile_missing", "resume_missing", "email_integration_required", "captcha_failed", "application_input_required", "submission_outcome_unknown", "already_applied", "application_limit_reached", "application_failed" ] } ``` ### ApplicationOutcomeDetails ```json { "type": [ "object", "null" ], "description": "Structured metadata for an outcome code when available. For application_limit_reached, maxApplications and windowDays identify the limit window.", "properties": { "maxApplications": { "type": "integer", "minimum": 1 }, "windowDays": { "type": "integer", "minimum": 1 } }, "additionalProperties": true } ``` ### ApplicationCreateResult ```json { "type": "object", "required": [ "id", "status", "created" ], "properties": { "id": { "type": "string", "format": "uuid" }, "status": { "$ref": "#/components/schemas/ApplicationStatus" }, "created": { "type": "boolean", "description": "False when this is the original resource for an idempotent replay." } } } ``` ### Application ```json { "type": "object", "required": [ "id", "jobUrl", "mode", "status", "error", "outcomeCode", "outcomeDetails", "failureCode", "requiresAnswers", "answerRequest", "submittedAnswers" ], "description": "Application state. answerRequest and submittedAnswers contain candidate-sensitive prompt/answer data and are returned only when the calling key also has profile:read. requiresAnswers remains available to applications:read-only keys.", "properties": { "id": { "type": "string", "format": "uuid", "example": "529f67cf-7296-40ea-a90a-a1dcc09f1e8d" }, "jobUrl": { "type": "string", "format": "uri" }, "ats": { "type": [ "string", "null" ], "example": "workday" }, "company": { "type": [ "string", "null" ], "example": "Example Labs" }, "jobTitle": { "type": [ "string", "null" ], "example": "Software Engineer" }, "mode": { "type": "string", "example": "agent" }, "status": { "$ref": "#/components/schemas/ApplicationStatus" }, "error": { "type": [ "string", "null" ], "deprecated": true, "description": "Legacy-safe alias of outcomeCode. Raw ATS diagnostics are never exposed; new clients should use outcomeCode." }, "outcomeCode": { "$ref": "#/components/schemas/ApplicationOutcomeCode", "description": "Normalized special outcome for either success or failure. success with already_applied means the employer already had this candidate's application and Apply Guy did not send a duplicate." }, "outcomeDetails": { "$ref": "#/components/schemas/ApplicationOutcomeDetails" }, "failureCode": { "$ref": "#/components/schemas/ApplicationOutcomeCode", "description": "Same normalized value as outcomeCode only when status is failed; otherwise null." }, "answerRound": { "type": "integer", "minimum": 0 }, "requiresAnswers": { "type": "boolean", "description": "True when the application is awaiting an external answer, even when answerRequest is redacted." }, "answerRequest": { "anyOf": [ { "$ref": "#/components/schemas/AnswerRequest" }, { "type": "null" } ], "description": "Present only while awaiting_answers and only for keys with profile:read." }, "queuedAt": { "type": [ "string", "null" ], "format": "date-time" }, "startedAt": { "type": [ "string", "null" ], "format": "date-time" }, "finishedAt": { "type": [ "string", "null" ], "format": "date-time" }, "submittedAnswers": { "type": [ "object", "null" ], "additionalProperties": true, "description": "Answer audit data, returned only for keys with profile:read." } } } ``` ### ApplicationPreflight ```json { "type": "object", "required": [ "jobUrl", "ats", "ready", "atsEnabled", "modeSupported", "emailIntegrationRequired", "emailIntegrationConnected", "hasResume", "hasUploadedResume", "missingProfileFields", "mode", "cost", "formDiscovery" ], "properties": { "jobUrl": { "type": "string", "format": "uri" }, "ats": { "type": [ "string", "null" ], "example": "greenhouse" }, "ready": { "type": "boolean", "description": "True only when the ATS, requested mode, profile, resume, and integrations are ready." }, "atsEnabled": { "type": "boolean" }, "modeSupported": { "type": "boolean", "description": "False when this ATS does not support the requested mode. SmartRecruiters is managed-only in v1." }, "emailIntegrationRequired": { "type": "boolean" }, "emailIntegrationConnected": { "type": "boolean" }, "hasResume": { "type": "boolean", "description": "True when an uploaded PDF, DOC, or DOCX is available to the application worker." }, "hasUploadedResume": { "type": "boolean" }, "missingProfileFields": { "type": "array", "description": "Exact profile fields that would block application creation for this ATS.", "items": { "type": "string" }, "example": [] }, "mode": { "type": "string", "enum": [ "managed", "agent" ] }, "cost": { "type": "number", "example": 1 }, "formDiscovery": { "type": [ "string", "null" ], "enum": [ "during_application", null ] } } } ``` ### AnswerRequest ```json { "type": "object", "required": [ "id", "fingerprint", "prompt", "responseSchema", "createdAt" ], "properties": { "id": { "type": "string", "format": "uuid", "description": "Send this value back as requestId in the answer envelope." }, "fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, "prompt": { "description": "Structured AI SDK prompt payload containing the complete instructions and candidate/job context for this answer round." }, "responseSchema": { "type": "object", "description": "JSON Schema that the submitted answer must satisfy." }, "createdAt": { "type": "string", "format": "date-time" } } } ``` ### AgentAnswer ```json { "type": "object", "required": [ "requestId", "fingerprint", "answer" ], "properties": { "requestId": { "type": "string", "format": "uuid", "example": "905c7655-7582-4556-a13d-bf49fcb63bf8" }, "fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "example": "b4fc0d55a3f819c70a37f2f8931f29fb848bff0e1f0b7976e5b04e49c015bbd2" }, "answer": { "description": "JSON value conforming exactly to answerRequest.responseSchema.", "example": { "answers": [ { "fieldId": "work_authorization", "value": "Yes" } ] } } } } ``` ### CreditAccount ```json { "type": "object", "required": [ "balance", "balanceMilli", "costs", "creditsPerDollar" ], "properties": { "balance": { "type": "number", "example": 100 }, "balanceMilli": { "type": "integer", "description": "Internal thousandths of a credit.", "example": 100000 }, "costs": { "type": "object", "required": [ "managed", "agent", "searchPer25", "jobDetail" ], "properties": { "managed": { "type": "number", "const": 2, "example": 2 }, "agent": { "type": "number", "const": 1, "example": 1 }, "searchPer25": { "type": "number", "const": 0.05, "example": 0.05, "description": "Cost for each requested block of up to 25 search results." }, "jobDetail": { "type": "number", "const": 0.01, "example": 0.01, "description": "Cost for a job-detail request that returns 200." } } }, "creditsPerDollar": { "type": "integer", "const": 20, "example": 20 }, "minimumPurchaseCents": { "type": "integer", "example": 500 }, "maximumPurchaseCents": { "type": "integer", "example": 100000 } } } ``` ### CheckoutCreate ```json { "type": "object", "required": [ "checkoutUrl", "sessionId", "amountCents", "credits" ], "properties": { "checkoutUrl": { "type": "string", "format": "uri", "example": "https://checkout.stripe.com/c/pay/cs_live_a1b2c3" }, "sessionId": { "type": "string", "example": "cs_live_a1b2c3" }, "amountCents": { "type": "integer", "example": 500 }, "credits": { "type": "number", "example": 100 } } } ``` ### CheckoutStatus ```json { "type": "object", "required": [ "id", "status", "paymentStatus" ], "properties": { "id": { "type": "string", "example": "cs_live_a1b2c3" }, "status": { "type": [ "string", "null" ], "example": "complete" }, "paymentStatus": { "type": "string", "example": "paid" } } } ``` ### UsageRange ```json { "type": "string", "enum": [ "24h", "7d", "30d", "90d" ], "default": "30d", "description": "Rolling reporting window ending at the response endsAt timestamp." } ``` ### UsageStatusCounts ```json { "type": "object", "required": [ "queued", "running", "awaiting_answers", "success", "failed", "cancelled" ], "properties": { "queued": { "type": "integer", "minimum": 0 }, "running": { "type": "integer", "minimum": 0 }, "awaiting_answers": { "type": "integer", "minimum": 0 }, "success": { "type": "integer", "minimum": 0 }, "failed": { "type": "integer", "minimum": 0 }, "cancelled": { "type": "integer", "minimum": 0 } }, "additionalProperties": false } ``` ### UsageCreditMetrics ```json { "type": "object", "required": [ "purchased", "spent", "refunded", "netUsed", "currentBalance", "purchasedMilli", "spentMilli", "refundedMilli", "netUsedMilli", "currentBalanceMilli" ], "properties": { "purchased": { "type": "number", "description": "Credits purchased during the selected range." }, "spent": { "type": "number", "description": "Gross credits debited for application reservations and job-catalog reads during the selected range." }, "refunded": { "type": "number", "description": "Application credits refunded during the selected range." }, "netUsed": { "type": "number", "description": "Spent minus refunded credits during the selected range." }, "currentBalance": { "type": "number", "description": "Account balance at report generation time." }, "purchasedMilli": { "type": "integer", "description": "Purchased amount in thousandths of a credit." }, "spentMilli": { "type": "integer", "description": "Gross application-reservation and job-catalog read spend in thousandths of a credit." }, "refundedMilli": { "type": "integer", "description": "Refunded amount in thousandths of a credit." }, "netUsedMilli": { "type": "integer", "description": "Net usage in thousandths of a credit." }, "currentBalanceMilli": { "type": "integer", "description": "Current balance in thousandths of a credit." } }, "additionalProperties": false } ``` ### UsageTimeSeriesPoint ```json { "type": "object", "required": [ "start", "applications", "success", "failed", "creditsSpentMilli" ], "properties": { "start": { "type": "string", "format": "date-time" }, "applications": { "type": "integer", "minimum": 0 }, "success": { "type": "integer", "minimum": 0 }, "failed": { "type": "integer", "minimum": 0 }, "creditsSpentMilli": { "type": "integer", "minimum": 0, "description": "Gross application-reservation and job-catalog read spend in this time bucket." } }, "additionalProperties": false } ``` ### UsageAtsBreakdown ```json { "type": "object", "required": [ "ats", "applications", "success", "failed", "successRate", "creditsSpentMilli" ], "properties": { "ats": { "type": "string", "example": "greenhouse" }, "applications": { "type": "integer", "minimum": 0 }, "success": { "type": "integer", "minimum": 0 }, "failed": { "type": "integer", "minimum": 0 }, "successRate": { "type": "number", "minimum": 0, "maximum": 100, "description": "Resolved-outcome success percentage from 0 to 100." }, "creditsSpentMilli": { "type": "integer", "minimum": 0, "description": "Application reservation spend attributed to this ATS. Catalog-read spend is excluded." } }, "additionalProperties": false } ``` ### UsageModeBreakdown ```json { "type": "object", "required": [ "mode", "applications", "success", "failed", "successRate", "creditsSpentMilli" ], "properties": { "mode": { "type": "string", "enum": [ "managed", "agent" ] }, "applications": { "type": "integer", "minimum": 0 }, "success": { "type": "integer", "minimum": 0 }, "failed": { "type": "integer", "minimum": 0 }, "successRate": { "type": "number", "minimum": 0, "maximum": 100, "description": "Resolved-outcome success percentage from 0 to 100." }, "creditsSpentMilli": { "type": "integer", "minimum": 0, "description": "Application reservation spend attributed to this execution mode. Catalog-read spend is excluded." } }, "additionalProperties": false } ``` ### UsageApiKeyBreakdown ```json { "type": "object", "required": [ "apiKeyId", "name", "prefix", "applications", "success", "failed", "successRate", "creditsSpentMilli" ], "properties": { "apiKeyId": { "type": "string", "format": "uuid" }, "name": { "type": "string" }, "prefix": { "type": "string" }, "applications": { "type": "integer", "minimum": 0 }, "success": { "type": "integer", "minimum": 0 }, "failed": { "type": "integer", "minimum": 0 }, "successRate": { "type": "number", "minimum": 0, "maximum": 100, "description": "Resolved-outcome success percentage from 0 to 100." }, "creditsSpentMilli": { "type": "integer", "minimum": 0, "description": "Gross application-reservation and job-catalog read spend attributed to this API key." } }, "additionalProperties": false } ``` ### UsageReport ```json { "type": "object", "required": [ "range", "startsAt", "endsAt", "bucket", "summary", "timeSeries", "byAts", "byMode", "byApiKey", "failureReasons" ], "properties": { "range": { "$ref": "#/components/schemas/UsageRange" }, "startsAt": { "type": "string", "format": "date-time" }, "endsAt": { "type": "string", "format": "date-time" }, "bucket": { "type": "string", "enum": [ "hour", "day" ] }, "summary": { "type": "object", "required": [ "applications", "statuses", "successful", "successRate", "credits", "completionMs" ], "properties": { "applications": { "type": "integer", "minimum": 0 }, "statuses": { "$ref": "#/components/schemas/UsageStatusCounts" }, "successful": { "type": "integer", "minimum": 0 }, "successRate": { "type": "number", "minimum": 0, "maximum": 100, "description": "Resolved-outcome success percentage: success / (success + failed) × 100, rounded to two decimal places. Excludes queued, running, awaiting-answers, and cancelled applications. Returns 0 when there are no resolved outcomes." }, "credits": { "$ref": "#/components/schemas/UsageCreditMetrics" }, "completionMs": { "type": "object", "required": [ "p50", "p95" ], "properties": { "p50": { "type": [ "number", "null" ], "minimum": 0, "description": "Median completion time in milliseconds, or null with no completed applications." }, "p95": { "type": [ "number", "null" ], "minimum": 0, "description": "95th-percentile completion time in milliseconds, or null with no completed applications." } }, "additionalProperties": false } }, "additionalProperties": false }, "timeSeries": { "type": "array", "items": { "$ref": "#/components/schemas/UsageTimeSeriesPoint" } }, "byAts": { "type": "array", "items": { "$ref": "#/components/schemas/UsageAtsBreakdown" } }, "byMode": { "type": "array", "items": { "$ref": "#/components/schemas/UsageModeBreakdown" } }, "byApiKey": { "type": "array", "items": { "$ref": "#/components/schemas/UsageApiKeyBreakdown" } }, "failureReasons": { "type": "array", "items": { "type": "object", "required": [ "reason", "count" ], "properties": { "reason": { "type": "string" }, "count": { "type": "integer", "minimum": 0 } }, "additionalProperties": false } } }, "additionalProperties": false } ``` ### UsageShareLinkCreate ```json { "type": "object", "properties": { "range": { "$ref": "#/components/schemas/UsageRange" }, "expiresInSeconds": { "type": "integer", "minimum": 3600, "maximum": 604800, "default": 86400, "description": "Link lifetime from one hour through seven days." } }, "additionalProperties": false } ``` ### UsageShareLinkCreator ```json { "oneOf": [ { "type": "object", "required": [ "type", "apiKeyId", "name", "prefix" ], "properties": { "type": { "type": "string", "const": "api_key" }, "apiKeyId": { "type": [ "string", "null" ], "format": "uuid" }, "name": { "type": [ "string", "null" ] }, "prefix": { "type": [ "string", "null" ] } }, "additionalProperties": false }, { "type": "object", "required": [ "type" ], "properties": { "type": { "type": "string", "const": "session" } }, "additionalProperties": false } ] } ``` ### UsageShareLink ```json { "type": "object", "required": [ "id", "range", "expiresAt", "revokedAt", "createdAt", "lastViewedAt", "viewCount", "creator" ], "description": "Revocable report-link metadata. Listing never exposes the URL or opaque token.", "properties": { "id": { "type": "string", "format": "uuid" }, "range": { "$ref": "#/components/schemas/UsageRange" }, "expiresAt": { "type": "string", "format": "date-time" }, "revokedAt": { "type": [ "string", "null" ], "format": "date-time" }, "createdAt": { "type": "string", "format": "date-time" }, "lastViewedAt": { "type": [ "string", "null" ], "format": "date-time" }, "viewCount": { "type": "integer", "minimum": 0 }, "creator": { "$ref": "#/components/schemas/UsageShareLinkCreator" } }, "additionalProperties": false } ``` ### UsageShareLinkCreated ```json { "allOf": [ { "$ref": "#/components/schemas/UsageShareLink" }, { "type": "object", "required": [ "url" ], "properties": { "url": { "type": "string", "format": "uri", "readOnly": true, "example": "https://applyguy.ai/developers/usage#rpt_example", "description": "One-time report URL. The opaque token is the raw fragment after #, so it is not sent in the navigation request or stored in server access logs. The URL cannot be recovered later." } } } ] } ``` ### UsageShareLinkExchange ```json { "type": "object", "required": [ "token" ], "properties": { "token": { "type": "string", "writeOnly": true, "description": "Opaque value read from the report URL fragment. Never put it in a query string or server log." } }, "additionalProperties": false } ``` ### WebhookEventType ```json { "type": "string", "enum": [ "application.queued", "application.running", "application.awaiting_answers", "application.succeeded", "application.failed", "application.cancelled" ] } ``` ### WebhookCreate ```json { "type": "object", "required": [ "url" ], "properties": { "url": { "type": "string", "format": "uri", "pattern": "^https://", "example": "https://agent.example.com/webhooks/applyguy" }, "events": { "type": "array", "minItems": 1, "items": { "$ref": "#/components/schemas/WebhookEventType" }, "example": [ "application.awaiting_answers", "application.succeeded", "application.failed" ] } } } ``` ### Webhook ```json { "type": "object", "required": [ "id", "url", "events", "active" ], "properties": { "id": { "type": "string", "format": "uuid" }, "url": { "type": "string", "format": "uri" }, "events": { "type": "array", "items": { "$ref": "#/components/schemas/WebhookEventType" } }, "active": { "type": "boolean" }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" } } } ``` ### WebhookCreated ```json { "allOf": [ { "$ref": "#/components/schemas/Webhook" }, { "type": "object", "required": [ "secret" ], "properties": { "secret": { "type": "string", "readOnly": true, "example": "whsec_••••••••••••••••" } } } ], "description": "Webhook metadata plus the one-time signing secret returned only on creation." } ``` ### WebhookCreatedResponse ```json { "type": "object", "required": [ "data", "warning" ], "properties": { "data": { "$ref": "#/components/schemas/WebhookCreated" }, "warning": { "type": "string", "example": "Store the signing secret now. It cannot be retrieved again." } } } ``` ### WebhookEvent ```json { "type": "object", "required": [ "id", "type", "createdAt", "data" ], "properties": { "id": { "type": "string", "format": "uuid", "description": "Stable event ID. Use it to deduplicate at-least-once deliveries." }, "type": { "$ref": "#/components/schemas/WebhookEventType" }, "createdAt": { "type": "string", "format": "date-time" }, "data": { "type": "object", "required": [ "applicationId", "status" ], "properties": { "applicationId": { "type": "string", "format": "uuid" }, "status": { "$ref": "#/components/schemas/ApplicationStatus" } } } } } ```