{"swagger":"2.0","info":{"title":"ApiSkills API","description":"A hands-on training API for learning API integration. Register an app in the portal to get an App ID, App Secret, API key, and bearer token, then practise every authentication style, data shape, and pagination pattern.\n\n**Authentication styles you can practise here:** Basic, Bearer token, API key (header & query), OAuth2 (client credentials, authorization code, PKCE, refresh), OAuth 1.0a, JWT (HS256 & RS256), HMAC signatures, and Digest.\n\n**Datasets (pack → entities):**\n- **fpa** (FP&A, scope `fpa:read`): departments, cost_centers, actuals\n- **stocks** (Stock Market, scope `stocks:read`): tickers, candles, holdings\n- **marketing** (Digital Marketing, scope `marketing:read`): channels, campaigns, daily\n- **hr** (HR Analytics, scope `hr:read`): departments, employees, headcount\n- **cricket** (Cricket (T20 league), scope `cricket:read`): teams, players, matches, innings\n\nEach dataset is available in four shapes (flat, list-of-lists, nested, nested-list) and every pagination style (page-number, offset, cursor, Link header).\n\n⚠️ This is a training sandbox — never send production credentials here.","version":"1.0.0","contact":{"name":"IFS Jaipur","url":"https://ifsjaipur.com"}},"host":"api.ifsjaipur.cloud","basePath":"/","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[{"name":"System"},{"name":"Data"},{"name":"Auth playground"},{"name":"OAuth2"},{"name":"OAuth 1.0a"},{"name":"HTTP methods"},{"name":"Resilience"},{"name":"CORS"},{"name":"App management"}],"securityDefinitions":{"apiKeyHeader":{"type":"apiKey","in":"header","name":"x-api-key","description":"Your app's API key."},"apiKeyQuery":{"type":"apiKey","in":"query","name":"api_key","description":"API key in the query string (weaker)."},"basicAuth":{"type":"basic","description":"Username = App ID, password = App Secret."},"bearerAuth":{"type":"apiKey","in":"header","name":"Authorization","description":"Value: \"Bearer <token>\" (app bearer token, OAuth2 access token, or JWT)."},"oauth2":{"type":"oauth2","flow":"application","tokenUrl":"https://api.ifsjaipur.cloud/oauth/token","scopes":{"fpa:read":"Read FP&A data","stocks:read":"Read Stock Market data","marketing:read":"Read Digital Marketing data","hr:read":"Read HR Analytics data","cricket:read":"Read Cricket (T20 league) data"}},"sessionAuth":{"type":"apiKey","in":"header","name":"Authorization","description":"Portal session token: \"Bearer <session JWT>\". The portal sends this for you."}},"paths":{"/":{"get":{"tags":["System"],"operationId":"ApiIndex","summary":"API index","description":"Name, version, and links.","security":[],"responses":{"200":{"description":"OK","schema":{"type":"object"}}}}},"/health":{"get":{"tags":["System"],"operationId":"Health","summary":"Liveness check","description":"Returns { status: \"ok\" }.","security":[],"responses":{"200":{"description":"OK","schema":{"type":"object"}}}}},"/health/ready":{"get":{"tags":["System"],"operationId":"HealthReady","summary":"Readiness check","description":"Checks database and Redis.","security":[],"responses":{"200":{"description":"Ready","schema":{"type":"object"}},"503":{"description":"A dependency is unavailable","schema":{"type":"object"}}}}},"/playground":{"get":{"tags":["System"],"operationId":"PlaygroundIndex","summary":"Playground index","description":"A map of every playground endpoint.","security":[],"responses":{"200":{"description":"OK","schema":{"type":"object"}}}}},"/playground/data":{"get":{"tags":["Data"],"operationId":"ListDatasets","summary":"List datasets","description":"Catalog of packs, entities, shapes, and pagination styles.","security":[],"responses":{"200":{"description":"OK","schema":{"type":"object"}}}}},"/playground/data/{pack}":{"get":{"tags":["Data"],"operationId":"GetPack","summary":"Describe one pack","description":"Fields, a sample row, and counts for each entity.","security":[],"parameters":[{"name":"pack","in":"path","required":true,"type":"string","x-ms-summary":"pack","description":"e.g. fpa, stocks, marketing, hr, cricket"}],"responses":{"200":{"description":"Pack detail","schema":{"type":"object"}},"404":{"description":"Unknown pack","schema":{"type":"object"}}}}},"/playground/data/{pack}/{entity}":{"get":{"tags":["Data"],"operationId":"GetData","summary":"Get dataset rows","description":"Return rows for a pack/entity. Auto-paginates via the top-level nextLink. Authenticate with the API key (header/query), Bearer, or OAuth2; the app must hold the pack scope.","security":[{"apiKeyHeader":[]},{"apiKeyQuery":[]},{"bearerAuth":[]},{"oauth2":[]}],"x-ms-pageable":{"nextLinkName":"nextLink"},"parameters":[{"name":"pack","in":"path","required":true,"type":"string","x-ms-summary":"pack","description":"e.g. fpa, stocks, marketing, hr, cricket"},{"name":"entity","in":"path","required":true,"type":"string","x-ms-summary":"entity","description":"e.g. candles, actuals, campaigns, employees, players"},{"name":"shape","in":"query","required":false,"type":"string","x-ms-summary":"shape","description":"Structural shape.","enum":["flat","list-of-lists","nested","nested-list"],"default":"flat"},{"name":"page","in":"query","required":false,"type":"integer","x-ms-summary":"page","description":"Page-number pagination."},{"name":"page_size","in":"query","required":false,"type":"integer","x-ms-summary":"page_size","description":"Rows per page (capped).","default":50},{"name":"offset","in":"query","required":false,"type":"integer","x-ms-summary":"offset","description":"Offset pagination."},{"name":"limit","in":"query","required":false,"type":"integer","x-ms-summary":"limit","description":"Row limit for offset pagination."},{"name":"cursor","in":"query","required":false,"type":"string","x-ms-summary":"cursor","description":"Opaque cursor — follow the relative next."},{"name":"pageToken","in":"query","required":false,"type":"string","x-ms-summary":"pageToken","description":"YouTube/Google-style opaque page token — resend nextPageToken."},{"name":"paginate","in":"query","required":false,"type":"string","x-ms-summary":"paginate","description":"Cursor, token (YouTube-style), or Link-header pagination.","enum":["cursor","token","link"]}],"responses":{"200":{"description":"A page of data","schema":{"type":"object","properties":{"pack":{"type":"string"},"entity":{"type":"string"},"shape":{"type":"string"},"nextLink":{"type":"string"},"pagination":{"type":"object"},"data":{"type":"array","items":{"type":"object"}}}}},"401":{"description":"Missing or invalid credentials","schema":{"type":"object"}},"403":{"description":"App lacks the required scope","schema":{"type":"object"}},"404":{"description":"Unknown pack or entity","schema":{"type":"object"}}}}},"/playground/auth/basic":{"get":{"tags":["Auth playground"],"operationId":"AuthBasic","summary":"Basic auth","description":"Authorization: Basic base64(App ID:App Secret).","security":[{"basicAuth":[]}],"responses":{"200":{"description":"Authenticated","schema":{"type":"object"}},"401":{"description":"Missing or invalid credentials","schema":{"type":"object"}}}}},"/playground/auth/bearer":{"get":{"tags":["Auth playground"],"operationId":"AuthBearer","summary":"Bearer token","description":"Authorization: Bearer <app bearer token (bt_...)>.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Authenticated","schema":{"type":"object"}},"401":{"description":"Missing or invalid credentials","schema":{"type":"object"}}}}},"/playground/auth/api-key":{"get":{"tags":["Auth playground"],"operationId":"AuthApiKeyHeader","summary":"API key (header)","description":"Send x-api-key: <key>.","security":[{"apiKeyHeader":[]}],"responses":{"200":{"description":"Authenticated","schema":{"type":"object"}},"401":{"description":"Missing or invalid credentials","schema":{"type":"object"}}}}},"/playground/auth/api-key-query":{"get":{"tags":["Auth playground"],"operationId":"AuthApiKeyQuery","summary":"API key (query)","description":"Send ?api_key=<key> (weaker).","security":[{"apiKeyQuery":[]}],"responses":{"200":{"description":"Authenticated","schema":{"type":"object"}},"401":{"description":"Missing or invalid credentials","schema":{"type":"object"}}}}},"/playground/auth/oauth2":{"get":{"tags":["Auth playground"],"operationId":"AuthOAuth2","summary":"OAuth2 access token","description":"Authorization: Bearer <access_token from /oauth/token>.","security":[{"bearerAuth":[]},{"oauth2":[]}],"responses":{"200":{"description":"Authenticated","schema":{"type":"object"}},"401":{"description":"Missing or invalid credentials","schema":{"type":"object"}}}}},"/playground/auth/oauth1":{"get":{"tags":["Auth playground"],"operationId":"AuthOAuth1","summary":"OAuth 1.0a signed request","description":"Requires a valid OAuth 1.0a signature (complete the 3-legged flow first).","security":[],"responses":{"200":{"description":"Authenticated","schema":{"type":"object"}},"401":{"description":"Missing or invalid credentials","schema":{"type":"object"}}}}},"/playground/auth/hmac":{"post":{"tags":["Auth playground"],"operationId":"AuthHmac","summary":"HMAC signature","description":"Send x-app-id, x-timestamp, and x-signature = HMAC_SHA256(API key, `${timestamp}.${method}.${path}`), hex. Also accepts GET.","security":[],"parameters":[{"name":"x-app-id","in":"header","required":true,"type":"string","description":"Your App ID."},{"name":"x-timestamp","in":"header","required":true,"type":"string","description":"Unix time (±5 min window)."},{"name":"x-signature","in":"header","required":true,"type":"string","description":"Hex HMAC-SHA256."}],"responses":{"200":{"description":"Authenticated","schema":{"type":"object"}},"401":{"description":"Missing or invalid credentials","schema":{"type":"object"}}}}},"/playground/auth/digest":{"get":{"tags":["Auth playground"],"operationId":"AuthDigest","summary":"Digest (RFC 7616)","description":"Call once with no auth for a nonce challenge, then resend a Digest response (username = App ID, password = API key).","security":[],"responses":{"200":{"description":"Authenticated","schema":{"type":"object"}},"401":{"description":"Missing or invalid credentials","schema":{"type":"object"}}}}},"/playground/auth/jwt":{"get":{"tags":["Auth playground"],"operationId":"AuthJwtVerify","summary":"Verify a JWT","description":"Authorization: Bearer <jwt>. Checks signature, exp, aud.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Authenticated","schema":{"type":"object"}},"401":{"description":"Missing or invalid credentials","schema":{"type":"object"}}}}},"/playground/auth/jwt/issue":{"post":{"tags":["Auth playground"],"operationId":"AuthJwtIssue","summary":"Issue JWTs","description":"Basic App ID:App Secret → HS256 + RS256 tokens.","security":[{"basicAuth":[]}],"responses":{"200":{"description":"OK","schema":{"type":"object"}}}}},"/playground/auth/jwt/decode":{"post":{"tags":["Auth playground"],"operationId":"AuthJwtDecode","summary":"Decode a JWT (no verify)","description":"Shows header + payload without verifying.","security":[],"parameters":[{"name":"body","in":"body","required":true,"schema":{"type":"object","required":["token"],"properties":{"token":{"type":"string"}}}}],"responses":{"200":{"description":"OK","schema":{"type":"object"}}}}},"/playground/auth/jwt/public-key":{"get":{"tags":["Auth playground"],"operationId":"AuthJwtPublicKey","summary":"RS256 public key","description":"PEM public key for verifying RS256 tokens.","security":[],"responses":{"200":{"description":"OK","schema":{"type":"object"}}}}},"/oauth/authorize":{"get":{"tags":["OAuth2"],"operationId":"OAuthAuthorize","summary":"Authorization endpoint","description":"Authorization Code flow (auto-approved), supports PKCE; redirects back with ?code=...","security":[],"parameters":[{"name":"response_type","in":"query","required":true,"type":"string","x-ms-summary":"response_type","description":"Must be \"code\".","enum":["code"]},{"name":"client_id","in":"query","required":true,"type":"string","x-ms-summary":"client_id","description":"Your App ID."},{"name":"redirect_uri","in":"query","required":true,"type":"string","x-ms-summary":"redirect_uri","description":"A registered redirect URI."},{"name":"scope","in":"query","required":false,"type":"string","x-ms-summary":"scope","description":"Space-separated scopes."},{"name":"state","in":"query","required":false,"type":"string","x-ms-summary":"state","description":"Opaque value echoed back."},{"name":"code_challenge","in":"query","required":false,"type":"string","x-ms-summary":"code_challenge","description":"PKCE challenge."},{"name":"code_challenge_method","in":"query","required":false,"type":"string","x-ms-summary":"code_challenge_method","description":"PKCE method.","enum":["S256"]}],"responses":{"302":{"description":"Redirect to redirect_uri with code or error"}}}},"/oauth/token":{"post":{"tags":["OAuth2"],"operationId":"OAuthToken","summary":"Token endpoint","description":"grant_type = client_credentials | authorization_code | refresh_token. Client auth via Basic or body.","consumes":["application/x-www-form-urlencoded"],"security":[],"parameters":[{"name":"grant_type","in":"formData","required":true,"type":"string","description":"client_credentials | authorization_code | refresh_token.","default":"client_credentials"},{"name":"client_id","in":"formData","required":false,"type":"string","description":"Your App ID."},{"name":"client_secret","in":"formData","required":false,"type":"string","description":"Your App Secret."},{"name":"scope","in":"formData","required":false,"type":"string","description":"Space-separated scopes."},{"name":"code","in":"formData","required":false,"type":"string","description":"For authorization_code."},{"name":"redirect_uri","in":"formData","required":false,"type":"string","description":"For authorization_code."},{"name":"code_verifier","in":"formData","required":false,"type":"string","description":"For PKCE."},{"name":"refresh_token","in":"formData","required":false,"type":"string","description":"For refresh_token."}],"responses":{"200":{"description":"Access token","schema":{"type":"object"}},"400":{"description":"invalid_grant / unsupported_grant_type / invalid_scope","schema":{"type":"object"}},"401":{"description":"invalid_client","schema":{"type":"object"}}}}},"/oauth/introspect":{"post":{"tags":["OAuth2"],"operationId":"OAuthIntrospect","summary":"Token introspection","description":"Returns { active, sub, client_id, scope, exp }.","consumes":["application/x-www-form-urlencoded"],"security":[],"parameters":[{"name":"token","in":"formData","required":true,"type":"string","description":"The token to introspect."}],"responses":{"200":{"description":"OK","schema":{"type":"object"}}}}},"/oauth1/request_token":{"post":{"tags":["OAuth 1.0a"],"operationId":"OAuth1RequestToken","summary":"Request token (leg 1)","description":"Signed request → temporary credentials. consumer_key = App ID, consumer_secret = API key.","security":[],"responses":{"200":{"description":"OK","schema":{"type":"object"}}}}},"/oauth1/authorize":{"get":{"tags":["OAuth 1.0a"],"operationId":"OAuth1Authorize","summary":"Authorize (leg 2)","description":"Auto-approves and returns an oauth_verifier.","security":[],"parameters":[{"name":"oauth_token","in":"query","required":true,"type":"string","x-ms-summary":"oauth_token","description":"The temporary token from leg 1."}],"responses":{"200":{"description":"OK","schema":{"type":"object"}}}}},"/oauth1/access_token":{"post":{"tags":["OAuth 1.0a"],"operationId":"OAuth1AccessToken","summary":"Access token (leg 3)","description":"Exchange the authorized request token + verifier (signed) for an access token.","security":[],"responses":{"200":{"description":"OK","schema":{"type":"object"}}}}},"/playground/echo":{"get":{"tags":["HTTP methods"],"operationId":"EchoGet","summary":"Echo (GET)","description":"Reflects method, query, content-type, body. Also accepts POST/PUT/PATCH/DELETE.","security":[],"responses":{"200":{"description":"OK","schema":{"type":"object"}}}},"post":{"tags":["HTTP methods"],"operationId":"EchoPost","summary":"Echo (POST)","description":"Reflects the parsed request body.","security":[],"parameters":[{"name":"body","in":"body","required":true,"schema":{"type":"object","required":[],"properties":{}}}],"responses":{"200":{"description":"OK","schema":{"type":"object"}}}}},"/playground/upload":{"post":{"tags":["HTTP methods"],"operationId":"Upload","summary":"File upload (multipart)","description":"multipart/form-data — reports each file and field.","consumes":["multipart/form-data"],"security":[],"parameters":[{"name":"file","in":"formData","required":false,"type":"file","description":"A file to upload."}],"responses":{"200":{"description":"Upload summary","schema":{"type":"object"}},"400":{"description":"Not multipart","schema":{"type":"object"}}}}},"/playground/response":{"get":{"tags":["Resilience"],"operationId":"ResponseGet","summary":"Configurable response (GET)","description":"Return any status after any delay (capped). Also POST/PUT/PATCH/DELETE.","security":[],"parameters":[{"name":"status","in":"query","required":false,"type":"integer","x-ms-summary":"status","description":"Status code (100–599).","default":200},{"name":"delay","in":"query","required":false,"type":"integer","x-ms-summary":"delay","description":"Delay in ms (capped).","default":0},{"name":"body","in":"query","required":false,"type":"string","x-ms-summary":"body","description":"Optional body to echo."}],"responses":{"200":{"description":"OK","schema":{"type":"object"}}}},"post":{"tags":["Resilience"],"operationId":"ResponsePost","summary":"Configurable response (POST)","description":"Same as GET with a body.","security":[],"parameters":[{"name":"status","in":"query","required":false,"type":"integer","x-ms-summary":"status","description":"Status code.","default":200},{"name":"delay","in":"query","required":false,"type":"integer","x-ms-summary":"delay","description":"Delay in ms.","default":0},{"name":"body","in":"query","required":false,"type":"string","x-ms-summary":"body","description":"Optional body to echo."}],"responses":{"200":{"description":"OK","schema":{"type":"object"}}}}},"/playground/timeout":{"get":{"tags":["Resilience"],"operationId":"Timeout","summary":"Artificial delay","description":"Sleeps for ?delay=ms (capped) to practise client timeouts.","security":[],"parameters":[{"name":"delay","in":"query","required":false,"type":"integer","x-ms-summary":"delay","description":"Delay in ms (capped).","default":1000}],"responses":{"200":{"description":"OK","schema":{"type":"object"}}}}},"/playground/redirect":{"get":{"tags":["Resilience"],"operationId":"Redirect","summary":"Redirect chain","description":"A chain of ?n= redirects ending in 200.","security":[],"parameters":[{"name":"n","in":"query","required":false,"type":"integer","x-ms-summary":"n","description":"Hops (max 10).","default":1},{"name":"status","in":"query","required":false,"type":"integer","x-ms-summary":"status","description":"Redirect status.","enum":[301,302,307,308],"default":302}],"responses":{"200":{"description":"Arrived","schema":{"type":"object"}},"302":{"description":"A redirect hop"}}}},"/playground/batch":{"post":{"tags":["Resilience"],"operationId":"Batch","summary":"Batch sub-requests","description":"Send { requests: [ { method, path, body? } ] }; get an array back (capped).","security":[],"parameters":[{"name":"body","in":"body","required":true,"schema":{"type":"object","required":["requests"],"properties":{"requests":{"type":"array","items":{"type":"object"}}}}}],"responses":{"200":{"description":"OK","schema":{"type":"object"}}}}},"/playground/headers":{"get":{"tags":["Resilience"],"operationId":"Headers","summary":"Echo request headers","description":"Returns your headers exactly as received.","security":[],"responses":{"200":{"description":"OK","schema":{"type":"object"}}}}},"/playground/cors/info":{"get":{"tags":["CORS"],"operationId":"CorsInfo","summary":"CORS info","description":"Explains the request origin.","security":[],"responses":{"200":{"description":"OK","schema":{"type":"object"}}}}},"/playground/cors/simple":{"get":{"tags":["CORS"],"operationId":"CorsSimple","summary":"Simple CORS GET","description":"Allowed without a preflight.","security":[],"responses":{"200":{"description":"OK","schema":{"type":"object"}}}}},"/playground/cors/preflight":{"post":{"tags":["CORS"],"operationId":"CorsPreflight","summary":"Preflighted CORS POST","description":"A JSON POST that triggers a preflight OPTIONS.","security":[],"parameters":[{"name":"body","in":"body","required":true,"schema":{"type":"object","required":[],"properties":{}}}],"responses":{"200":{"description":"OK","schema":{"type":"object"}}}}},"/api/apps":{"get":{"tags":["App management"],"operationId":"ListMyApps","summary":"List my apps","description":"Every app owned by the signed-in user.","security":[{"sessionAuth":[]}],"responses":{"200":{"description":"OK","schema":{"type":"object"}}}},"post":{"tags":["App management"],"operationId":"CreateApp","summary":"Create an app","description":"Register a new app; secrets returned ONCE.","security":[{"sessionAuth":[]}],"parameters":[{"name":"body","in":"body","required":true,"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"description":{"type":"string"}}}}],"responses":{"201":{"description":"Created (secrets shown once)","schema":{"type":"object"}}}}},"/api/apps/{id}":{"get":{"tags":["App management"],"operationId":"GetApp","summary":"Get one app","description":"App details, credentials metadata, and scopes.","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"type":"string","x-ms-summary":"id","description":"The app id."}],"responses":{"200":{"description":"App detail","schema":{"type":"object"}},"404":{"description":"Not found","schema":{"type":"object"}}}},"delete":{"tags":["App management"],"operationId":"DeleteApp","summary":"Delete an app","description":"Permanently delete the app and its credentials/logs. ?mode=revoke soft-disables instead.","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"type":"string","x-ms-summary":"id","description":"The app id."},{"name":"mode","in":"query","required":false,"type":"string","x-ms-summary":"mode","description":"Omit to delete; \"revoke\" to soft-disable.","enum":["revoke"]}],"responses":{"200":{"description":"Deleted or revoked","schema":{"type":"object"}},"404":{"description":"Not found","schema":{"type":"object"}}}}},"/api/apps/{id}/secret":{"post":{"tags":["App management"],"operationId":"RegenerateSecret","summary":"Regenerate the App Secret","description":"Invalidate the old secret; return a new one (once).","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"type":"string","x-ms-summary":"id","description":"The app id."}],"responses":{"200":{"description":"OK","schema":{"type":"object"}}}}},"/api/apps/{id}/rotate":{"post":{"tags":["App management"],"operationId":"RotateCredentials","summary":"Rotate credentials","description":"Rotate secret / API key / bearer without deleting the app. Body { secret?, apiKey?, bearer? }; omit all to rotate everything.","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"type":"string","x-ms-summary":"id","description":"The app id."},{"name":"body","in":"body","required":true,"schema":{"type":"object","required":[],"properties":{"secret":{"type":"boolean"},"apiKey":{"type":"boolean"},"bearer":{"type":"boolean"}}}}],"responses":{"200":{"description":"OK","schema":{"type":"object"}}}}},"/api/apps/{id}/redirect-uris":{"put":{"tags":["App management"],"operationId":"SetRedirectUris","summary":"Set OAuth2 redirect URIs","description":"Replace allowed redirect URIs (max 10).","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"type":"string","x-ms-summary":"id","description":"The app id."},{"name":"body","in":"body","required":true,"schema":{"type":"object","required":["redirectUris"],"properties":{"redirectUris":{"type":"array","items":{"type":"string"}}}}}],"responses":{"200":{"description":"OK","schema":{"type":"object"}}}}},"/api/me/reset":{"post":{"tags":["App management"],"operationId":"ResetSandbox","summary":"Reset my sandbox","description":"Delete ALL of my apps. Scoped to the signed-in user.","security":[{"sessionAuth":[]}],"responses":{"200":{"description":"OK","schema":{"type":"object"}}}}}}}